服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android实现伴奏录音合成MP3

Android实现伴奏录音合成MP3

2022-09-16 17:06yafyr Android

这篇文章主要为大家详细介绍了Android实现伴奏录音合成MP3,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现伴奏录音合成MP3的具体代码,供大家参考,具体内容如下

基本实现思路如下:

1.利用android自带的录音类(AudioRecord)实现录音.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/**
  * 播放伴奏
  */
 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 {
  @Override
  public 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 exception
    e.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 exception
     e2.printStackTrace();
    }
   }
 
  }
 }

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

主要调用的合成方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***
 * 方法描述:本地方法调用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 mp3
       int i = SimpleLame.convert(mixPCMPath, mixMP3Path, m_in_buf_size);
       Log.i(SingSingleActivity.this.getClass().getName(), "转换" + i + "混音完成");
       saveMp3File(mixMP3Path);
      }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/yafyr/article/details/73718637

延伸 · 阅读

精彩推荐