关于多路语音混音的思考与实现
来源:互联网 发布:jquery.jdownload.js 编辑:程序博客网 时间:2024/05/18 21:10
在最近的项目开发中涉及到一个伴奏和类似K歌的功能,最明显的做法就是将播放器里播放的声音扑捉到缓冲区里与麦克风的声音做混合,然后编码发送出去。这里有个关键环节就是混音。因为是音乐类的声音混合,所以要求尽量保真。我看了数字信号处理方面关于波形混合的算法描述,其实就是两个波形值线性相加得到新的波形就可以了。用符号描述:
Si= Bi + Pi; (i = 1 , 2, ,3 ...N, B表示背景音,P表示人声)。
这个原理很简单,但是在PC上,一个语音样本值的范围是-32767 ~ 32767,之间的值。如果背景和人声叠加后,很有可能就会超过这个值,这样只能取最大或者最小值,如此以来合成后的声音发生了改变,这样合成后的声音就有爆音。达不到效果。我后来尝试用:
Si= (Bi + Pi) / 2;
这样可以得到最好的波形,但又引来另外一个问题,整个合成后的声音播放出来声音变小了。为了让波形尽量不变,但又维持尽量大的音量。后来我引入了一个调节参数f模型。具体算法描述如下:
假如人声和背景音同时输入M个语音块,一个语音块的N样本。
1.初始化f = 1.0;
2.将第一个语音块进行线性叠加。得到 S(1, 2, 3, ...N)波形序列,从S序列中找出绝对值最大的样本数S(max).
3.计算本语音块的调节参数 如果S(max) >32767则: f = S(max) / 32767,如果 S(max) <=32767; f用上次语音块的f;
4.将S(1, 2, 3, ...., N)全部乘 f得到新的S样本集合。
5.将f趋近于1.0操作 f = (1 - f) / 32 + f;
6.获取下一个语音块,重复第2步。
以下是基本的算法代码示例:
class HeAudioMixer{....boolmixer(const SrcAudioDataList& data_list, int32_t src_size, int16_t* dst, int32_t& dst_size);....protected:floatf_;int32_t*values_;int32_taudio_size_;//一个固定单元的AUDIO长度};bool HeAudioMixer::mixer(const SrcAudioDataList& data_list, int32_t src_size, int16_t* dst, int32_t& dst_size){if(data_list.size() <= 0 || dst == NULL || src_size > dst_size || src_size == 0 || src_size > audio_size_){return false;}int16_t* dst_pos = dst;int16_t* src_pos = NULL;int32_tmix_value = 0;int32_tmax_sample = 0;register int32_t i = 0;int32_tsample_num = data_list.size();//如果只有一个样本,无需混合,只需要赋值就行了if(sample_num == 1){src_pos = data_list[0];for(i = 0; i < src_size; ++ i){dst_pos[i] = src_pos[i];}f_ = 1.0;}else if(sample_num > 0){for(i = 0; i < src_size; ++ i){ //统计样本mix_value = 0;for(register int32_t v_index = 0; v_index < sample_num; ++ v_index){src_pos = data_list[v_index];if(src_pos != NULL)mix_value += src_pos[i];}values_[i] = mix_value;if(max_sample < abs(mix_value)) //求出一个最大的样本max_sample = abs(mix_value);}if(max_sample * f_ > VOLUMEMAX)f_ = VOLUMEMAX * 1.0 / max_sample;for(i = 0; i < src_size; ++ i)dst_pos[i] = (int16_t)(values_[i] * f_);//让f_接近1.0if(f_ < 1.0)f_ = (1.0 - f_) / 32 + f_; else if(f_ > 1.0)f_ = 1.0;dst_size = src_size;}return true;}综述,以上是两个样本的混合,多个源语音样本其实是一样的计算。通过基本的线上测试,发现这个算法在合成方面可以做到基本不损失用户体验。总体效果还算不错。如果超过5个样本合成,合成后的声音会有吵杂的感觉,需要继续找到新的算法支持。
- 关于多路语音混音的思考与实现
- 关于语音合成的一点思考
- 关于语音报警的实现
- Razor与SPA,关于MVC-View实现的思考
- 关于mongodb索引优化的实现与思考
- 关于 'JavaScript实现' 的思考
- 关于思考的思考
- 关于思考的思考
- 关于java接口与多态、继承的思考
- 关于echo音箱等人工智能(语音交互)产品形态的思考
- 关于java实现插入排序的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 关于Java栈与堆的思考
- 当程序猿娶到一个不懂逻辑的女害纸
- 常用ios方法
- 什么是 F#
- Myeclipse 加载building workspace慢的问题
- javascript 图片转换base64
- 关于多路语音混音的思考与实现
- TI单元测试
- jQuery炫酷翻页图片相册
- Android View 子类/属性详情
- 转债投资笔记
- 关于ssh三大框架中web.xml的总结
- 生成二维码代码
- 年变化趋势、月变化趋势相互转换与对应输入框的转换
- 清洗超纯水设备的报价及清洗周期