如何使用标量手动更改Android AudioTrack流的增益级别? [英] How can I manually change the gain level of an Android AudioTrack stream using a scalar?

查看:281
本文介绍了如何使用标量手动更改Android AudioTrack流的增益级别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Android AudioTrack对象流式传输16位单声道PCM文件.我的代码从DataInputStream读取一个double,将其转换为8个字节,然后将这8个字节保存到要写入AudioTrack的缓冲区中.这很好.但是现在,我正在尝试通过将两倍乘以标量(例如0.5)来调整增益.当我这样做时,它会使我的音频严重失真.我试过使用浮点数而不是双精度数,并且得到相同的结果.有没有更好的方法来改变流的增益?我的最终目标是创建一个简单的回声效果,这就是我这样做的原因.

I'm using the Android AudioTrack object to stream a 16bit mono PCM file. My code reads a double from a DataInputStream, converts it to 8 bytes, and then saves that 8 bytes to a buffer to be written to the AudioTrack. This works fine. But now, I'm trying to adjust the gain by multiplying the double by a scalar (like 0.5). When I do this, it makes my audio terribly distorted. I have tried using floats instead of doubles, and I get the same result. Is there a better way to go about changing the gain of the stream? My ultimate goal is to create a simple echo effect, which is why I'm doing it this way.

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()方法读取字节,则它会不加区别地读取Big endian中的64位,因此字节的读取顺序是错误的.但请记住,即使readDouble会读取小字节序的字节,或者您的音频为大字节序,它也会读取64位并将其视为一个大的double值,而实际上每个样本都代表一个带符号的short值,范围为从-32768到+32767(假设已签名).如果出于数字信号处理的目的将其转换为双精度,则最好通过除以32767.0f将其归一化为-1.0到+1.0范围(否则,请不要麻烦将其转换为双精度).第一名).完成对DSP的双重处理后,将其乘以32767,然后将其转换回小字节序.这是一种快速而肮脏的解决方法:

If you are using the Android AudioRecord and AudioTrack classes for recording and playback, keep in mind that a 16 bit mono audio sample is by default small endian. If you're reading the bytes with the DataInputStream class's readDouble() method, it's indiscriminately reading 64 bits in Big endian, so the bytes are being read in the wrong order. But keep in mind that even if readDouble would read the bytes in small endian, or if your audio was in Big endian, it's reading 64 bits and treating them as one big double value when in reality each sample represents a signed short with a values ranging from -32768 to +32767 (assuming that it is signed). If you're converting it to a double for the purpose of digital signal processing, it's good practice to normalize it to the -1.0 to +1.0 range by dividing by 32767.0f (otherwise, don't bother converting it to a double in the first place). When you're done doing your DSP on the double, multiply it by 32767 and convert it back to small endian. Here's a quick and dirty way to go about it:

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

这篇关于如何使用标量手动更改Android AudioTrack流的增益级别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆