如何以编程方式确定歌曲的速度/BPM?常用的算法有哪些,需要注意什么?
10 回答
这很难在单个 StackOverflow 帖子中解释。通常,最简单的节拍检测算法通过定位声能中的峰值来工作,这很容易检测。更复杂的方法使用梳状滤波器和其他统计/波形方法。有关包括代码示例的详细说明,请查看此 GameDev 文章。
要搜索的关键字是“节拍检测”、“节拍跟踪”和“音乐信息检索”。这里有很多信息:http: //www.music-ir.org/
有一个(可能)年度竞赛叫做 MIREX,不同的算法在它们的节拍检测性能上进行测试。
http://nema.lis.illinois.edu/nema_out/mirex2010/results/abt/mck/
那应该给你一个要测试的算法列表。
一个经典的算法是Beatroot (google it),它很好而且很容易理解。它是这样工作的:
- 对音乐进行短时 FFT 以获得声波图。
- 将每个时间步长的所有频率的幅度增加相加(忽略减少)。这为您提供了一个称为“光谱通量”的一维时变函数。
- 使用任何旧的峰值检测算法查找峰值。这些被称为“开始”并且对应于音乐中声音的开始(音符的开始,鼓声等)。
- 构建发病间隔 (IOI) 的直方图。这可以用来找到可能的节奏。
- 为节拍跟踪结果初始化一组“代理”或“假设”。按顺序一次给这些代理喂食。每个代理跟踪也是节拍的起始列表,以及当前的节奏估计。代理可以接受这些起始点,如果它们与他们最后跟踪的节拍和节奏非常吻合,如果它们完全不同,则忽略它们,或者如果它们介于两者之间,则生成一个新代理。并非每个节拍都需要开始 - 代理可以插值。
- 每个智能体都根据其假设的简洁程度给出一个分数——如果它的所有节拍开始都响亮,它会得到更高的分数。如果他们都是正常的,它会得到更高的分数。
- 得分最高的代理就是答案。
根据我的经验,这种算法的缺点:
- 峰值检测是相当临时的,并且对阈值参数等敏感。
- 有些音乐在节拍上没有明显的开始。显然它不适用于那些。
- 很难知道如何解决 60bpm-vs-120bpm 问题,尤其是实时跟踪!
- 仅使用一维光谱通量会丢弃大量信息。我认为你可以通过使用一些带限制的光谱通量(可能还有一个用于鼓的宽带)来做得更好。
这是该算法的实时版本的演示,显示了光谱通量(底部的黑线)和起始点(绿色圆圈)。值得考虑的事实是节拍仅从绿色圆圈中提取。我已经像点击一样回放了起始点,老实说,我认为我听不到它们的节拍,所以在某些方面,这个算法在节拍检测方面比人们更好。我认为减少到这样一个低维信号是它的弱步骤。
令人烦恼的是,几年前我确实找到了一个非常好的网站,其中包含许多用于节拍检测的算法和代码。我完全没有重新找到它。
编辑:找到了!
这里有一些很棒的链接可以帮助您入门:
节拍提取涉及识别音乐中的认知度量结构。很多时候,这些与物理声音能量不对应——例如,在大多数音乐中都有一定程度的切分音,这意味着我们感知到的“踩脚”节拍与物理声音的存在不对应。这意味着这是一个与起始检测完全不同的领域,它是物理声音的检测,并且以不同的方式执行。
你可以试试Aubio库,它是一个简单的 C 库,提供了起始和节拍提取工具。
还有在线Echonest API,虽然这涉及将 MP3 上传到网站并检索 XML,所以可能不太适合..
编辑:我昨晚遇到了这个 - 一个非常有前途的 C/C++ 库,虽然我自己没有使用它。鞋面插件
如果你能设法在你的项目中与 python 代码交互,Echo Nest Remix API是一个非常漂亮的 python API:
有一种方法analysis.tempo
可以为您提供 BPM。正如您从 API 文档或本教程中看到的那样,它可以做的不仅仅是简单的 BPM
您感兴趣的一般研究领域称为音乐信息检索
有许多不同的算法可以做到这一点,但它们基本上都以起始检测为中心。
开始检测测量事件的开始,在这种情况下,事件是正在播放的音符。您可以查找加权傅立叶变换(高频内容)的变化,您可以查找光谱内容的大变化。(光谱差异)。(我建议您进一步研究几篇论文)一旦应用了起始检测算法,您就可以通过阈值确定节拍的位置。
获得节拍的时间定位后,您可以使用各种算法。您可以将其转换为脉冲序列(创建一个始终为零的信号,仅在您的节拍发生时为 1)然后对其应用 FFT 和 BAM,现在您在最大峰值处有一个起始频率。
这里有一些论文可以引导您朝着正确的方向前进:
http://www.elec.qmul.ac.uk/people/juan/Documents/Bello-TSAP-2005.pdf
http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf
这是一些人正在讨论的内容的扩展:
有人提到研究应用机器学习算法:基本上从起始检测函数(如上所述)中收集一堆特征,并将它们与神经网络/逻辑回归中的原始信号结合起来,并了解是什么让节拍成为节拍。
看看 Andrew Ng 博士,他有来自斯坦福大学的在线免费机器学习讲座(不是冗长的视频讲座,实际上有一个在线远程课程)
执行傅里叶变换,并在功率谱中找到峰值。您正在寻找低于 20 Hz 人类听觉截止频率的峰值。我猜通常在 0.1-5ish Hz 范围内是慷慨的。
可能有帮助的问题:Bpm 音频检测库
此外,这是关于 SO 的几个“峰值发现”问题之一: 测量信号的峰值检测
编辑:不是我做音频处理。这只是基于您正在寻找文件的频域属性这一事实的猜测......
另一个编辑:值得注意的是,像 mp3 这样的有损压缩格式首先存储傅里叶域数据而不是时域数据。稍微聪明一点,您就可以省去一些繁重的计算……但请参阅 cobbal 的深思熟虑的评论。
重新发布我的答案:最简单的方法是让用户按照节拍的节奏点击一个按钮,然后计算点击次数除以时间。
有几种方法可以获得 BPM,但我发现最有效的一种是“节拍频谱”(在此处描述)。该算法通过将音乐的每个短样本与其他样本进行比较来计算相似度矩阵。一旦计算出相似度矩阵,就有可能获得每个时间间隔 T 的每个样本对 {S(T);S(T+1)} 之间的平均相似度:这是拍频。拍频频谱中的第一个高峰大部分时间是拍频持续时间。最好的部分是您还可以进行音乐结构或节奏分析等操作。
其他人已经描述了一些节拍检测方法。我想补充一点,有一些库可以为这类任务提供技术和算法。
Aubio就是其中之一,它享有很高的声誉,它是用 C 语言编写的,带有 C++ 包装器,因此您可以轻松地将它与可可应用程序集成(Apple 框架中的所有音频内容也是用 C/C++ 编写的)。
我想这在 4-4 舞曲中是最简单的,因为应该有大约每秒两次的单一低频砰砰声。