☰
Kumone AutoMix系列二:纯vDSP节拍跟踪——BPM估计与Downbeat追踪的原理与实现
2026/10/15 18:55:06 网站建设 项目流程

【免费下载链接】kumone

雲の音 — Native macOS NetEase Cloud Music client built with SwiftUI

项目地址:https://gitcode.com/gh_mirrors/ku/kumone
点击查看免费下载

Kumone(雲の音)是一款原生 macOS 网易云音乐客户端,其AutoMix 自动混音功能要实现 DJ 级别的无缝对拍过渡,前提是先把每首歌的节拍算准。本文带你拆解它如何用纯 vDSP 节拍跟踪完成BPM 估计与Downbeat 追踪:零第三方依赖,一首 4 分钟的歌只需 1–2 秒,BPM 误差 ±2 以内,拍点相位误差中位数小于 70ms。

一、为什么节拍分析是 AutoMix 的地基

AutoMix 的过渡分三档:两首歌 BPM 相近且节拍可信时做beatMatched 变速对拍混音;不适合时退化为普通交叉淡出;再不行就无缝硬切(gapless)。第一档能否启用,完全取决于分析器给出的两个数字:

  • bpm+bpmConfidence(置信度 0–1,阈值 0.6)
  • downbeats(小节起点的时刻列表)

门控逻辑写在 TransitionPlanner.swift 里:双方置信度 ≥ 0.6、折算 BPM 差 ≤ 8%,才允许对拍。切点落在副歌半句上,再华丽的混音技法也救不回来——节拍网格错一拍,所有候选切点全错一拍。

二、整体流水线:单趟 STFT 喂饱全部特征

分析入口在 TrackAnalyzer.swift,文件头部的注释就开宗明义:Beat/energy analysis, pure vDSP/Accelerate. No third-party code.。选纯自研不是炫技——常见的 aubio、BTrack 都是 GPL 协议,与本项目 LGPL-3.0-only 不兼容(见 automix-spec.md §1)。

流水线一句话概括:

解码为 22.05 kHz 单声道 → STFT(窗 1024 / hop 256,Hann 窗)→ 40 维 log-mel 谱 →spectral flux onset 包络→ 自相关 + 先验估BPM→ 动态规划逐拍跟踪 → 低频投票定Downbeat

注意"单趟":BPM、拍点、调性、人声活跃度、结构分段(见 StructureSegmenter.swift)全部复用同一份 STFT 特征,不重复扫音频。

三、BPM 估计:自相关 + 对数正态先验

代码见estimateTempo(约 TrackAnalyzer.swift#L780-L839),四步走:

  1. Onset 包络:对 log-mel 谱做半波整流一阶差分再跨频带求和——"谱里突然多出来的能量",鼓点、拍手、和弦进入都会在这里冒尖。
  2. 归一化自相关:对去均值的 onset 包络求r(lag)/r(0),lag 范围对应 50–200 BPM。
  3. 对数正态先验加权:以 120 BPM 为中心(σ=0.9 个八度)的高斯先验乘到自相关曲线上,天然压制 60/180 BPM 这类"半拍/双拍"幻影峰。
  4. 抛物线插值 + 置信度:峰顶做亚采样点插值拿到小数 lag;置信度 = 峰值锐度(峰 vs 邻域均值)× 周期性强度,两头都不突出就自动低置信。

拿到 BPM 后还有一步"回头精修":拍点跟踪完成后,用整段网格的总跨度反算 BPM(60 × (拍数-1) / 总时长),与自相关结果相差 5% 以内就以网格值为准——全局跨度对逐拍抖动远比局部自相关稳健。

四、Beat 跟踪:Ellis 2007 风格的动态规划

BPM 只给了"节奏的周期",还需要把每一拍"钉"在正确的时间上。trackBeats(约 TrackAnalyzer.swift#L845-L901)是经典的 Ellis 2007 目标函数:

  • 激励项:onset 包络值(按标准差归一化)——拍点尽量落在能量突变处;
  • 张力项:相邻拍间隔与期望周期的对数偏差平方 × 紧度系数 100——间隔偏离一个 beat 就重罚。

逐帧前向累积最优得分并记录回链,最后从尾部最高分帧回溯,得到全曲拍点序列。整个过程是 O(n × 窗口) 的一维 DP,vDSP 加速后毫秒级完成。

五、Downbeat 追踪:4/4 假设下的低频投票

"第几拍是小节第一拍"?estimateDownbeats(约 TrackAnalyzer.swift#L907-L946)的做法很朴素也很有效:

  1. 对每个拍点打分 = 该拍邻域内<200Hz 低频能量(kick/bass 最集中的频段)+ onset 强度的归一化之和;
  2. 假设 4/4 拍,把全部拍点按序号分成 4 个相位组,各取平均分;
  3. 平均得分最高的相位组整体胜出,组内拍点即 downbeats。

低频投票的关键是"整组一致性"而非单拍最强——某一拍再炸,也不如"每 4 拍都有低音"的规律可信。

六、验证:用合成 kick 音做回归测试

怎么证明算法靠谱?TrackAnalyzerTests.swift 不依赖真实歌库,而是合成纯 kick 鼓音轨(100 / 120 / 128 BPM,含 44.1 kHz 重采样路径),然后断言:

指标阈值
BPM 误差(×2/÷2 折算后)≤ ±2
拍点相位误差中位数< 70 ms
downbeat 间距中位数≈ 4 × 拍周期(误差 < 0.15 s)

这与 automix-spec.md M3 里程碑的验收标准一致。对无鼓点、自由节拍的曲目,算法会给出低bpmConfidence,过渡计划自动走退化链,保证听感底线。

七、小结:一张网格撑起整个 AutoMix

阶段技术产出
特征提取STFT + 40 维 log-mel + spectral fluxonset 包络
BPM 估计自相关 + 120 BPM 对数正态先验 + 抛物线插值bpm、bpmConfidence
拍点跟踪Ellis 2007 动态规划beats
Downbeat4 相位低频能量投票downbeats
下游消费TransitionPlanner.swift、StructureSegmenter.swift对拍混音选点、段落分段

全程只用了 Apple 自家的 Accelerate/vDSP,零新增依赖,结果持久化到AnalysisStore每曲只算一次。下一篇文章,我们将看看这张节拍网格如何被 TransitionPlanner 用来挑选"副歌唱完那一刻"作为交接点——那才是真正的 AutoMix 高光时刻。

【免费下载链接】kumone

雲の音 — Native macOS NetEase Cloud Music client built with SwiftUI

项目地址:https://gitcode.com/gh_mirrors/ku/kumone
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询