¿Cómo puedo superponer un archivo de audio sobre otro y guardarlo?

Lo que estoy tratando de lograr es superponer una pista vocal sobre una pista de música para formar una nueva canción.

Aquí hay algún código que tengo. Estoy leyendo el vocal.mp3 utilizando FileInputStream y luego guardarlo en una matriz de bytes como …

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

Entonces … hago lo mismo por la music.mp3 y leo eso en una matriz de bytes separados. No me voy a molestar en mostrar el código para que ya que es el mismo que el anterior.

Después de tener los dos arrays de bytes separados, puedo combinarlos como si …

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

Y luego escribir la matriz de bytes combinados a un nuevo archivo song.mp3 para guardar como …

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

Este código se fusionará los dos archivos mp3 en uno … pero juegan uno tras otro … Necesito saber si alguien me puede ayudar a encontrar una manera de hacer que jueguen simultáneamente. De esta manera, la pista vocal y musical tocará al mismo tiempo en un nuevo archivo de canciones que generaría.

ACTUALIZAR

Aquí hay una actualización de la dirección que estoy tomando en mi código.

Me gustaría llamar a un método y pasar dos rutas de archivo para cada archivo mp3 separado, algo así:

mixSamples(String filePathOne, String filePathTwo)

Entonces en ese método me gustaría usar extractor de medios para extraer los datos de cada archivo mp3 y luego decodificar cada archivo. Después de que los archivos han sido decodificados me gustaría almacenar cada archivo en un short[] y luego llamar al método mix() como se ve a continuación para mezclar los dos short[]'s en un combinado short[] y luego codificar que recién creado Array de nuevo en 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; } 

Desea utilizar MediaCodec con MediaExtractor para decodificar mp3 (o cualquier otro formato de audio) a muestras. Cada muestra se presenta por corto no byte. Eventualmente tendrías corto [] (número de muestras). Una vez que usted decodifica ambos archivos de audio, entonces usted podría mezclar las muestras juntas para producir nuevas muestras. A continuación, vuelva a procesar para codificar a formato de audio utilizando muestras de resultados. Utilicé el formato PCM16 como formato intermedio. Una de las maneras de mezclar audio juntos puede ser esto:

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

ACTUALIZACIÓN Dar código de mi corazón 🙂 Voy a escribir artículos en él más adelante en mi blog android.vladli.com. Este código es para el código ya desaprobado, que funcionará, y la nueva API es un poco más limpio, aunque no muy diferente.

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

He hecho el mismo hace unos años, solía tocar 4 música al mismo tiempo. He utilizado hilos. Cada hilo reproducido una música con reproductor de medios y se pueden sincronizar con Cyclbarrier.

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

  • Mapas de Android NullPointerException ItemizedOverlay
  • Implementación de un mapa interior
  • Android: ¿Cómo overlay-a-bitmap / draw-over un mapa de bits?
  • El desplazamiento y el zoom de MapView es lento después de agregar muchas superposiciones
  • Emular el botón Atrás con superposición en Android
  • ¿Posible superponer un botón encima de otro?
  • Superposición de imagen en dos filas en una vista de lista
  • Texto que no se muestra en la superposición de MapView
  • Superposición sobre un ImageView en Android
  • Mostrar una superposición de "ayuda" en un diseño de Android
  • SetFocus (overlayItem) de ItemizedOverlay no funciona
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.