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

时间:2014-04-03 17:21:10

标签: android audio stream audiotrack

我使用Android AudioTrack对象来传输16位单声道PCM文件。我的代码从DataInputStream中读取一个double,将其转换为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
        }
    }

1 个答案:

答案 0 :(得分:2)

如果您使用Android AudioRecord和AudioTrack类进行录制和播放,请记住16位单声道音频样本默认为小端。如果您正在使用DataInputStream类的readDouble()方法读取字节,则它会在Big endian中不加区分地读取64位,因此正在以错误的顺序读取字节。但请记住,即使readDouble将读取小端的字节,或者如果您的音频是Big endian,它也会读取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