音频处理之语音加速播放

本文系做者原创。如转载,请注明出处。 谢谢!算法

在作语音类APP时,语音留言(以码流形式)会被保存下来。当听时想快点听完,因而就有了语音加速播放功能。同时还有个需求,能实时切换播放速率,即当1.5倍
速播放时切两倍速,就要马上两倍速播放。函数

首先作了一番调研,看几倍速后就基本上听不清说什么了。找来了一款能在PC上运行的有加速播放功能的软件,试验下来两倍速以上就基本上听不清说什么了。因而除
了正常速率外,只有两个速率可调:1.5倍速和两倍速。同时搜了一下变速相关的开源算法(算法原理请看其余相关文章),发现主打变声功能的sound touch使用率较高。它能够改变音调(pitch)和语速(rate)等,好多软件拿它作一些趣味音频。基于sound touch作了一个应用程序看加速效果,同时要兼顾男声和女声。试验下来发现语速加快了后音调就变了,也就是还要同时调音调。改了音调作了一番调试后只能接近原声,能兼顾男女声。再试试在PC上运行的软件,加速后也是只能接近原声。作了这些后就决定用sound touch来作了,在不一样的速率下音调(pitch)和语速(rate)参数值也肯定了下来(男女声在一个速率下用一组参数值)。线程

再看咱们的相关代码,系统支持ILBC和OPUS两种codec,ILBC每帧30ms, OPUS每帧20ms, 播放线程每20ms运行一次,即每次取20ms PCM数据播放。要想播放语音留言,首先要解码码流成PCM 数据放在buffer1中,再看是否要加速播放,要加速的话就把buffer1中的语音数据调加速函数处理后放在buffer2中,不加速就把buffer1中的语音数据直接拷进buffer2中,等待buffer2中的数据被取走播放。根据这些通过一番尝试后用了分段循环处理的实现方法。一个循环内取固定时间长度的原始音频帧,取出的这段音频帧无论是否加速在这个循环内都要正好播放完,同时兼顾ILBC和OPUS两种不一样的帧长和1.5倍速两倍速两种不一样的速率。ILBC时,每帧30ms,每次取20ms播放,有1.5倍速两倍速两种速率,最小的原始PCM数据长度(即最小固定长度)是120ms(原始ILBC帧数是4帧,1.5倍速后是80ms,4次可取完播放,2倍速后是60ms,3次可取完播放)。OPUS时,每帧20ms,每次取20ms播放,有1.5倍速两倍速两种速率,最小的原始PCM数据长度也是120ms(原始OPUS帧数是6帧,1.5倍速后是80ms,4次可取完播放,2倍速后是60ms,3次可取完播放)。因此一个循环内取的最小原始音频的固定长度是120ms. 一个循环结束后正好播放完,清空buffer2,而后取下一段原始音频帧解码加速后播放。为了在循环内播放时声音不断断续续,buffer2里要有足够的数据供取走播放。这样在每一个循环刚开始的时候,要尽量多的解码帧数加速后放在buffer2中等取走播放。至于几回解码完所需的码流帧数,这要根据cpu来定。通常一个循环的前一两次就把码流解码加速作完了,后面的次数里只须要从加速后的buffer2里取数据播放就能够了。这样循环内每次播放线程运行时都能取到数据播放,下一循环开始时也能取到数据播放,不存在断断续续的状况。调试

当要求实时切换语速时,要把这120ms原始语音数据播放完在下一个循环里才能改变语速。因为120ms很短,用户基本无感知,能够认为是实时的,不影响用户体验。
当到语音结尾时,有多少帧就解码加速多少帧供播放,当从加速后的buffer里不能取到20ms数据就可认为播放结束了。这时用零补足20ms数据,把这些数据播放出去,从而结束播放。code

跟上层的UI联调后效果不错。这样APP内的语音加速方案就搞定了。it

相关文章
相关标签/搜索