如何混合/重叠两个MP3audio文件到一个MP3文件(不连接)

我想合并两个MP3文件到一个MP3文件。例如,如果第一个文件是1分钟,第二个文件是30秒,那么输出应该是一分钟。 在那一分钟里它应该播放这两个文件。

Solutions Collecting From Web of "如何混合/重叠两个MP3audio文件到一个MP3文件(不连接)"

首先, 为了混合两个audio文件,你需要操纵它们的原始表示 ; 由于MP3文件是压缩的 ,因此您不能直接访问信号的原始表示。 您需要解码压缩的MP3stream,以便“理解”audio信号的波形,然后才能混合它们。

因此,为了将两个压缩audio文件混合成单个压缩audio文件,需要以下步骤:

  1. 使用解码器解码压缩文件以获得原始数据( NO PUBLIC SYSTEM API可用于此,您需要手动完成! )。
  2. 混合两个未压缩的原始数据stream(如果需要,应用audio剪辑 )。 为此,您需要考虑使用解码器 ( PCM )获得的原始数据格式,
  3. 将原始混合数据编码成压缩的MP3文件(按照解码器,您需要使用编码器手动完成)

更多信息MP3解码器可以在这里find。

我不确定你是否想在Android手机上这样做(看起来像是因为你的标签),但如果我是对的也许尝试LoopStack ,这是一个移动DAW(没有自己尝试)。

如果您只是在不调整输出音量的情况下“混合”两个文件,则输出可能会被剪辑。 但是我不确定是否可以“混合”两个mp3文件而不解码它们。

如果你可以将它们合并到你的PC上,试试Audacity ,这是一个免费的桌面DAW。

我没有在Android中完成,但我已经使用Adobe Flex做了。 我猜这个逻辑还是一样的。 我遵循以下步骤:

  • 我将两个mp3都解压到两个字节数组中。 ( song1ByteArraysong2ByteArray
  • 找出更大的字节数组。 (比方说, song1ByteArray是较大的一个)。
  • 创build一个返回混合字节数组的函数。

     private ByteArray mix2Songs(ByteArray song1ByteArray, ByteArray song2ByteArray){ int arrLength=song1ByteArray.length; for(int i=0;i<arrLength;i+=8){ // here if you see we are incrementing the length by 8 because a sterio sound has both left and right channels 4 bytes for left +4 bytes for right. // read left and right channel values for the first song float source1_L=song1ByteArray.readFloat();// I'm not sure if readFloat() function exists in android but there will be an equivalant one. float source1_R=song1ByteArray.readFloat(); float source2_L=0; float source2_R=0; if(song2ByteArray.bytesAvailable>0){ source2_L=song1ByteArray.readFloat();//left channel of audio song2ByteArray source2_R=song1ByteArray.readFloat(); //right channel of audio song2ByteArray } returnResultArr.writeFloat((source_1_L+source_2_L)/2); // average value of the source 1 and 2 left channel returnResultArr.writeFloat((source_1_R+source_2_R)/2); // average value of the source 1 and 2 right channel } return returnResultArr; } 

1. 在Android上发布混音

2. 另一个在Android上混音的post

3.您可以利用Java Sound混合两个audio文件

例:

 // First convert audiofile to audioinputstream audioInputStream = AudioSystem.getAudioInputStream(soundFile); audioInputStream2 = AudioSystem.getAudioInputStream(soundFile2); // Create one collection list object using arraylist then add all AudioInputStreams Collection list=new ArrayList(); list.add(audioInputStream2); list.add(audioInputStream); // Then pass the audioformat and collection list to MixingAudioInputStream constructor MixingAudioInputStream mixer=new MixingAudioInputStream(audioFormat, list); // Finally read data from mixed AudionInputStream and give it to SourceDataLine nBytesRead =mixer.read(abData, 0,abData.length); int nBytesWritten = line.write(abData, 0, nBytesRead); 

4.尝试使用具有-m选项的AudioConcat进行混音

 java AudioConcat [ -D ] [ -c ] | [ -m ] | [ -f ] -o outputfile inputfile ... Parameters. -c selects concatenation mode -m selects mixing mode -f selects float mixing mode -o outputfile The filename of the output file inputfile the name(s) of input file(s) 

5.你可以使用ffmpeg的android wrapper来使用这里解释的语法和方法

这个人在一个和你的项目非常相似的项目中使用了JLayer库。 他还给你一个关于如何将你的android应用程序直接重新编译jar的库集成的指南。

解释他的代码很容易完成你的任务:

 public static byte[] decode(String path, int startMs, int maxMs) throws IOException, com.mindtherobot.libs.mpg.DecoderException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024); float totalMs = 0; boolean seeking = true; File file = new File(path); InputStream inputStream = new BufferedInputStream(new FileInputStream(file), 8 * 1024); try { Bitstream bitstream = new Bitstream(inputStream); Decoder decoder = new Decoder(); boolean done = false; while (! done) { Header frameHeader = bitstream.readFrame(); if (frameHeader == null) { done = true; } else { totalMs += frameHeader.ms_per_frame(); if (totalMs >= startMs) { seeking = false; } if (! seeking) { SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream); if (output.getSampleFrequency() != 44100 || output.getChannelCount() != 2) { throw new com.mindtherobot.libs.mpg.DecoderException("mono or non-44100 MP3 not supported"); } short[] pcm = output.getBuffer(); for (short s : pcm) { outStream.write(s & 0xff); outStream.write((s >> 8 ) & 0xff); } } if (totalMs >= (startMs + maxMs)) { done = true; } } bitstream.closeFrame(); } return outStream.toByteArray(); } catch (BitstreamException e) { throw new IOException("Bitstream error: " + e); } catch (DecoderException e) { Log.w(TAG, "Decoder error", e); throw new com.mindtherobot.libs.mpg.DecoderException(e); } finally { IOUtils.safeClose(inputStream); } } public static byte[] mix(String path1, String path2) { byte[] pcm1 = decode(path1, 0, 60000); byte[] pcm2 = decode(path2, 0, 60000); int len1=pcm1.length; int len2=pcm2.length; byte[] pcmL; byte[] pcmS; int lenL; // length of the longest int lenS; // length of the shortest if (len2>len1) { lenL = len1; pcmL = pcm1; lenS = len2; pcmS = pcm2; } else { lenL = len2; pcmL = pcm2; lenS = len1; pcmS = pcm1; } for (int idx = 0; idx < lenL; idx++) { int sample; if (idx >= lenS) { sample = pcmL[idx]; } else { sample = pcmL[idx] + pcmS[idx]; } sample=(int)(sample*.71); if (sample>127) sample=127; if (sample<-128) sample=-128; pcmL[idx] = (byte) sample; } return pcmL; } 

请注意,我在最后一行中添加了衰减和削波:在混合两个波形时,您总是必须执行这两个操作。 如果你没有内存/时间的要求,你可以做一个int []的样本总和,并评估什么是最好的衰减,以避免削减。

要合并(重叠)两个声音文件,您可以使用此FFMPEG库 。

这里是文档

在他们的例子中,你可以input你想要的命令。 所以让我们来谈谈我们需要的命令。

 -i [FISRST_FILE_PATH] -i [SECOND_FILE_PATH] -filter_complex amerge -ac 2 -c:a libmp3lame -q:a 4 [OUTPUT_FILE_PATH] 

对于第一个和第二个文件path,您将获得声音文件的绝对path。 1-如果在存储上,则它是Environment.getExternalStorageDirectory().getAbsolutePath()的子文件夹Environment.getExternalStorageDirectory().getAbsolutePath()

2-如果它是资产,所以它应该是文件的子文件夹file:///android_asset/

对于输出path,确保添加扩展名ex。

 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/File Name.mp3" 

我没有得到任何好的解决scheme,但我们可以在这里做一些技巧.. :)您可以将两个MP3文件分配给两个不同的MediaPlayer对象。然后同时播放两个文件与一个button.compare和两个mp3文件来find最长持续时间。之后使用AudioReorderlogging到该持续时间。 它会解决你的问题..我知道它不是一个正确的方式,但希望它会帮助你.. 🙂