2015-06-23 13 views
5

Was ich versuche zu erreichen, ist eine Überlagerung einer Gesangsspur über eine Musikspur, um eine neue Liedspur zu bilden.Wie kann ich eine Audiodatei über eine andere legen und sie speichern?

Hier ist ein Code, den ich habe. Ich lese die vocal.mp3FileInputStream verwenden und dann zu einem Byte-Array Speicher wie so ...

 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(); 

Dann ... ich tue das Gleiche für die music.mp3 und dass in einen separaten Byte-Array gelesen. Ich werde nicht den Code dafür zeigen, da es das gleiche wie oben ist.

Nachdem ich die zwei separate Byte-Arrays haben kann ich sie wie so kombinieren ...

 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(); 

Und dann zu einer neuen song.mp3 Datei die kombinierte Byte-Array schreiben wie so für das Speichern von ...

 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(); 
     } 

Dieser Code wird die beiden mp3-Dateien in eine verschmelzen ... aber sie spielen eine nach der anderen ... ich muss wissen, wenn mir jemand einen Weg, sie zu erhalten, finden helfen können gleichzeitig zu spielen. Auf diese Weise wird der Gesangs- und Musiktitel gleichzeitig in einer neuen Song-Datei abgespielt, die ich erzeugen würde.

UPDATE

Hier ist ein Update auf die Richtung, die ich in meinem Code nehmen werde.

Ich möchte eine Methode aufrufen und es zwei Dateipfade für jede separate MP3-Datei, so etwas wie so passieren:

mixSamples(String filePathOne, String filePathTwo)

Dann in dieser Methode würde ich gerne Medien Extraktor verwenden, um die Daten zu extrahieren von jeder mp3 Datei und dekodieren Sie dann jede Datei. Nachdem die Dateien dekodiert wurden, möchte ich jede Datei in einem short[] speichern und dann die mix() Methode wie unten zu sehen, um die beiden short[]'s zu einem kombinierten short[] zu mischen und dann dieses neu erstellte Array wieder in ein mp3 zu kodieren.

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

tun Sie Thema zur gleichen Zeit spielen wollen, oder einfach nur die Bytes zusammenführen? – Karoly

+0

Ich möchte sie zur gleichen Zeit spielen ... aber die zwei Byte-Arrays müssen möglicherweise auch in ein Byte-Array zusammengeführt werden, um in einer neuen Datei mit dem fertigen Lied zu speichern. Ich dachte, vielleicht gibt es eine Möglichkeit, eine Schleife zu machen, die einen kleinen Bruchteil jedes Bytearrays liest und dann zwischen den Bytearrays hin und her rotiert, wobei sie jeweils ein Byte in das dritte und letzte Array schreibt. – AMG

Antwort

2

Sie wollen MediaCodec mit MediaExtractor verwenden mp3 (oder ein anderes Audioformat) zu den Proben zu dekodieren. Jeder Abtastwert wird durch ein kurzes Nicht-Byte dargestellt. Schließlich hätten Sie kurz [] (Anzahl der Proben). Sobald Sie beide Audiodateien dekodiert haben, können Sie die Samples zusammenmischen, um neue Samples zu erzeugen. Stellen Sie dann den Prozess wieder her, um mithilfe von Ergebnissamples in das Audioformat zu codieren. Ich habe PCM16 als Zwischenformat verwendet. Eine der Möglichkeiten, Audio mischen kann das sein:

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 Giving Code aus meinem Herzen :) Ich werde Artikel darauf android.vladli.com später auf meinem Blog zu schreiben. Dieser Code ist für bereits veralteten Code, es funktioniert, und neue API ist etwas sauberer, obwohl nicht viel anders.

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

Ich habe nie versucht, das, ich würde ein gutes Beispiel, wie MediaCodec mit MediaExtractor verwenden, um meine MP3-Dateien in kurze Arrays zu decodieren verwenden ... dann nehme ich an, ich könnte Ihr vorheriges Beispiel verwenden, um zwei Proben zu einem kurzen Array zu mischen – AMG

+0

Bitte , siehe oben aktualisierten Code. –

+0

Vielen Dank @Vladimir Lichonos für Ihre Hilfe, ich beginne die Dinge jetzt ein wenig klarer zu verstehen. Allerdings habe ich immer noch Probleme damit und das verfolgt mich seit Jahren. Ich habe meine Frage aktualisiert, um den Prozess, den ich zu erreichen versuche, zu erklären, und ich hoffe, dass Sie mir weiterhelfen können. Sobald ein Kopfgeld verfügbar ist, werde ich es Ihnen für Ihre weitere Unterstützung anbieten und verleihen. – AMG

Verwandte Themen