Question

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
        }
    }
Was it helpful?

Solution

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){
        //
    }

sources: http://www.jsresources.org/faq_audio.html#samples_organized

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top