对于点对点音频客户端,我需要能够将输出音量更改为所需的水平。就我而言,体积是介于零和一之间的浮点数。
我以这种方式修改音频流:
void play(byte[] buf)
{
for (int i = 0; i < buf.length; i += 2)
{
// sample size is 2 bytes, so convert to int and then back
int data = ((buf[i + 1] & 0xFF) << 8) | (buf[i] & 0xFF);
data = (int) (data * outputVolume);
buf[i] = (byte) (data & 0xFF);
buf[i + 1] = (byte) (data >> 8);
}
line.write(buf, 0, Math.min(buf.length, line.available()));
}
现在,当outputVolume
设置为0时,输出为静默。设置为1时,它的行为正常且质量很好(因为未修改)。但是0到1之间的任何数字都会产生可怕的噪声,它比预期的流本身响亮。达到0.5时,噪音达到最高点。
我不想使用音频混音器本身的控件(例如增益控件或音量控件),因为这样会产生兼容性问题,以后,我想进一步修改字节流,因此我必须进行迭代通过流。
答案 0 :(得分:2)
假设音频数据已签名(因为我认为拥有未签名的16位样本是非常不寻常的),那么该代码中有一个错误,因为您还需要对样本进行签名扩展。
您可以从高字节中删除& 0xFF
,这将使符号扩展自动发生:
int data = (buf[i + 1] << 8) | (buf[i] & 0xFF);
如果由于某种原因您无法修改and-shift-or表达式,则可以这样进行符号扩展:
int data = ((buf[i + 1] & 0xFF) << 8) | (buf[i] & 0xFF);
data = (data << 16) >> 16;
移位表达式的结果与此等效:
if (data > 32767)
data -= 65536;
这:
if ((i & 0x80_00) != 0)
i |= 0xFF_FF_00_00;
(那些也可以。)
但是,根据您的情况,您只需从高字节中删除& 0xFF
。
为便于快速解释,如果您有一些这样的16位样本(即-1):
11111111_11111111
如果仅转换为32位而不扩展符号,则会得到:
00000000_00000000_11111111_11111111
但这是65536,不是-1。如果设置了16位值中的MSB,则符号扩展用1填充高位:
11111111_11111111_11111111_11111111