¿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

  • SetFocus (overlayItem) de ItemizedOverlay no funciona
  • Superposición de imagen en dos filas en una vista de lista
  • Cómo agregar vista de superposición sobre otra vista en android?
  • Convertir la ubicación en GeoPoint
  • ¿Posible superponer un botón encima de otro?
  • Dibujar texto en la parte superior de mapa de bits no
  • Clips de superposición de objetos de galería
  • ¿Cómo grabar video con superposición animada en Android?
  • Android - los estados de la superposición automática táctil / resaltado del estado de la imagen
  • Imagen sobre otra imagen Android
  • Superposición sobre la barra de navegación en Android 4
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.