如何使用标量手动更改 Android 音轨流的增益级别



我正在使用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

相关内容

  • 没有找到相关文章

最新更新