「音箱」RT-Thread智能音箱音频应用实践( 四 )


混音框架设计
「音箱」RT-Thread智能音箱音频应用实践
本文插图
接下来我将介绍智能音箱设计过程中遇到的另一个重要问题 。 如上图左侧部分 , 音箱服务器推送了一个音频 , 在播放过程中突然需要播放提示音 , 通常我们需要将音频暂停播放 , 插入提示音 , 播放完成后音频恢复播放 。 在这种情况下 , 设备需要维护播放状态的 。 如图中原始音频是44K , 采样率是16K , 中间有采样率切换的过程 。 切换采样率的过程中 , 需要注意它的实时性 , 因为我们控制内部芯片会产生一定时延 。 另一个就是pop音问题 , 当还有音频在播放时 , 切换采样率会有噪音出现 。 对此 , 我们做出了部分改进 , 采用混音的思路:将原音频音量降低 , 再采用混音的方式将提示音混入 , 提示音播放完成后恢复音频音量 。 这种思路不需要考虑播放器播放状态的维护 , 而且两路音频完全独立 , 开发者逻辑代码编写也清晰简单 。
「音箱」RT-Thread智能音箱音频应用实践
本文插图
我们在做这个方案时评估了Linux下的一个成熟算法 。 算法采用了线性重采样算法 。 如上图 , 它的库里有五种模式 , 默认使用最低模式 。 我们使用ARM-CotexM4芯片做了测试 , 发现最多模式会占用百分之八十CPU 。
「音箱」RT-Thread智能音箱音频应用实践
本文插图
libsamplerate算法输入的数据是浮点类型 , 使用此算法先将数据切为单精度浮点数 , 内部使用双精度浮点数做计算采样以确保采样效果 。 如图中48K音频采样耗费了115%CPU , 重采样过程花费三百多秒 。 我们对此做了改进 。 我们对输入参数使用整形定点算法 , 这时占用CPU降到了79% 。 我们又将内部双精度浮点数强制降为单精度后 , CPU占用率降到了49.5% 。 最终 , 我们做成了全整形数 , 这时CPU占用只有3.8% 。 另外 , 由于重采样算法由C语言写成 , 我们从汇编层面对它做了优化 , 之前的操作造成了采样效果变差 , 通过汇编优化将32位整型数改为了64位 , 整体效果虽不及浮点数 , 但整体效果提升了很多 。
「音箱」RT-Thread智能音箱音频应用实践
本文插图
市面上主流混音算法模型有几种 , 第一种是两个声道数据直接加和 , 当某一通道的数据幅度较大时混音后任意出现音频数据溢出 , 从而音频失真 。 第二种是加和后再除以音道数防止溢出 , 这样会造成音道内音量衰减 , 并且音轨越多衰减越多 。 还有一种是加和箝位 , 即相加超过最大值时进行限幅 , 这样音频也会失真 。 另外还有饱和处理、归一化处理等 。 考虑到RTOS 方案应用场景是一个音轨音量高一个音量稍低 , 我们并需要两个声音同时听清 , 我们只需要保证一个音轨的质量 。 最终我们选择了图中第二种算法 。 虽然会产生一些衰减 , 但是在这个场景下只保证两个音道中一个声音清晰 , 衰减是可以忽略的 。 但是其它算法可能会出现失真 , 这是不能接受的 。 这种方案在实际应用中效果很好的 。
「音箱」RT-Thread智能音箱音频应用实践
本文插图
上图是我们测试结果 。 图中是一帧数据、20毫秒的窗口 , 我们做了重采样混音算法 。 优化过后 , 主音轨重采样耗了大概1.288毫秒 , 副音轨耗了1.296毫秒 , 混音用时1.281毫秒 , 在ARM9 120MHZ的系统中耗费了大概20%的CPU消耗 。


推荐阅读