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.mp3
FileInputStream
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;
}
tun Sie Thema zur gleichen Zeit spielen wollen, oder einfach nur die Bytes zusammenführen? – Karoly
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