We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
音视频倍速 是内容类APP非常重要的功能,其内部包含了 视频流 和 音频流 的倍速,其中视频倍速原理相对简单,即在解码视频帧时提升帧率即可。
APP
音频倍速 相对复杂,众所周知,声音的本质其实是 物体振动时产生的声波,因此音频的倍速是 将语音信号在时域上拉长或缩短,考虑到用户的体验,在保证声音变速的同时,语音的采样率、基频以及共振峰都不能发生变化,以此达到 变速不变调 的目的。
对于 Android 平台的应用而言,音频倍速通常有3种实现方式:
Android
对于原生的 AudioTrack 而言,其本身提供了处理PCM音频流的功能,但由于其默认被系统的 MediaPlayer 绑定,而后者本身在不同平台上的兼容性就不佳,因此很少被使用。
AudioTrack
PCM
MediaPlayer
Sonic 库则被 Google 大名鼎鼎的开源播放器 ExoPlayer 所使用,其内部基于 时域压扩算法 (Time-scale modificatio,下简称TSM算法), 通过定位 基音周期 的方式,对输入的语音信号进行不断的分帧与合帧的处理,最终合成新的信号以达到倍速的效果。
Sonic
Google
ExoPlayer
Time-scale modificatio,下简称TSM算法
SoundTouch 则被 Bilibili 开源的 ijkPlayer 所内置,内部仍然基于TSM算法,和Sonic不同的是使用了 寻找相关峰 进行语音信号的合成。
SoundTouch
Bilibili
ijkPlayer
TSM
不可否认,信号的合成必然会造成原始音频的失真,区别在于Sonic是基于 基音周期 的,因此变速后的语音信号对人声音影响较小;而 SoundTouch 倍速效果更适用于综合性的场景。
但在实际应用中,问题却不断涌现:
要搞明白这些疑惑,就需要从原理和具体的算法实现进行分析。
音频倍速的实现思路分为针对 时域 信号或者 频域 信号分析,但由于频域的复杂度过高,因此实践中通常从时域信号着手。
时域压扩(TSM) 也正是基于时域信号的处理中的典型算法,其提供了 变速不变调 的音频处理实现。
音频信号的处理过程中,不可避免的要进行 分帧 (analysis fames)操作,帧的长度大多选取是 20ms 到 50ms 之间,并进行加窗操作,而由于加窗操作本身会对一帧信号的两端进行抑制,因此分帧不能按长度分段截取,而是相互重叠一部分(overlap),之后再进行 合帧 (synthesis frames)。如果分帧以 50% 的 overlap,而合帧(synthesis frames)时以 75%,那么就实现了慢放,反过来则是快放。
analysis fames
20ms
50ms
overlap
synthesis frames
50%
75%
一言蔽之,对每个帧进行一系列处理比如拉伸或者压缩,最后在将这些帧重新叠加成合成信号实现倍速:
OLA(Overlap-and-Add, OLA) 重叠相加算法是音频变速算法中最简单的时域算法,它是后续时域算法(SOLA, SOLA-FS, TD-PSOLA, WSOLA)的基础。
OLA(Overlap-and-Add, OLA)
(SOLA, SOLA-FS, TD-PSOLA, WSOLA)
首先,音频信号分帧处理后,暴力的将处理后的信号首位拼接起来,思路非常简单,但劣势显而易见,它会造成拼接后信号的不连续,相邻帧重叠区域产生基频失真:
为了减轻这种波形不连续的影响,我们对信号进行了分帧加窗处理,OLA中通常使用汉宁窗对帧进行加窗叠加(如下图 b ):
b
加窗的处理保证了信号两端被抑制,保证后续的傅里叶变换,减轻频谱泄漏;这之后,通过固定间隔 Ha 取到下一个帧(如上图 c ),加窗后与前一帧叠加(如上图 d ),以缓解波形不连续(基音断裂)问题。
Ha
c
d
即便如此,在帧裁剪的过程中,仍然无法保证每一个帧都能覆盖完整周期并保证其相位对齐,这种失真也叫相位跳跃失真(phase jump artifacts),对于音频的听感仍然不佳:
phase jump artifacts
如图,两个周期信号帧通过 OLA 合成后变得 “不周期” 了。
OLA
如何解决这样的问题,WSOLA (Waveform similarity Overlap-Add, 波形相似叠加) 算法提出这样一种思路,通过寻找当前帧下一个最相似的信号帧,并对两帧进行叠加,这样合成后的语音便会非常自然:
WSOLA
上图很清晰表述了该算法的核心思想:
1.在原音频中截取一个帧,加窗; 2.在一个范围内(蓝色虚线框)选取第二个帧,这个帧的相位参数应该和第一个帧相位对齐; 3.在另一个范围内(蓝色实线框)中查找第三个帧,这个帧和第二个帧应该最相似; 4.最后把它们叠加在一块。
问题很自然转换成为了 “ 如何找到最相似的帧 ”,在Android中,对于音频 变速不变调 处理的问题,SoundTouch使用 寻找相关峰 的算法来实现,而Sonic则使用的是另外一种 AMDF 的基音提取算法。
AMDF
对于 寻找相关峰 ,顾名思义,当第一帧数据到达时,会将数据依次传入Buffer,并在固定长度之后的位置开始,寻找与第一帧信号相关性最大的位置,并对两帧信号进行合成;
Buffer
对于 Sonic 中使用的是 AMDF (平均幅度差函数法)方法,该方法极其简单,在一定范围内,分别计算每个帧与起始帧的 AMDF 值,幅度差最小的帧与第一帧的距离便是基音周期,寻找到基因周期后,根据基音周期进行变速变调。
文章最初有提到,使用 ExoPlayer 播放音乐时, Sonic的倍速效果失真明显,和 ijkPlayer 对应的 SoundTouch 倍速效果有 明显差距。
这似乎有违常理,既然 Sonic 是基于定位基音周期的算法实现,那么对于人声这种周期性强的音频信号而言,倍速效果应该更好才对。
经过对比与思考,我们做出以下推测,诚然,对于纯粹的人声,Sonic 的倍速效果较佳,但对于绝大多数音乐,听众对于声音节奏的听感更多是由背景乐所提供的,而背景乐通常是由多种乐器组合演奏,Sonic对这种包含较多谐波冲击和瞬态分量的音频信号处理起来则更棘手。
因此,在具体的音频倍速实现中,不妨对具体的业务场景进行不同的决断,对于常规音乐——尤其是背景乐、打击感比较强的音乐,我们可以选择SoundTouch, 而对于人声更纯粹的音频类型(比如相声、评书、歌手清唱)而言,Sonic也是不错的选择。
本文部分文案节选自下述资料,有兴趣的读者可以进行针对性深入了解。
A Review of Time-Scale Modification of Music Signals @ Jonathan Driedger @ Meinard Müller
TSM时域压扩(变速不变调)算法总结 @DBinary
音频变速变调原理及 soundtouch 代码分析 @floer rivor
音频变速变调 -sonic 源码分析 @floer rivor
google-ExoPlayer @GitHub
bilibili-ijkplayer @GitHub
bilibili-soundtouch @GitHub
waywardgeek-sonic @GitHub
Hello,我是 却把清梅嗅 ,如果您觉得文章对您有价值,欢迎 ❤️,也欢迎关注我的 博客 或者 GitHub。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
概述
音视频倍速 是内容类
APP
非常重要的功能,其内部包含了 视频流 和 音频流 的倍速,其中视频倍速原理相对简单,即在解码视频帧时提升帧率即可。音频倍速 相对复杂,众所周知,声音的本质其实是 物体振动时产生的声波,因此音频的倍速是 将语音信号在时域上拉长或缩短,考虑到用户的体验,在保证声音变速的同时,语音的采样率、基频以及共振峰都不能发生变化,以此达到 变速不变调 的目的。
对于
Android
平台的应用而言,音频倍速通常有3种实现方式:对于原生的
AudioTrack
而言,其本身提供了处理PCM
音频流的功能,但由于其默认被系统的MediaPlayer
绑定,而后者本身在不同平台上的兼容性就不佳,因此很少被使用。Sonic
库则被Google
大名鼎鼎的开源播放器ExoPlayer
所使用,其内部基于 时域压扩算法 (Time-scale modificatio,下简称TSM算法
), 通过定位 基音周期 的方式,对输入的语音信号进行不断的分帧与合帧的处理,最终合成新的信号以达到倍速的效果。SoundTouch
则被Bilibili
开源的ijkPlayer
所内置,内部仍然基于TSM
算法,和Sonic
不同的是使用了 寻找相关峰 进行语音信号的合成。不可否认,信号的合成必然会造成原始音频的失真,区别在于
Sonic
是基于 基音周期 的,因此变速后的语音信号对人声音影响较小;而SoundTouch
倍速效果更适用于综合性的场景。但在实际应用中,问题却不断涌现:
Sonic
效果应该更好,但实际中,Sonic
在高倍速下听感失真明显,和SoundTouch
的效果有显著差距,导致该现象的原因是什么?要搞明白这些疑惑,就需要从原理和具体的算法实现进行分析。
音频倍速原理
1、TSM基本原理
音频倍速的实现思路分为针对 时域 信号或者 频域 信号分析,但由于频域的复杂度过高,因此实践中通常从时域信号着手。
时域压扩(TSM) 也正是基于时域信号的处理中的典型算法,其提供了 变速不变调 的音频处理实现。
音频信号的处理过程中,不可避免的要进行 分帧 (
analysis fames
)操作,帧的长度大多选取是20ms
到50ms
之间,并进行加窗操作,而由于加窗操作本身会对一帧信号的两端进行抑制,因此分帧不能按长度分段截取,而是相互重叠一部分(overlap
),之后再进行 合帧 (synthesis frames
)。如果分帧以50%
的overlap
,而合帧(synthesis frames
)时以75%
,那么就实现了慢放,反过来则是快放。一言蔽之,对每个帧进行一系列处理比如拉伸或者压缩,最后在将这些帧重新叠加成合成信号实现倍速:
2、暴力的OLA
OLA(Overlap-and-Add, OLA)
重叠相加算法是音频变速算法中最简单的时域算法,它是后续时域算法(SOLA, SOLA-FS, TD-PSOLA, WSOLA)
的基础。首先,音频信号分帧处理后,暴力的将处理后的信号首位拼接起来,思路非常简单,但劣势显而易见,它会造成拼接后信号的不连续,相邻帧重叠区域产生基频失真:
为了减轻这种波形不连续的影响,我们对信号进行了分帧加窗处理,OLA中通常使用汉宁窗对帧进行加窗叠加(如下图
b
):加窗的处理保证了信号两端被抑制,保证后续的傅里叶变换,减轻频谱泄漏;这之后,通过固定间隔
Ha
取到下一个帧(如上图c
),加窗后与前一帧叠加(如上图d
),以缓解波形不连续(基音断裂)问题。即便如此,在帧裁剪的过程中,仍然无法保证每一个帧都能覆盖完整周期并保证其相位对齐,这种失真也叫相位跳跃失真(
phase jump artifacts
),对于音频的听感仍然不佳:3.波形相似叠加(WSOLA)
如何解决这样的问题,
WSOLA
(Waveform similarity Overlap-Add, 波形相似叠加) 算法提出这样一种思路,通过寻找当前帧下一个最相似的信号帧,并对两帧进行叠加,这样合成后的语音便会非常自然:上图很清晰表述了该算法的核心思想:
问题很自然转换成为了 “ 如何找到最相似的帧 ”,在
Android
中,对于音频 变速不变调 处理的问题,SoundTouch
使用 寻找相关峰 的算法来实现,而Sonic
则使用的是另外一种AMDF
的基音提取算法。对于 寻找相关峰 ,顾名思义,当第一帧数据到达时,会将数据依次传入
Buffer
,并在固定长度之后的位置开始,寻找与第一帧信号相关性最大的位置,并对两帧信号进行合成;对于
Sonic
中使用的是AMDF
(平均幅度差函数法)方法,该方法极其简单,在一定范围内,分别计算每个帧与起始帧的AMDF
值,幅度差最小的帧与第一帧的距离便是基音周期,寻找到基因周期后,根据基音周期进行变速变调。阶段性小结
文章最初有提到,使用
ExoPlayer
播放音乐时,Sonic
的倍速效果失真明显,和ijkPlayer
对应的SoundTouch
倍速效果有 明显差距。这似乎有违常理,既然
Sonic
是基于定位基音周期的算法实现,那么对于人声这种周期性强的音频信号而言,倍速效果应该更好才对。经过对比与思考,我们做出以下推测,诚然,对于纯粹的人声,
Sonic
的倍速效果较佳,但对于绝大多数音乐,听众对于声音节奏的听感更多是由背景乐所提供的,而背景乐通常是由多种乐器组合演奏,Sonic
对这种包含较多谐波冲击和瞬态分量的音频信号处理起来则更棘手。因此,在具体的音频倍速实现中,不妨对具体的业务场景进行不同的决断,对于常规音乐——尤其是背景乐、打击感比较强的音乐,我们可以选择
SoundTouch
, 而对于人声更纯粹的音频类型(比如相声、评书、歌手清唱)而言,Sonic
也是不错的选择。参考资料
本文部分文案节选自下述资料,有兴趣的读者可以进行针对性深入了解。
A Review of Time-Scale Modification of Music Signals @ Jonathan Driedger @ Meinard Müller
TSM时域压扩(变速不变调)算法总结 @DBinary
音频变速变调原理及 soundtouch 代码分析 @floer rivor
音频变速变调 -sonic 源码分析 @floer rivor
google-ExoPlayer @GitHub
bilibili-ijkplayer @GitHub
bilibili-soundtouch @GitHub
waywardgeek-sonic @GitHub
关于我
Hello,我是 却把清梅嗅 ,如果您觉得文章对您有价值,欢迎 ❤️,也欢迎关注我的 博客 或者 GitHub。
The text was updated successfully, but these errors were encountered: