1

I've trying to create a single synchronous audio output file from two or more than two audio files of same length. I have done some research and came to know that this can be achieved through below steps:

  1. Only uncompressed audio files can be used for this purpose. i.e. Convert mp3 audio files into WAV format.
  2. Mix 2 new wav files; i have followed this approach: Mix audio in android

But the same problem arises, the mixed audio file doesn't play.

I've been trying to add a valid header to the output file as per this answer Writing PCM recorded data into a .wav file (java android).

Here is my Mixer class:

public class SongMixer2
{

private Context mContext;

public SongMixer2(Context context)
{
    mContext = context;
}

public void onCreate()
{
    try
    {
        mixSound();
    } catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

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 = mContext.getResources().openRawResource(R.raw.brokaw);
    InputStream in2 = mContext.getResources().openRawResource(R.raw.brokaw);

    byte[] arrayMusic1 = null;
    arrayMusic1 = new byte[in1.available()];
    arrayMusic1 = createMusicArray(in1);
    in1.close();

    byte[] arrayMusic2 = null;
    arrayMusic2 = new byte[in2.available()];
    arrayMusic2 = createMusicArray(in2);
    in2.close();

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

    audioTrack.play();

    for (int i = 0; i < output.length - 1; i++)
    {
        float samplef1 = arrayMusic1[i] / 128.0f;
        float samplef2 = arrayMusic2[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, output.length);
    convertByteToFile(output);
}

public static byte[] createMusicArray(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

}

public static void convertByteToFile(byte[] fileBytes)
        throws FileNotFoundException
{

    String path = Environment.getExternalStorageDirectory().getPath() + "/mixed.wav";
    File f=new File(path);
    BufferedOutputStream bos = new BufferedOutputStream(
            new FileOutputStream(f));
    try
    {
        bos.write(writeHeader(fileBytes.length), 0, 44);
        bos.write(fileBytes);
        bos.flush();
        bos.close();
    } catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static byte[] writeHeader(int totalDataLen)
{
    byte[] header = new byte[44];

    header[0] = 'R';  // RIFF/WAVE header
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    header[4] = (byte) (totalDataLen & 0xff);
    header[5] = (byte) ((totalDataLen >> 8) & 0xff);
    header[6] = (byte) ((totalDataLen >> 16) & 0xff);
    header[7] = (byte) ((totalDataLen >> 24) & 0xff);
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    header[12] = 'f';  // 'fmt ' chunk
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
    header[17] = 0;
   /* header[18] = 0;
    header[19] = 0;
    header[20] = 1;  // format = 1
    header[21] = 0;
    header[22] = (byte) channels;
    header[23] = 0;
    header[24] = (byte) (longSampleRate & 0xff);
    header[25] = (byte) ((longSampleRate >> 8) & 0xff);
    header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (2 * 16 / 8);  // block align
    header[33] = 0;
    header[34] = RECORDER_BPP;  // bits per sample
    header[35] = 0;*/
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
   /* header[40] = (byte) (totalAudioLen & 0xff);
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
*/

 return header;
}

}

And the Activity:

public class SoundMixerActivity extends Activity 
{
protected void onCreate(Bundle savedInstanceState) 
    {
    super.onCreate(savedInstanceState);
    new SongMixer2(this).onCreate();
}
}

A File 'mixed.wav' is created there in SD card, but it won't play...anyone please help!!

Community
  • 1
  • 1
Vinay
  • 1,859
  • 22
  • 26

1 Answers1

2

In your header you say the file has an audio alignment of 4 bytes. This would be for 16-bit stereo audio.

In your createMix, however, you assume that the audio is 8bit (a byte) rather than 16-bit. You need to perform your mixing with shorts.

Its also usual to take the average of the samples from each file. ie (sample1 + sample2) / 2.

Goz
  • 61,365
  • 24
  • 124
  • 204
  • Thanks Goz, for your quick reply. i updated header to header[16] = 32; but no luck, the file is created but can't play :( Could you tell me if there is a different approach to achieve the objective? – Vinay Feb 25 '14 at 13:13
  • 1
    @Vinay: Slow response, sorry. Why did you update your header to 32 bytes? 36 - 16 = 20, not 32. Also, its the mixing of the samples together in the data chunk thats really wrong (assuming you DO want 16-bit audio). – Goz Mar 06 '14 at 08:23
  • The correct solution would be to correctly parse your wave header. Feel free to start another question with the code you have written so far and link to it in the comments here. I'll try and help you if I can ... – Goz Jun 23 '15 at 11:53