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