Is it possible to merge two audio files into one android?

3

Example: Audio A + Audio B = Audio C. I need the sounds to come together, do not concatenate.

The format can be WAV, but I preferred it to be MP3.

I found some examples on the net, but none worked.

protected Void myMethod() {
    List<String> selection = new ArrayList<String>(); 

    selection.add("a.wav");
    selection.add("b.wav");

    isProcessingOn=true;
    int RECORDER_SAMPLERATE = 0;
    try {
        DataOutputStream amplifyOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(Environment.getExternalStorageDirectory() + "/ssmultitrackPlus/project1/NOVO.wav")));
        DataInputStream[] mergeFilesStream = new DataInputStream[selection.size()];
        long[] sizes=new long[selection.size()];
        for(int i=0; i<selection.size(); i++) {
            File file = new File(Environment.getExternalStorageDirectory() + "/ssmultitrackPlus/project1/" +selection.get(i));
         sizes[i] = (file.length()-44)/2;
        }
        for(int i =0; i<selection.size(); i++) {
            mergeFilesStream[i] =new DataInputStream(new BufferedInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/ssmultitrackPlus/project1/" +selection.get(i))));


           // if(i == selection.size()-1) {
                mergeFilesStream[i].skip(24);
                byte[] sampleRt = new byte[4];
                mergeFilesStream[i].read(sampleRt);
                ByteBuffer bbInt = ByteBuffer.wrap(sampleRt).order(ByteOrder.LITTLE_ENDIAN);
                RECORDER_SAMPLERATE = bbInt.getInt();
                mergeFilesStream[i].skip(16);
          //  }
            //    else {
               //     mergeFilesStream[i].skip(44);
           //     }

        }

        for(int b=0; b<selection.size(); b++) {
        for(int i=0; i<(int)sizes[b]; i++) {
             byte[] dataBytes = new byte[2];
             try {
             dataBytes[0] = mergeFilesStream[b].readByte();
             dataBytes[1] = mergeFilesStream[b].readByte();
             }
             catch (EOFException e) {
                amplifyOutputStream.close();
             }
             short dataInShort = ByteBuffer.wrap(dataBytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
             float dataInFloat= (float) dataInShort/37268.0f;


            short outputSample = (short)(dataInFloat * 37268.0f);
            byte[] dataFin = new byte[2];
           dataFin[0] = (byte) (outputSample & 0xff);
           dataFin[1] = (byte)((outputSample >> 8) & 0xff);        
          amplifyOutputStream.write(dataFin, 0 , 2);

        }
        }
        amplifyOutputStream.close();
        for(int i=0; i<selection.size(); i++) {
            mergeFilesStream[i].close();
        }

    } catch (FileNotFoundException e) {

        e.printStackTrace();
    } catch (IOException e) {

        e.printStackTrace();
    }
    long size =0;
    try {
        FileInputStream fileSize = new FileInputStream(Environment.getExternalStorageDirectory() + "/ssmultitrackPlus/project1/NOVO.wav");
        size = fileSize.getChannel().size();
        fileSize.close();
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    final int RECORDER_BPP = 16;

    long datasize=size+36;
    long byteRate = (RECORDER_BPP * RECORDER_SAMPLERATE)/8;
    long longSampleRate = RECORDER_SAMPLERATE;
    byte[] header = new byte[44];




     header[0] = 'R';  // RIFF/WAVE header 
     header[1] = 'I';
     header[2] = 'F';
     header[3] = 'F';
     header[4] = (byte) (datasize & 0xff);
     header[5] = (byte) ((datasize >> 8) & 0xff);
     header[6] = (byte) ((datasize >> 16) & 0xff);
     header[7] = (byte) ((datasize >> 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) 1;
     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) ((RECORDER_BPP) / 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) (size & 0xff);
     header[41] = (byte) ((size >> 8) & 0xff);
     header[42] = (byte) ((size >> 16) & 0xff);
     header[43] = (byte) ((size >> 24) & 0xff);
   // out.write(header, 0, 44); 

    try {
         RandomAccessFile rFile = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/ssmultitrackPlus/project1/NOVO.Wav", "rw");
        rFile.seek(0);
        rFile.write(header);
        rFile.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    return null;
}

The code above concatenates the tracks, I would like you to join the two or more sounds at the same time.

    
asked by anonymous 24.09.2014 / 05:02

1 answer

5

Your logic is correct, unfortunately you have not shown how you are trying to do on Android, you may need to know a little theory to understand what is going on with your code, any kind of sound can be defined as vibrations propagating through air until it reaches your ears:

Haveyoueverwonderedhowyoucanhearavastnumberofsoundshappeningsimultaneously?

A:Withoutyouknowingeverythingisbeingmixed,allvibrationsoccurringintheenvironmentcometogetherandareinterpretedbyyourauditorysystem!

Computationalallywearesimulatingtheauditorysystem,ifwewantdifferentsoundoriginstojoin,wejustaddthevibrationalpulses.

Howtodothis?

A:Youwillneedtherawinformationtobeabletomanipulateyouraudio,thisappliestoanytypeofmanipulationneededeg:changeaudiovolume,changefrequency,slowdownorfaster,etc.

WhenIsaid" informação crua " I mean that it is the data of your audio before undergoing any coding in mp3, wav, ogg, etc., and to achieve this in recorded and encoded audio, audio format you will find a different algorithm, start with .wav samples are simpler to decode / encode, I believe there should be a vast alternative in Android for this step!

OK with the decoded data you can have a vector (if the audio is mono), with the manipulable values, I advise that the decoded values are in the format float point 32bit , the values of your vector will be between -1 e 1 .

With this data you can simply add the two vectors decoded in the float format, to prevent any overflow in the values with amplitude close to the end (to prevent noise) you can multiply the two vectors by% with% and then add you can normalize the output, a pseudo code with this step would be:

resultado = (vetor1 * 0.5) + (vetor2 * 0.5)

To normalize find the absolute maximum value of the above result and multiply by the result

Resultado_final_normalizado = (1 / max(abs(resultado))) * resultado 

Ps: The two audio you want to add need to have the same sample rate, another point to note is if the two vectors after decoding will have the same size, if they are different then concatenate the smaller vector with 0.5 to stay the same size!

EDIT:

Code used to merge three audio files:

private void mixFiles(){
                try {
                        InputStream is1 = getResources().openRawResource(R.raw.test1);
                        List<Short> music1 = createMusicArray(is1);

                        InputStream is2 = getResources().openRawResource(R.raw.test2);
                        List<Short> music2 = createMusicArray(is2);

                        InputStream is3 = getResources().openRawResource(R.raw.test3);
                        List<Short> music3 = createMusicArray(is3);

                        completeStreams(music1,music2,music3);
                        short[] music1Array = buildShortArray(music1);
                        short[] music2Array = buildShortArray(music2);
                        short[] music3Array = buildShortArray(music3);

                        short[] output = new short[music1Array.length];
                        for(int i=0; i < output.length; i++){

                                float samplef1 = music1Array[i] / 32768.0f;
                                float samplef2 = music2Array[i] / 32768.0f;
                                float samplef3 = music3Array[i] / 32768.0f;

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


                                output[i] = outputSample;
                        }
                        CHAME_AQUI_SUA_FUNCAO_PARA_SALVAR_EM_WAVE
                } catch (NotFoundException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

Notice the variable zeros it will contain the mixed files in raw, call some function that saves the result in wave. The code shown by you seems to have a function that writes the header + date of the file to output , you can reuse this piece of code.

The above code is slightly different from the one proposed by me, in this case it just checks if the signal amplitude is greater than .wave or 1 if yes the amplitude is forced to stay at its ends.

    
30.09.2014 / 15:50