近期需要做音轨合成这样一个功能,何为音轨合成,说白了就是N个音频文件合成一个,同时播放N个声音。然而网上各种找代码,并没有一个能用的,最后终于找到一个外国大神写的合音工具类,稍加修改便成了自己的东西,现在分享出来,方便大家使用。
模拟器没办法录音,所以这里先只提供一张效果图
我这里做的效果是点击开始录音开始录制声音,停止后将该录音文件存储在sd卡,并在中间的ListViw显示名字,点击item选中多条后,即可开始合音
先来说一下步骤,
1.录音并将录音文件存储在sd卡下
2.解码
3.合音
从大的方向来讲,要实现这里的效果只需以上三步
我这里使用的MediaRecorder录音,首先,点击按钮后开始录音:
MediaRecorder mRecorder = new MediaRecorder();
mRecorder.reset();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置声音来源
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 设置所录制的音视频文件的格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);// 设置所录制的声音的编码格式
mRecorder.setAudioEncodingBitRate(96000);// 比特率
mRecorder.setAudioChannels(2);// 通道
mRecorder.setAudioSamplingRate(44100);// 采样率
mRecorder.setOutputFile(recordFile.getAbsolutePath() + "/record"+ count + ".mp4");// 设置录制的音频文件的保存位置
try {mRecorder.prepare();
} catch (IOException e) {e.printStackTrace();
}
mRecorder.start();
这里需要注意的是:
1.要合音的文件格式必须相同,比如必须都是MP4或都是MP3,否则合出来的音会像卡带了一样
2.采样率、通道、精度必须相同,有一个参数不同都会影响到合出来的效果
3.做的时候还遇到一个问题,设置采样率、通道、比特率的代码必须放在setOutputFormat后面,如果放在setOutputFormat前面,合出来的音也是有问题的。至于这个为什么, 我暂时也没有找到答案,当时因为这个问题困扰了很久,无意间放到setOutputFormat后面才意外成功
录音结束后,将文件名字添加到List中,来充当ListView的数据
mRecorder.stop();
mRecorder = null;
RecordBean bean = new RecordBean();
bean.setId(count);
bean.setName(count + ".mp4");
bean.setState(0);
bean.setPath(recordFile.getAbsolutePath() + "/record" + count + ".mp4");
list.add(bean);
adapter.setList(list);
接下来,就是选择录音的文件并进行解码,将解码后的文件存在sd卡,合音时,将解码后的文件进行合音。
解码:
/*** 解码* */class DecodeTask extends AsyncTask<Void, Double, Boolean> {private String fileUrl;private int position;DecodeTask(String url, int p) {fileUrl = url;position = p;}@Overrideprotected Boolean doInBackground(Void... params) {try {// 解码后的路径String decodeFilePath = decodeFile.getAbsolutePath()+ "/decode" + MD5Util.getMD5Str(fileUrl);// 将解码后的路径保存在list中,方便后面取值list.get(position).setDecodePath(decodeFilePath);// 解码AudioDecoder audioDec = AudioDecoder.createDefualtDecoder(fileUrl);fileUrl = decodeFilePath;audioDec.decodeToFile(decodeFilePath);return true;} catch (IOException e) {e.printStackTrace();return false;}}@Overrideprotected void onPostExecute(Boolean result) {super.onPostExecute(result);dialog.cancel();}}
合音:
/*** 合音* */class MixTask extends AsyncTask<Void, Double, Boolean> {private int size;MixTask(int num) {size = num;}@Overrideprotected Boolean doInBackground(Void... params) {String rawAudioFile = null;// 将需要合音的音频解码后的文件放到数组里File[] rawAudioFiles = new File[size];StringBuilder sbMix = new StringBuilder();int index = 0;for (int i = 0; i < list.size(); i++) {if (1 == list.get(i).getState()) {rawAudioFiles[index++] = new File(list.get(i).getDecodePath());sbMix.append(i + "");}}// 最终合音的路径final String mixFilePath = mixFile.getAbsolutePath() + "/mix"+ MD5Util.getMD5Str(sbMix.toString());// 下面的都是合音的代码try {MultiAudioMixer audioMixer = MultiAudioMixer.createAudioMixer();audioMixer.setOnAudioMixListener(new OnAudioMixListener() {FileOutputStream fosRawMixAudio = new FileOutputStream(mixFilePath);@Overridepublic void onMixing(byte[] mixBytes) throws IOException {fosRawMixAudio.write(mixBytes);}@Overridepublic void onMixError(int errorCode) {try {if (fosRawMixAudio != null)fosRawMixAudio.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void onMixComplete() {try {if (fosRawMixAudio != null)fosRawMixAudio.close();} catch (IOException e) {e.printStackTrace();}}});audioMixer.mixAudios(rawAudioFiles);rawAudioFile = mixFilePath;} catch (FileNotFoundException e) {e.printStackTrace();}AudioEncoder accEncoder = AudioEncoder.createAccEncoder(rawAudioFile);String finalMixPath = mixFile.getAbsolutePath() + "/finalMix.aac";accEncoder.encodeToFile(finalMixPath);return true;}@Overrideprotected void onPostExecute(Boolean result) {super.onPostExecute(result);Toast.makeText(getApplicationContext(), "合音成功", Toast.LENGTH_SHORT).show();dialog.cancel();}}
最后合成的声音,可以在sdcard/merge/mix/中找到,叫finalMix.aac,可以点击播放试一下
Demo中只是实现该操作,有些东西没有加,如判断sd卡、判断权限是否关闭等,这些实际操作中切勿忘记自行加上
由于所需要的类还是比较多的,这里不能贴上全部代码,有需要的可自行下载Demo:http://download.csdn.net/detail/qq_18612815/9529622
Demo中重要的地方我都加了注释,基本都能看得懂
本篇讲的是音轨合成,接下来的几篇会增加音轨拼接、音轨与视频合成,有需要的加个关注,方便get
刚刚发现了一个bug,Demo中 RecordWithRecordActivity 199行应改为 new MixTask(num).execute();,之前写demo时候测试把num写成2固定死了,所以如果选择超过2个文件就会崩...
转载请注明来自http://blog.csdn.net/qq_18612815