Sample code for Android AudioTrack Mixing

jason white picture jason white · Feb 27, 2013 · Viewed 14.1k times · Source

I have two PCM sound file in resource folder. I used inputstream and converted them into bytearray.

Then I processed them by normalized and adding music1 and music2 and output to the byte array output. Finally, put the output array and feed it to the AudioTrack.

Obviously, I don't hear anything and something is wrong.

 private void mixSound() throws IOException {

    InputStream in1=getResources().openRawResource(R.raw.cheerapp2);      
    InputStream in2=getResources().openRawResource(R.raw.buzzer2);

     byte[] music1 = null;
     music1= new byte[in1.available()]; 
     music1=convertStreamToByteArray(in1);
     in1.close();


     byte[] music2 = null;
     music2= new byte[in2.available()]; 
     music2=convertStreamToByteArray(in2);
     in2.close();

     byte[] output = new byte[music1.length];

     audioTrack.play();

     for(int i=0; i < output.length; i++){

         float samplef1 = music1[i] / 128.0f;      //     2^7=128
         float samplef2 = music2[i] / 128.0f;


         float mixed = samplef1 + samplef2;
         // reduce the volume a bit:
         mixed *= 0.8;
         // hard clipping
         if (mixed > 1.0f) mixed = 1.0f;
         if (mixed < -1.0f) mixed = -1.0f;
        byte outputSample = (byte)(mixed * 128.0f);
         output[i] = outputSample;
         audioTrack.write(output, 0, i);
      }   //for loop


      public static byte[] convertStreamToByteArray(InputStream is) throws IOException {



    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buff = new byte[10240];
    int i = Integer.MAX_VALUE;
    while ((i = is.read(buff, 0, buff.length)) > 0) {
        baos.write(buff, 0, i);
    }

    return baos.toByteArray(); // be sure to close InputStream in calling function

}

Answer

combinatorics picture combinatorics · Feb 27, 2013

I tried your code (substituting in some audio files of my own). I initialised an AudioTrack instance like this, hopefully this is similar to how you did it:

AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, 44100, AudioTrack.MODE_STREAM);

And tried running it. It made a high pitched noise, that got lower as time went on. I checked the code and the problem is that you are writing the entire output byte array to the audioTrack on every iteration of the loop in your mixSound() method.

the line

 audioTrack.write(output, 0, i);

needs moved outside the loop and to be changed to

 audioTrack.write(output, 0, output.length);

So you mix both files together into the output byte array, then write the whole thing at once.

So the code for the working mixSound method looks like this:

private void mixSound() throws IOException {
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, 44100, AudioTrack.MODE_STREAM);

    InputStream in1=getResources().openRawResource(R.raw.track1);      
    InputStream in2=getResources().openRawResource(R.raw.track2);

    byte[] music1 = null;
    music1= new byte[in1.available()]; 
    music1=convertStreamToByteArray(in1);
    in1.close();


    byte[] music2 = null;
    music2= new byte[in2.available()]; 
    music2=convertStreamToByteArray(in2);
    in2.close();

    byte[] output = new byte[music1.length];

    audioTrack.play();

    for(int i=0; i < output.length; i++){

        float samplef1 = music1[i] / 128.0f;      //     2^7=128
        float samplef2 = music2[i] / 128.0f;


        float mixed = samplef1 + samplef2;
        // reduce the volume a bit:
        mixed *= 0.8;
        // hard clipping
        if (mixed > 1.0f) mixed = 1.0f;

        if (mixed < -1.0f) mixed = -1.0f;

        byte outputSample = (byte)(mixed * 128.0f);
        output[i] = outputSample;

    }   //for loop
    audioTrack.write(output, 0, output.length);

}