基本实现思路如下:
1.利用android自带的录音类(AudioRecord)实现录音.

 /*** 播放伴奏*/private MediaPlayer player;/*** 返回按钮*/private ImageView btnBack;/*** 切换歌曲*/private Button btnSwitchSong;/*** 伴唱时长*/private TextView tv_recod_time;/*** 歌词VIEW*/private LyricView lv_lyric;/*** 开始录制*/private Button btnPlay;/*** 标题*/private TextView ivTitle;private boolean canPlay = true;private boolean isPause = false;/**** 背景音乐模式*/private BackgroudMusicMode mode = BackgroudMusicMode.Accompany;/*** 歌曲id*/private String songId;/*** 歌曲名称*/private String songName;/*** 歌手名字*/private String singerName;/*** 伴奏文件*/private File file;/*** 是否正在录制*/private boolean isStart = false;/*** 录音状态*/private boolean starting = false;/*** 伴奏时间*/private int bztimetmp = 0;/*** 伴奏时间*/private String bztime = "";/*** 录制时间*/private int recordTimeLength=0;/*** 更新伴奏时间*/private RecordTask rt = null;/*** 录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备* 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025*/private int sampleRateInHz = 44100;/*** 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道*/private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;/*** 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。*/private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;/*** 调整播放音量*/private AudioManager audioManager;/*** 最大音量*/private int maxVolume = 0;/*** 当前音量*/private int currentVolume = 0;/*** AudioRecord 写入缓冲区大小*/protected int m_in_buf_size;/*** 录制音频对象*/private AudioRecord mRecorder;/*** 录入的字节数组*/private byte[] m_in_bytes;/*** 存放录入字节数组的大小*/private LinkedList<byte[]> m_in_q;/*** AudioTrack 播放缓冲大小*/private int m_out_buf_size;/*** 播放音频对象*/private AudioTrack mAudioTrack;/*** 播放的字节数组*/private byte[] m_out_bytes;/*** 录制音频线程*/private Thread record;/*** 播放音频线程*/private Thread play;/*** 让线程停止的标志*/private boolean flag = true;/*** 是否启动回声*/private boolean room_flag = true;/***上面有个播放歌词的组件/**** 初始化*/private void init() {audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);registerHeadsetPlugReceiver();ycApplication = (YueChangApplication) getApplication();coverDao = new CoverDao(getApplicationContext());Bundle bundle = getIntent().getExtras();songId = bundle.getString("songId");songName = bundle.getString("songName");singerName = bundle.getString("singerName");if (songId != null) {// AudioRecord 得到录制最小缓冲区的大小m_in_buf_size = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);// 实例化播放音频对象mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat,m_in_buf_size);// 实例化一个字节数组,长度为最小缓冲区的长度m_in_bytes = new byte[m_in_buf_size];// 实例化一个链表,用来存放字节组数m_in_q = new LinkedList<byte[]>();// AudioTrack 得到播放最小缓冲区的大小m_out_buf_size = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);// 实例化播放音频对象mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat,m_out_buf_size, AudioTrack.MODE_STREAM);// 实例化一个长度为播放最小缓冲大小的字节数组m_out_bytes = new byte[m_out_buf_size];record = new Thread(new recordSound());//            if(ycApplication.isHeadsetplug()){//            }else{
//                m_out_trk = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat,
//                        m_out_buf_size, AudioTrack.MODE_STREAM);
//            }}}/**** 类描述:录音线程 ** @version 1.0*/class recordSound implements Runnable {@Overridepublic void run() {// 初始化输出流DataOutputStream dos = null;try {File audioFile = new File(SongUtil.getRecordSingPCMPath(songId));// 初始化输出流dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));byte[] bytes_pkg;if (mRecorder.getState() == AudioRecord.STATE_UNINITIALIZED) {// 实例化播放音频对象mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig,audioFormat, m_in_buf_size);}// 开始录音mRecorder.startRecording();while (flag) {int size = mRecorder.read(m_in_bytes, 0, m_in_buf_size);bytes_pkg = m_in_bytes.clone();if (m_in_q.size() >= 2) {m_in_q.removeFirst();}m_in_q.add(bytes_pkg);if ((ycApplication.isHeadsetplug() && ycApplication.isOpenInEarphone())|| (!ycApplication.isHeadsetplug() && ycApplication.isOpenInSpeaker())) {//Log.d(SingSingleActivity.this.getClass().getName(), "启动录音播放1");if (play == null||!room_flag) {//Log.d(SingSingleActivity.this.getClass().getName(), "启动录音播放2");room_flag = true;play = new Thread(new playRecord());// 启动播放线程play.start();}} else {if(room_flag||play != null){//Log.d(SingSingleActivity.this.getClass().getName(), "关闭录音播放1");room_flag = false;if (play != null) {play.interrupt();}play = null;}}// 写入PCM文件dos.write(bytes_pkg, 0, size);dos.flush();}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} finally {try {// 关闭录音if (mRecorder != null) {try {if (mRecorder.getState() == AudioRecord.STATE_INITIALIZED) {// 关闭录音mRecorder.stop();mRecorder.release();}} catch (Exception e2) {// TODO: handle exception}}if (dos != null) {dos.close();}} catch (Exception e2) {// TODO: handle exceptione2.printStackTrace();}}}}

2.录音完成后,调用开源工具(Mad)实现PCM合成输出到MP3文件.
主要调用的合成方法:

 /**** 方法描述:本地方法调用JNI合并mp3PCM与sourcePCM* @param sourcePCM* @param mp3PCM* @param mixPCM* @return*/public static native int mix2PCMToPCM(String sourcePCM, String mp3PCM, String mixPCM);String recordPCMPath = SongUtil.getRecordSingPCMPath(songId); //录音生成的PCM文件String accompanyPCMPath = SongUtil.getAccompanySongPCMPath(songId); //伴奏解码生成的PCM文件String mixPCMPath = SongUtil.getMixSingPCMPath(songId); //合成后的PCM文件String mixMP3Path = SongUtil.getMixSingMp3Path(songId); //合成后的MP3文件// 混音int code = SongEncodeUtil.mix2PCMToPCM(recordPCMPath, accompanyPCMPath, mixPCMPath);if (code == 0) {// 转换混合后音频格式 TO mp3int i = SimpleLame.convert(mixPCMPath, mixMP3Path, m_in_buf_size);Log.i(SingSingleActivity.this.getClass().getName(), "转换" + i + "混音完成");saveMp3File(mixMP3Path);}

完整代码下载

浅谈Android实现伴奏录音合成MP3相关推荐

  1. Android 高仿唱吧 咔拉ok 商业项目开源代码 K歌合成 伴奏录音合成MP3(音频五)

    Android MediaRecorder录音录像 暂停 继续录音 播放 ARM格式(音频一) https://blog.csdn.net/WHB20081815/article/details/88 ...

  2. 浅谈Android引用计数(2)

    在浅谈Android引用计数(1)中讲了LightRefBase实现对象计数管理的原理,这篇文章将要分析重量级的引用基类:RefBase的实现和它的作用. 下面是RefBase和相关类的类图: 图中可 ...

  3. 浅谈Android保护技术__代码混淆

    浅谈Android保护技术__代码混淆 浅谈Android保护技术__代码混淆 代码混淆 代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读 ...

  4. android fps 垂直同步,浅谈Android流畅度

    原标题:浅谈Android流畅度 哈哈 讲个故事 白 1 流畅度 关于流畅度谷歌官方给出的解释为:running at a consistent 60 frames per second, witho ...

  5. 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

    原文地址: http://blog.csdn.net/luoshengyang/article/details/6627260 在前面一篇文章浅谈Service Manager成为Android进程间 ...

  6. android分屏模式_浅谈 Android 7.0 多窗口分屏模式的实现

    从 Android 7.0 开始,Google 推出了一个名为"多窗口模式"的新功能,也就是我们常说的"分屏模式".那么,这个功能有什么用呢?作为开发者,我们又 ...

  7. 浅谈Android onTouchEvent 与 onInterceptTouchEvent的区别详解

    浅谈Android onTouchEvent 与 onInterceptTouchEvent的区别详解 本篇文章小编为大家介绍,Android onTouchEvent 与 onInterceptTo ...

  8. android 存储空间监控,浅谈 Android 内存监控(中)

    前言 在上篇 浅谈 Android 内存监控(上) 中,我们聊了 LeakCanary,微信的 Matirx 和美团的 Probe,它们各自有不同的应用场景,例如,在开发测试环境,我们会偏向用 Lea ...

  9. 《浅谈-Android系统越用反应越慢的问题》

    <浅谈-Android系统越用反应越慢的问题> android应用程序和iphone应用程序不一样,用过iphone的都知道,点击图标进入程序后,如果还想用其他程序,必须先按返回退出然后进 ...

最新文章

  1. 这款库克寄予厚望的苹果产品,只活了2年
  2. HTML, CSS, Javascript, jQuery之间的关系
  3. linux ssh关闭后台程序不终止
  4. 设计模式在C语言中的应用--读nginx源码
  5. 如何将四元数方向转化为旋转举证_旋转表示法(持续更新)
  6. Nginx使用webbench进行压力测试
  7. 算法训练营01-学习总览
  8. Rational Rose 2003 下载、破解及安装方法(图文)
  9. 论文浅尝 - ACL2020 | 用于回答知识库中的多跳复杂问题的查询图生成方法
  10. 一秒执行一次_《一秒钟》:一贯的粗旷式抓大放小,张艺谋的自命题作业总是要观众自己再做一遍...
  11. [Codeforces1132G]Greedy Subsequences——线段树+单调栈
  12. 控制台怎么查看错误的详细信息_js错误处理,quot;try..catchquot;
  13. Ref和Out关键字的区别
  14. 神秘黑客攻陷密码管理器 Passwordstate 部署恶意软件,发动软件供应链攻击
  15. 数电课设—四位数字电子钟设计
  16. 【GIT】搭建git项目
  17. 微信公众号开发--实现扫码关注公众号自动登录网站
  18. 禁用ubuntu16.04的guest账户
  19. 关于反走样技术的基本介绍与分享
  20. jQuery Media Plugin 插件实现在线视频播放业务

热门文章

  1. 联想电脑主页被篡改为https://www.baidu.com/?tn=02003390_62_hao_pg 解决
  2. 安卓逆向笔记(课外资料)
  3. 基于java的学生选课成绩信息系统
  4. 【Android,gradle】A problem occurred evaluating project ‘:app‘.
  5. STL浅谈(2)——链表+相应迭代器实现
  6. Luogu P1462 通往奥格瑞玛的道路(最短路+二分)
  7. 易语言内存逆向教程(PC电脑端方向最新)+送图色基础+多线程中控(类人猿)
  8. CocoaPods安装方法2022年最新版
  9. cnpm yarn 安装
  10. 【面试需要】掌握JavaScript中的this,call,apply的原理