2015-06-23 29 views
5

Quello che sto cercando di realizzare è la sovrapposizione di una traccia vocale su una traccia musicale per formare una nuova traccia canzone.Come posso sovrapporre un file audio a un altro e salvarlo?

Ecco un codice che ho. Sto leggendo il vocal.mp3 utilizzando FileInputStream e poi salvarla in un array di byte in questo modo ...

 try { 
      fis = new FileInputStream(myFile); 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     bos = new ByteArrayOutputStream(); 
     byte[] buf = new byte[2048]; 
     try { 
      for (int readNum; (readNum = fis.read(buf)) != -1;) { 
       bos.write(buf, 0, readNum); 
       System.out.println("read " + readNum + " bytes,"); 
      } 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 

     bytes = bos.toByteArray(); 

Allora ... io faccio la stessa cosa per il music.mp3 e letto che in un array di byte separata. Non mi preoccuperò di mostrare il codice per questo dato che è lo stesso di sopra.

Dopo ho le due matrici di byte separati li posso combinare in questo modo ...

 outputStream = new ByteArrayOutputStream(); 
     try { 
      outputStream.write(bytes); 
      outputStream.write(bytes2); 
     } catch (IOException e1) { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 

     mixData = new byte[bytes.length + bytes2.length]; 
     mixData = outputStream.toByteArray(); 

E poi scrivere la matrice di byte combinato in un nuovo file song.mp3 per il salvataggio in questo modo ...

 File someFile = new File(songOutPath); 

     try { 
      fos2 = new FileOutputStream(someFile); 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     try { 
      fos2.write(mixData); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     try { 
      fos2.flush(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     try { 
      fos2.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

Questo codice unire i due mp3 file in un unico ... ma svolgono uno dopo l'altro ... ho bisogno di sapere se qualcuno mi può aiutare a trovare un modo per farli giocare contemporaneamente. In questo modo la traccia vocale e musicale suonerà allo stesso tempo in un nuovo file di brani che genererei.

UPDATE

Ecco un aggiornamento per la direzione che sto prendendo nel mio codice.

vorrei chiamare un metodo e passare due filepaths per ogni file mp3 separato, qualcosa in questo modo:

mixSamples(String filePathOne, String filePathTwo)

allora in quel modo vorrei usare estrattore media per estrarre i dati da ogni file mp3 e quindi decodificare ogni file. Dopo che i file sono stati decodificati, desidero memorizzare ciascun file in un short[] e quindi chiamare il metodo mix() come illustrato di seguito per mescolare i due short[]'s in uno short[] combinato e quindi codificare nuovamente l'array appena creato in un mp3.

public void mixSamples(String filePathOne, String filePathTwo){ 
     MediaCodec codec = null; 

     MediaExtractor extractor = new MediaExtractor(); 
     try { 
      extractor.setDataSource(filePathOne); 
      return create(extractor); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } finally { 
      extractor.release(); 
     } 

     // ... Do I create another extractor here for my second file? 

     MediaFormat format = extractor.getTrackFormat(0); 
     String mime = format.getString(MediaFormat.KEY_MIME); 
     format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2); 
     format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); 

     try { 
      codec = MediaCodec.createDecoderByType(mime); 
      codec.configure(format, null, null, 0); 
      codec.start(); 
      ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); 
      ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); 

      extractor.selectTrack(0); 

      MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 
      final long timeoutUs = 5000; 
      boolean sawInputEOS = false; 
      boolean sawOutputEOS = false; 
      int noOutputCounter = 0; 

      while (!sawOutputEOS && noOutputCounter < 50) { 
       noOutputCounter++; 
       if (!sawInputEOS) { 
        int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs); 
        if (inputBufferIndex >= 0) { 
         ByteBuffer buffer = codecInputBuffers[inputBufferIndex]; 
         int sampleSize = extractor.readSampleData(buffer, 0); 
         long presentationTimeUs = 0; 
         if (sampleSize < 0) { 
          sawInputEOS = true; 
          sampleSize = 0; 
         } else { 
          presentationTimeUs = extractor.getSampleTime(); 
         } 
         codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, 
           presentationTimeUs, 
           sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); 
         if (!sawInputEOS) { 
          extractor.advance(); 
         } 
        } 
       } 

       int outputBufferIndex = codec.dequeueOutputBuffer(info, timeoutUs); 
       if (outputBufferIndex >= 0) { 
        if (info.size > 0) { 
         noOutputCounter = 0; 
        } 
        ByteBuffer buffer = codecOutputBuffers[outputBufferIndex]; 
        if (info.size > 0) { 

         // Do something... Maybe create my short[] here... 
        } 
        codec.releaseOutputBuffer(outputBufferIndex, false); 
        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
         sawOutputEOS = true; 
        } 
       } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
        codecOutputBuffers = codec.getOutputBuffers(); 
       } 
      } 
     } catch (IOException e){ 

     }finally { 
      codec.stop(); 
      codec.release(); 
     } 
    } 

    static short[] mix(short[] buffer, short[] mixWith, int numberOfMixSamples) { 
     final int length = Math.min(buffer.length, numberOfMixSamples); 
     int mixed; 
     for (int i = 0; i < length; i++) { 
      mixed = (int) buffer[i] + (int) mixWith[i]; 
      if (mixed > 32767) mixed = 32767; 
      if (mixed < -32768) mixed = -32768; 
      buffer[i] = (short) mixed; 
     } 
     return buffer; 
    } 
+0

Vuoi giocare a tema, allo stesso tempo, o semplicemente unire i byte? – Karoly

+0

Voglio riprodurli allo stesso tempo ... ma potrebbe essere necessario unire i due array di byte in un array di byte per salvare in un nuovo file con il brano completato. Stavo pensando che forse esiste un modo per creare un ciclo che legge una piccola frazione di ogni array di byte e quindi ruota avanti e indietro tra gli array di byte scrivendo un byte alla volta sul terzo e sull'array finale. – AMG

risposta

2

che si desidera utilizzare MediaCodec con MediaExtractor di decodificare MP3 (o qualsiasi altro formato audio) ai campioni. Ogni campione è presentato per byte non byte. Alla fine avresti breve [] (numero di campioni). Una volta decodificati entrambi i file audio, è possibile unire campioni per produrre nuovi campioni. Quindi ripristinare la procedura per codificare in formato audio utilizzando i campioni dei risultati. Ho usato PCM16 come formato intermedio. Uno dei modi per mescolare audio insieme può essere questo:

static short[] mix(short[] buffer, short[] mixWith, int numberOfMixSamples) { 
    final int length = Math.min(buffer.length, numberOfMixSamples); 
    int mixed; 
    for (int i = 0; i < length; i++) { 
     mixed = (int) buffer[i] + (int) mixWith[i]; 
     if (mixed > 32767) mixed = 32767; 
     if (mixed < -32768) mixed = -32768; 
     buffer[i] = (short) mixed; 
    } 
    return buffer; 
} 

UPDATE Dare codice dal mio cuore :) ho intenzione di scrivere articoli su di esso in seguito sul mio blog android.vladli.com. Questo codice è per codice già deprecato, funzionerà e la nuova API è leggermente più pulita, anche se non molto diversa.

MediaExtractor extractor = new MediaExtractor(); 
extractor.setDataSource(file.getAbsolutePath()); 
try { 
    return create(extractor); 
} finally { 
    extractor.release(); 
} 

// ... 

MediaFormat format = extractor.getTrackFormat(0); 
String mime = format.getString(MediaFormat.KEY_MIME); 
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2); 
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); 

MediaCodec codec = MediaCodec.createDecoderByType(mime); 
codec.configure(format, null, null, 0); 
codec.start(); 

try { 
    ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); 
    ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); 

    extractor.selectTrack(0); 

    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 
    final long timeoutUs = 5000; 
    boolean sawInputEOS = false; 
    boolean sawOutputEOS = false; 
    int noOutputCounter = 0; 

    while (!sawOutputEOS && noOutputCounter < 50) { 
     noOutputCounter++; 
     if (!sawInputEOS) { 
      int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs); 
      if (inputBufferIndex >= 0) { 
       ByteBuffer buffer = codecInputBuffers[inputBufferIndex]; 
       int sampleSize = extractor.readSampleData(buffer, 0); 
       long presentationTimeUs = 0; 
       if (sampleSize < 0) { 
        sawInputEOS = true; 
        sampleSize = 0; 
       } else { 
        presentationTimeUs = extractor.getSampleTime(); 
       } 
       codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, 
         presentationTimeUs, 
         sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); 
       if (!sawInputEOS) { 
        extractor.advance(); 
       } 
      } 
     } 

     int outputBufferIndex = codec.dequeueOutputBuffer(info, timeoutUs); 
     if (outputBufferIndex >= 0) { 
      if (info.size > 0) { 
       noOutputCounter = 0; 
      } 
      ByteBuffer buffer = codecOutputBuffers[outputBufferIndex]; 
      if (info.size > 0) { 
       // data.writePcm16(buffer, info.offset, info.size); 
       // data here is my class to gather buffer (samples) in a queue for further playback. In your case can write them down into disk or do something else 
      } 
      codec.releaseOutputBuffer(outputBufferIndex, false); 
      if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
       sawOutputEOS = true; 
      } 
     } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
      codecOutputBuffers = codec.getOutputBuffers(); 
     } 
    } 
} finally { 
    codec.stop(); 
    codec.release(); 
} 
+0

Non ho mai provato ad usarlo, apprezzerei un buon esempio di come utilizzare MediaCodec con MediaExtractor per decodificare i miei file mp3 in array corti ... quindi presumo di poter utilizzare il tuo esempio precedente per mixare due campioni in un array breve – AMG

+0

Please , vedi il codice aggiornato sopra. –

+0

Grazie mille @Vladimir Lichonos per il tuo aiuto, sto iniziando a capire le cose un po 'più chiaramente ora. Tuttavia, sto ancora avendo problemi con questo e questo mi ha perseguitato per anni. Ho aggiornato la mia domanda per spiegare il processo che sto cercando di raggiungere e spero che possa aiutarmi ulteriormente :) Non appena sarà disponibile una taglia per questo, la offrirò e la assegnerò per ulteriore assistenza. – AMG