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;
}
Vuoi giocare a tema, allo stesso tempo, o semplicemente unire i byte? – Karoly
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