我正在使用Android AudioTrack对象来流式传输16位单声道PCM文件。我的代码从 DataInputStream 中读取双精度值,将其转换为 8 个字节,然后将这 8 个字节保存到缓冲区以写入 AudioTrack。这工作正常。但是现在,我试图通过将双精度乘以标量(如 0.5)来调整增益。当我这样做时,它会让我的音频严重失真。我尝试使用浮点数而不是双精度,我得到了相同的结果。有没有更好的方法来改变流的增益?我的最终目标是创建一个简单的回声效果,这就是我这样做的原因。
ByteBuffer bb = ByteBuffer.allocate(8);
while(isPlaying){
try {
//fill buffer with bytes from file reader
for(int i=0; i < BUFFSIZE/8; i++){
//read double from DataInputStream
double temp = dis.readDouble();
//save double to ByteBuffer
bb.putDouble(0, temp * .5);
// save 8 bytes to array of bytes
bb.rewind();
bb.get(buff,i*8,8);
}
//write buffer to track to play
track.write(buff, 0, BUFFSIZE);
} catch (IOException e) {
break; //when eof is reached
}
}
如果您使用 Android AudioRecord 和 AudioTrack 类进行录制和播放,请记住,默认情况下,16 位单声道音频样本是小端序。如果您使用 DataInputStream 类的 readDouble() 方法读取字节,它会不分青红皂白地读取大端序中的 64 位,因此字节的读取顺序错误。但请记住,即使 readDouble 会读取小端序中的字节,或者如果您的音频是大端序,它也会读取 64 位并将它们视为一个大的双精度值,而实际上每个样本都表示一个有符号的短值,其值范围从 -32768 到 +32767(假设它是有符号的)。如果您出于数字信号处理的目的将其转换为双精度值,则最好通过除以 32767.0f 将其规范化为 -1.0 到 +1.0 范围(否则,首先不要费心将其转换为双精度)。当您在双精度上完成 DSP 时,将其乘以 32767 并将其转换回小端序。这里有一个快速而肮脏的方法:
try{
for(int offset=0; offset < buff_size; offset+= 2) //increment index by two because 16bit mono sample is 2 bytes long
{
//reads 2 bytes from stream and stores them in buff at offset. returns number of bytes read.
if (dis.read(buff,offset, 2) > 0){
//where buff is an array of bytes
// Low Byte High Byte Left Shift
double sample= ((buff[offset + 0]) | (buff[offset + 1] << 8) );
/*Explanation: First We take the High Byte and shift it 8 Bytes to the left. In Java, this promotes it to an integer(32 bits).
* Next we merge the int representing High Byte and the Low Byte byte with a bitwise OR operator
* 00000000 0000000 10101111 00000000
* OR 10110000 =
* 00000000 0000000 10101111 10110000 Now our bytes are in the Big Endian order required for primitive types */
//since 2 bytes is a short which has range -32768 to +32767, we divide by 32768 to normalize to -1.0 to +1.0 range for DSP
sample = sample /32768.0;
sample = sample * .5;
//convert it back to small endian
int nsample = (int) Math.round(sample * 32767.0);//expands it to the range of -32768 to 32767 range of short, round, & truncate
buff[offset + 1] = (byte) ((nsample >> 8) & 0xFF); //isolate and extract the high byte
buff[offset + 0] = (byte) (nsample & 0xFF); //isolate the low byte with MASK
}
}
track.write(buff, 0, buff_size);
}catch(Exception e){
//
}
来源:http://www.jsresources.org/faq_audio.html#samples_organized