NetEq 时间伸缩 · 变速不变调

NetEq 靠加速/减速播放来微调缓冲,但快进磁带会变尖、慢放会变低沉——怎么变速却不变调?靠 WSOLA:找相似波形、去掉或插入一个基音周期、交叉叠加。这一章讲清这个让 NetEq 悄悄调节延迟的核心技术。

作者 David更新于 第 70 篇(共 112 篇)

NetEq 时间伸缩 · 变速不变调

NetEq 靠加速 / 减速播放微调缓冲:缓冲多了加速追回、少了减速攒回。但有个难题:普通的变速会变调——快进像磁带倒带尖细,慢放像喝醉了低沉。NetEq 必须变速却不变调,才能让人察觉不到。这一章讲这个精妙的技术。

难题:变速为什么会变调

先理解为什么天真的变速会变调:

声音的“音调”由波形的频率决定。如果你简单地把音频“快放”(每秒播更多样本),波形的频率就整体升高——音调变尖(花栗鼠效应);“慢放”则频率降低,音调变闷。 这是因为“播放速度”和“频率”被绑在了一起:快放 = 波形被横向压缩 = 频率升高 = 音调变高。所以不能简单地“少播点样本来加速”——那会毁掉音色,一听就假。

NetEq 要的是:把一段音频的时长改变(变短 = 加速 / 变长 = 减速),但保持音调不变——就像你正常语速说话和略快说话,音调是一样的,只是时长不同。这在信号处理里叫时间伸缩(time-stretching),是个经典难题。

解法:WSOLA,按基音周期增删

NetEq 用的技术是 WSOLA(Waveform Similarity Overlap-Add,波形相似交叠相加),思路巧妙:

要给语音“加速”(缩短),就找到一个基音周期、把它去掉一个**;要“减速”(拉长),就插入一个——因为语音是准周期的,去掉 / 插入一整个基音周期,音调(周期本身)不变,只是时长变了。** 关键在“去掉 / 插入的接缝处怎么不咔哒”:WSOLA 用波形相似性找到最匹配的拼接点(让接缝两侧的波形尽量吻合),再用交叉叠加(overlap-add) 平滑过渡——和 Merge 的交叉淡化异曲同工。

举例:一段 30ms 的音频,基音周期是 5ms(200Hz 的低音)。要加速,就找一个位置去掉一个 5ms 周期,变成 25ms——播放时长短了、但每个周期还是 5ms,所以音调没变,只是这段话说得略快了。人耳对“略快 / 略慢”的语速极不敏感(尤其只调几毫秒),于是 NetEq 能神不知鬼不觉地每次微调几毫秒,把缓冲量慢慢拉回目标。变速不变调,是 NetEq 能“悄悄调节延迟”的技术基石。

为什么这如此重要

WSOLA 时间伸缩,是 NetEq 自适应缓冲的执行手段,它的意义比看起来大:

正因为能“无感地变速”,NetEq 才能把延迟控制做得如此丝滑——它不必“要么多缓冲、要么断音”地生硬取舍,而能持续地、微量地伸缩播放,让缓冲量始终平滑地贴着目标。 对比视频抖动缓冲:视频只能“整帧地”增减缓冲(要么多等一帧、要么丢一帧),粒度粗;而音频靠 WSOLA 能以毫秒级、连续地调节,粒度细得多。这就是为什么音频的延迟自适应比视频平滑得多——你几乎从不会感觉到音频在“调整缓冲”,但它一直在。

代价是 CPU:WSOLA 要做波形相似性搜索,有计算量。但音频数据量小,这点开销值得——换来的是流畅、低延迟、无感的音频体验。当你视频通话时觉得“声音一直很顺”,背后正是 NetEq 在用 WSOLA 持续地、悄悄地伸缩着每一小段音频。

小结与第 7 部分 NetEq 回顾

时间伸缩让 NetEq 变速不变调:天真变速会变调(快尖慢闷),NetEq 用 WSOLA——按基音周期去掉一个(加速)/ 插入一个(减速),音调不变、只改时长,接缝用波形相似 + 交叉叠加磨平。这让 NetEq 能无感、连续、毫秒级地微调缓冲,比视频抖动缓冲平滑得多。

NetEq 至此讲透:总览→缓冲与延迟→六种操作→丢包隐藏→时间伸缩。它把抖动缓冲、丢包隐藏、时间伸缩融为一体,是实时音频接收侧的杰作。

接收侧讲完,转到发送侧的另一座高峰——音频处理 APM,尤其是回声消除。下一章总览 APM。👉 APM 音频处理总览。

参考资料

  • [1] libwebrtc 源码.modules/audio_coding/neteq/accelerate.cc、preemptive_expand.cc、time_stretch.cc。
  • [2] WSOLA 算法 —— Waveform Similarity Overlap-Add 时间伸缩。
  • [3] 关联NetEq 缓冲与延迟——时间伸缩的目的。

本页目录