2015-06-23 11 views
5

Điều tôi đang cố gắng hoàn thành là phủ một bản nhạc thanh nhạc lên bản nhạc để tạo thành bản nhạc mới.Làm cách nào để phủ một tệp âm thanh lên một tệp khác và lưu tệp đó?

Đây là một số mã tôi có. Tôi đọc vocal.mp3 sử dụng FileInputStream và sau đó lưu nó vào một mảng byte như vậy ...

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

Sau đó ... Tôi làm điều tương tự cho music.mp3 và đọc đó vào một mảng byte riêng biệt. Tôi sẽ không bận tâm hiển thị mã cho điều đó vì nó giống như trên.

Sau khi tôi có hai mảng byte riêng tôi có thể kết hợp chúng như vậy ...

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

Và sau đó viết mảng byte kết hợp vào một tập tin song.mp3 mới để tiết kiệm như vậy ...

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

mã này sẽ hợp nhất hai mp3 file thành một ... nhưng họ chơi cái khác ... tôi cần phải biết nếu ai đó có thể giúp tôi tìm một cách để có được chúng để chơi cùng một lúc. Bằng cách này, bản nhạc và bản nhạc sẽ phát cùng lúc trong một tập tin bài hát mới mà tôi sẽ tạo ra.

CẬP NHẬT

Đây là bản cập nhật theo hướng tôi đang dùng trong mã của mình.

Tôi muốn gọi một phương thức và vượt qua nó hai filepaths cho mỗi tập tin mp3 riêng biệt, một cái gì đó giống như vậy:

mixSamples(String filePathOne, String filePathTwo)

Sau đó, trong phương pháp mà tôi muốn sử dụng phương tiện truyền thông vắt để trích xuất các dữ liệu từ mỗi tệp mp3 và sau đó giải mã từng tệp. Sau khi các tập tin đã được giải mã, tôi muốn lưu trữ mỗi tập tin trong một short[] và sau đó gọi phương thức mix() như dưới đây để kết hợp hai short[]'s thành một kết hợp short[] và sau đó mã hóa mảng mới được tạo trở lại thành một 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

bạn có muốn phát chủ đề cùng một lúc hoặc chỉ hợp nhất các byte không? – Karoly

+0

Tôi muốn phát chúng cùng một lúc ... nhưng hai mảng byte cũng có thể cần phải hợp nhất thành một mảng byte để lưu vào một tệp mới với bài hát đã hoàn thành. Tôi đã suy nghĩ có thể có một cách để làm cho một vòng lặp mà đọc một phần nhỏ của mỗi mảng byte và sau đó quay qua lại giữa các mảng byte bằng văn bản một byte tại một thời gian để mảng thứ 3 và cuối cùng. – AMG

Trả lời

2

Bạn muốn sử dụng MediaCodec với MediaExtractor để giải mã mp3 (hoặc bất kỳ định dạng âm thanh nào khác) thành mẫu. Mỗi mẫu được trình bày bằng không ngắn byte. Cuối cùng bạn sẽ có [] ngắn (số mẫu). Khi bạn giải mã cả hai tệp âm thanh, bạn có thể trộn các mẫu lại với nhau để tạo mẫu mới. Sau đó, hoàn nguyên quy trình để mã hóa thành định dạng âm thanh bằng cách sử dụng mẫu kết quả. Tôi đã sử dụng PCM16 làm định dạng trung gian. Một trong những cách để trộn âm thanh lại với nhau có thể là thế này:

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

CẬP NHẬT Giving mã từ trái tim tôi :) Tôi sẽ viết bài về nó sau này trên blog của tôi android.vladli.com. Mã này dành cho mã không được dùng nữa, mã này sẽ hoạt động và API mới hơi sạch hơn, mặc dù không khác nhiều.

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

Tôi chưa bao giờ thử sử dụng, tôi sẽ đánh giá cao một ví dụ tốt về cách sử dụng MediaCodec với MediaExtractor để giải mã các tệp mp3 của tôi thành các mảng ngắn ... sau đó tôi giả sử tôi có thể sử dụng ví dụ trước của bạn để trộn hai mẫu vào một mảng ngắn – AMG

+0

, xem mã được cập nhật ở trên. –

+0

Cảm ơn bạn rất nhiều @Vladimir Lichonos cho sự giúp đỡ của bạn, tôi bắt đầu hiểu những điều rõ ràng hơn một chút ngay bây giờ. Tuy nhiên, tôi vẫn còn gặp rắc rối với điều này và điều này đã ám ảnh tôi trong nhiều năm. Tôi đã cập nhật câu hỏi của mình để giải thích quá trình tôi đang cố gắng đạt được và tôi hy vọng rằng bạn có thể hỗ trợ thêm cho tôi :) Ngay khi tiền thưởng có sẵn cho tôi, tôi sẽ cung cấp và trao giải thưởng đó cho bạn để được hỗ trợ thêm. – AMG

Các vấn đề liên quan