18

I want to merge two mp3 files into one mp3 file.for example if 1st file is 1min and 2nd file is 30 sec then the output should be one min. In that one min it should play both the files.

Sagar Hatekar
  • 8,700
  • 14
  • 56
  • 72
sandeep
  • 481
  • 1
  • 6
  • 14
  • So you want to _mix_ the two audio files? – Michael Mar 27 '13 at 06:44
  • Yes,but i want to mix two mp3 files – sandeep Mar 27 '13 at 08:17
  • If you only want to play 2 files simultaneously then can you not load both in separate mediaPlayer? Create one instance to play first file and another for second and then take 2 new threads and start playing those files as `mediaPlayer.start()` at the same time. – Apurva Oct 21 '15 at 05:26

7 Answers7

2

First of all, in order to mix two audio files you need to manipulate their raw representation; since an MP3 file is compressed, you don't have a direct access to the signal's raw representation. You need to decode the compressed MP3 stream in order to "understand" the wave form of your audio signals and then you will be able to mix them.

Thus, in order to mix two compressed audio file into a single compressed audio file, the following steps are required:

  1. decode the compressed file using a decoder to obtain the raw data (NO PUBLIC SYSTEM API available for this, you need to do it manually!).
  2. mix the two raw uncompressed data streams (applying audio clipping if necessary). For this, you need to consider the raw data format obtained with your decoder (PCM)
  3. encode the raw mixed data into a compressed MP3 file (as per the decoder, you need to do it manually using an encoder)

More info aboud MP3 decoders can be found here.

bonnyz
  • 13,458
  • 5
  • 46
  • 70
  • it would be great if you could add some code to your answer. – Advait Saravade Oct 16 '15 at 10:19
  • 3
    @AdvaitS This is a lot of work involved, no easy answer for this tasks. You should try to implement it first, and then come back to ask clarifications – bonnyz Oct 16 '15 at 10:25
  • Is there any way to share some of my code with you? – Advait Saravade Oct 16 '15 at 11:13
  • 2
    @AdvaitS You should post your code together with an educated explanation of what you've done and what you need to do as a new question. I think this is the best way to find help. – bonnyz Oct 16 '15 at 11:18
  • I cannot possibly do that. The question would be a duplicate. Your solution, although providing guidance, is still incomplete. I would love to award the bounty for your answer if you provided some code. – Advait Saravade Oct 18 '15 at 13:08
  • @Advait S People took time out to post their solutions here. The least you could do is try them out and post your findings or at least post why the solutions don't work. I know its hard to part with your bounty but no one is going to do your homework for you here :) – Sagar Hatekar Dec 03 '16 at 17:17
0

I am not sure if you want to do it on an Android phone (looks like that because of your tags), but if I'm right maybe try LoopStack, it's a mobile DAW (did not try it myself).

If you are just "mixing" two files without adjusting the output volume your output might clip. However I am not sure if it's possible to "mix" two mp3 files without decoding them.

If it is okay for you to merge them on your PC try Audacity, it's a free desktop DAW.

c4bbage
  • 113
  • 3
0

I have not done it in Android but I had done it using Adobe flex. I guess the logic remains the same. I followed the following steps:

  • I extracted both the mp3s into two byte arrays. (song1ByteArray, song2ByteArray)
  • Find out the bigger byte array. (Let's say song1ByteArray is the larger one).
  • Create a function which returns the mixed byte array.

    private ByteArray mix2Songs(ByteArray song1ByteArray, ByteArray song2ByteArray){
    int arrLength=song1ByteArray.length; 
    for(int i=0;i<arrLength;i+=8){ // here if you see we are incrementing the length by 8 because a sterio sound has both left and right channels 4 bytes for left +4 bytes for right.
        // read left and right channel values for the first song
        float source1_L=song1ByteArray.readFloat();// I'm not sure if readFloat() function exists in android but there will be an equivalant one.
        float source1_R=song1ByteArray.readFloat(); 
        float source2_L=0;
        float source2_R=0;
        if(song2ByteArray.bytesAvailable>0){
            source2_L=song1ByteArray.readFloat();//left channel of audio song2ByteArray
            source2_R=song1ByteArray.readFloat(); //right channel of audio song2ByteArray
        }
        returnResultArr.writeFloat((source_1_L+source_2_L)/2); // average value of the source 1 and 2 left channel
        returnResultArr.writeFloat((source_1_R+source_2_R)/2); // average value of the source 1 and 2 right channel
    }
    return returnResultArr;
    }
    
smottt
  • 3,272
  • 11
  • 37
  • 44
0

1. Post on Audio mixing in Android

2. Another post on mixing audio in Android

3. You could leverage Java Sound to mix two audio files

Example:


// First convert audiofile to audioinputstream

audioInputStream = AudioSystem.getAudioInputStream(soundFile);
audioInputStream2 = AudioSystem.getAudioInputStream(soundFile2);

// Create one collection list object using arraylist then add all AudioInputStreams

Collection list=new ArrayList();
list.add(audioInputStream2);
list.add(audioInputStream);

// Then pass the audioformat and collection list to MixingAudioInputStream constructor

MixingAudioInputStream mixer=new MixingAudioInputStream(audioFormat, list); 

// Finally read data from mixed AudionInputStream and give it to SourceDataLine

nBytesRead =mixer.read(abData, 0,abData.length);

int nBytesWritten = line.write(abData, 0, nBytesRead);

4. Try AudioConcat that has a -m option for mixing


java AudioConcat [ -D ] [ -c ] | [ -m ] | [ -f ] -o outputfile inputfile ...

Parameters. 

-c
selects concatenation mode

-m
selects mixing mode

-f
selects float mixing mode

-o outputfile
The filename of the output file

inputfile
the name(s) of input file(s)

5. You could use ffmpeg android wrapper using a syntax and approach as explained here

Community
  • 1
  • 1
Sagar Hatekar
  • 8,700
  • 14
  • 56
  • 72
  • I don't think Java Sound was ported to Android back then. So the MixingAudioInputStream constructor won't work. – Advait Saravade Oct 21 '15 at 01:12
  • Yes I've tried this. The sound API hasn't been ported over to Android. There's even a discussion about it here - https://groups.google.com/forum/m/#!topic/android-developers/VD2V7ENFrgs – Advait Saravade Oct 21 '15 at 07:35
0

This guy used the JLayer library in a project quite similar to yours. He also gives you a guide on how to integrate that library in your android application directly recompiling the jar.

Paraphrasing his code it is very easy to accomplish your task:

public static byte[] decode(String path, int startMs, int maxMs) 
  throws IOException, com.mindtherobot.libs.mpg.DecoderException {
  ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);

  float totalMs = 0;
  boolean seeking = true;

  File file = new File(path);
  InputStream inputStream = new BufferedInputStream(new FileInputStream(file), 8 * 1024);
  try {
    Bitstream bitstream = new Bitstream(inputStream);
    Decoder decoder = new Decoder();

    boolean done = false;
    while (! done) {
      Header frameHeader = bitstream.readFrame();
      if (frameHeader == null) {
        done = true;
      } else {
        totalMs += frameHeader.ms_per_frame();

        if (totalMs >= startMs) {
          seeking = false;
        }

        if (! seeking) {
          SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);

          if (output.getSampleFrequency() != 44100
              || output.getChannelCount() != 2) {
            throw new com.mindtherobot.libs.mpg.DecoderException("mono or non-44100 MP3 not supported");
          }

          short[] pcm = output.getBuffer();
          for (short s : pcm) {
            outStream.write(s & 0xff);
            outStream.write((s >> 8 ) & 0xff);
          }
        }

        if (totalMs >= (startMs + maxMs)) {
          done = true;
        }
      }
      bitstream.closeFrame();
    }

    return outStream.toByteArray();
  } catch (BitstreamException e) {
    throw new IOException("Bitstream error: " + e);
  } catch (DecoderException e) {
    Log.w(TAG, "Decoder error", e);
    throw new com.mindtherobot.libs.mpg.DecoderException(e);
  } finally {
    IOUtils.safeClose(inputStream);     
  }
}

public static byte[] mix(String path1, String path2) {
    byte[] pcm1 = decode(path1, 0, 60000); 
    byte[] pcm2 = decode(path2, 0, 60000);
    int len1=pcm1.length; 
    int len2=pcm2.length;
    byte[] pcmL; 
    byte[] pcmS;
    int lenL; // length of the longest
    int lenS; // length of the shortest
    if (len2>len1) {
        lenL = len1;
        pcmL = pcm1;
        lenS = len2;                
        pcmS = pcm2;
    } else {
        lenL = len2;
        pcmL = pcm2;
        lenS = len1;                
        pcmS = pcm1;
    } 
    for (int idx = 0; idx < lenL; idx++) {
        int sample;
        if (idx >= lenS) {
            sample = pcmL[idx];
        } else {
            sample = pcmL[idx] + pcmS[idx];
        }
        sample=(int)(sample*.71);
        if (sample>127) sample=127;
        if (sample<-128) sample=-128;
        pcmL[idx] = (byte) sample;
    }
    return pcmL;
}

Note that I added attenuation and clipping in the last rows: you always have to do both when mixing two waveforms. If you don't have memory/time requirements you can make an int[] of the sum of the samples and evaluate what is the best attenuation to avoid clipping.

NicolaSysnet
  • 486
  • 2
  • 10
0

To merge (overlap) two sound files, you can use This FFMPEG library.

Here is the Documentation

In their sample you can just enter the command you want. So lets talk about the command that we need.

-i [FISRST_FILE_PATH] -i [SECOND_FILE_PATH] -filter_complex amerge -ac 2 -c:a libmp3lame -q:a 4 [OUTPUT_FILE_PATH]

For first and second file paths, you will get the absolute path of the sound file. 1- If it is on storage then it is a sub folder for Environment.getExternalStorageDirectory().getAbsolutePath()

2- If it is assets so it should be a sub folder for file:///android_asset/

For the output path, Make sure to add the extension ex.

String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/File Name.mp3"
Omar HossamEldin
  • 3,033
  • 1
  • 25
  • 51
-1

I didn't get any fine solution.but we can do some trick here.. :) You can assign both mp3 files to two different MediaPlayer object.then play both files at a time with a button.compare both mp3 files to find the longest duration.after that Use a AudioReorder to record to that duration. it will solve your problem..I know its not a right way but hope it will help you.. :)

Vanilla Boy
  • 258
  • 2
  • 12