如何在PHP中检测一首歌的BPM

80

如何通过编程确定歌曲的速度/BPM?常用的算法有哪些,需要考虑哪些因素?

10个回答

44

在单个 StackOverflow 帖子中解释这是具有挑战性的。一般而言,最简单的节拍检测算法是通过定位声能量中的峰值来工作,这很容易检测到。更复杂的方法使用梳状滤波器和其他统计/波形方法。有关详细说明和代码示例,请查看此 GameDev 文章


5年后,GameDev文章还是没有404错误ツ(此外,您可以经常使用webarchive.org,如http://web.archive.org/web/20120525085210/http://archive.gamedev.net/archive/reference/programming/features/beatdetection/index.html) - earcam
请问您能否解释一下GameDev文章中的一个问题?作者说1024个样本大约是0.5秒。稍后他又说44032个样本大约是1秒。但是如果每0.05秒1024个样本等于每秒20480个样本,那我们是如何得出44032个样本大约是1秒的呢?难道有不同的频率吗?这段文字可以通过搜索数字1024的第一个条目轻松找到。 - Powercoder
https://www.gamedev.net/tutorials/_/technical/math-and-physics/beat-detection-algorithms-r1952/ 包含相同的信息。 - yyny

30

需要搜索的关键词是“节拍检测”,“节拍跟踪”和“音乐信息检索”。这里有很多信息:http://www.music-ir.org/

还有一个(或许)年度竞赛叫做MIREX,不同的算法会在其中测试它们的节拍检测性能。

http://nema.lis.illinois.edu/nema_out/mirex2010/results/abt/mck/

这应该会给你一个要测试的算法列表。

一个经典算法是Beatroot(Google一下),非常容易理解。它的工作原理如下:

  1. 对音乐进行短时傅里叶变换以得到声谱图。
  2. 对所有频率上每个时间步长的幅度增量求和(忽略幅度的减少),得到一个称为“谱通量”的1D时变函数。
  3. 使用任何旧的峰值检测算法找到峰值。这些被称为“起始点”,对应着音乐中的声音开始(音符、鼓击等)。
  4. 构建间隔起始点之间时间的直方图。这可以用来找到可能的节奏。
  5. 初始化一组“代理”或“假设”,用于节拍跟踪结果。依次将这些代理以一次一个的顺序传递给起始点。每个代理跟踪同时也是节拍的起始点列表和当前的节奏估计值。代理可以接受起始点,如果起始点与其上一个节拍和节奏估计值非常接近,则忽略它们,如果它们之间有差异,则生成一个新的代理。不需要每个起始点都对应一个节拍-代理可以进行插值。
  6. 根据其假设的整洁程度为每个代理得分-如果其节拍起始点都很响亮,则获得更高的分数。如果它们都很规则,则得分会更高。
  7. 最高得分的代理就是答案。

根据我的经验,这种算法的缺点包括:

  • 峰值检测方法非常临时,对阈值参数等因素非常敏感。
  • 有些音乐没有明显的节拍起点,在这种情况下无法使用该方法。
  • 很难解决60bpm与120bpm之间的问题,特别是在实时追踪时!
  • 只使用一维谱通量会舍弃大量信息。我认为通过几个限带谱通量(也许一个宽带鼓声)可以做得更好。

这里是该算法的实时演示,显示了谱通量(底部黑线)和起始点(绿色圆圈)。值得注意的是,节拍仅从绿色圆圈中提取。我将起始点播放为点击音,并且老实说,我认为我无法从点击音中听出节拍,所以在某些方面,该算法比人们更擅长节拍检测。我认为将信号降至如此低的维度是其弱点所在。

令人恼火的是,几年前我发现了一个非常好的网站,其中有许多关于节拍检测的算法和代码。但我完全找不到它了。

编辑:我找到了!

以下是一些很棒的链接,可以帮助您入门:

http://marsyasweb.appspot.com/

http://www.vamp-plugins.org/download.html


构建针对OSX目标的Vamp插件很困难。依赖关系没有问题,但是在darwin操作系统中的typedefs存在问题。尝试将sdk切换到.../Developer/SDKs/iPhoneOS7.0.sdk后使用make -f build/Makefile.osx命令,你就会明白我的意思了。 - loretoparisi

22
节奏提取是指在音乐中识别认知度量结构。很多时候,这些结构并不对应于物理声音能量——例如,在大多数音乐中都存在一定程度的打击节奏,这意味着我们感知到的“踩脚”节拍与物理声音的存在并不相符合。这意味着这是一个与“起始检测”截然不同的领域,“起始检测”是检测物理声音的存在,并以不同的方式执行。
您可以尝试使用Aubio库,它是一个简单的C库,提供起始和节奏提取工具。
还有在线的Echonest API,但这需要上传MP3到网站并获取XML,可能不太适合。 编辑:我昨晚发现了这个非常有希望的C/C++库,虽然我自己没有使用过:Vamp Plugins

10

您感兴趣的研究领域被称为音乐信息检索(MUSIC INFORMATION RETRIEVAL)

有许多不同的算法可以做到这一点,但它们都基本上围绕起始点检测(ONSET DETECTION)展开。

起始点检测测量事件的开始,而在这种情况下,事件是指发出音符。 您可以查找加权傅里叶变换(高频内容)中的变化,也可以查找谱内容中的大量变化(谱差异)。(在下面我推荐了几篇论文供您进一步了解)完成起始点检测算法后,您可以通过阈值选取节拍位置。

一旦获得了节奏的时间定位,就可以使用各种算法。 您可以将其转换为脉冲列(创建一个信号,该信号在所有时间为零,仅在发生节拍时为1),然后对其应用FFT,现在您已经在最大峰处获得起始点的频率。

以下是引导您正确方向的一些论文:

https://web.archive.org/web/20120310151026/http://www.elec.qmul.ac.uk/people/juan/Documents/Bello-TSAP-2005.pdf

https://adamhess.github.io/Onset_Detection_Nov302011.pdf

以下是一些人正在讨论的扩展内容:

有人提到了研究应用机器学习算法:基本上,从起始点检测函数(上述提到的)中收集大量特征并将其与原始信号结合在神经网络/逻辑回归中,学习什么构成了节拍。

请查看Andrew Ng博士,他在网上提供斯坦福大学的免费机器学习课程(不是冗长的视频讲座,实际上是在线远程课程)。


第二个URL已经失效。我们已经检查了权限或未找到,并检查了档案,但没有运气。https://web.archive.org/web/20220000000000*/http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf - JayRizzo
你现在可以在我的Github页面上找到它。http://adamhess.github.io/Onset_Detection_Nov302011.pdf - Adam Hess

9
如果您能够在项目中与Python代码进行接口交互,Echo Nest Remix API 是一个相当不错的Python API:其中有一个方法analysis.tempo可以给出BPM。除了简单的BPM之外,它还可以执行更多操作,可以从API文档或这个教程中看到。

7

进行傅里叶变换,并在功率谱中查找峰值。您要寻找低于人类听觉20 Hz截止频率的峰值。我猜通常在0.1-5 Hz范围内比较慷慨。

可能有用的SO问题:Bpm音频检测库

此外,这是SO上的几个“峰值查找”问题之一:测量信号的峰值检测


编辑:并不是我进行音频处理。这只是一个猜测,基于您正在寻找文件的频域属性...
另一个编辑: 值得注意的是,像mp3这样的有损压缩格式在第一时间存储的是傅里叶域数据而不是时域数据。通过一些巧妙的方法,你可以节省大量计算量...但请参考cobbal的深思熟虑的评论。

1
然而,MP3 通过削减人类听力范围之外的频率来实现压缩。傅里叶可能不是这里正确的工具。 - cobbal
1
MP3不会“削减”人类听力范围之外的频率,并且它会对每个约1毫秒宽的包络窗口进行余弦变换(与傅里叶变换相关)。我建议尝试dmckee的第一个建议,使用10秒长的窗口,看看结果如何。 - TrayMan
这太简单化了,无法真正发挥作用。 - Timmmm

2
有几种方法可以得到BPM,但我发现最有效的方法是“节拍频谱”(在这里描述)。该算法通过将音乐的每个短样本与其他所有样本进行比较来计算相似性矩阵。一旦计算出相似性矩阵,就可以获取每个时间间隔T中每个样本对{S(T);S(T+1)}之间的平均相似度:这就是节拍频谱。节拍频谱中的第一个高峰大多是节拍持续时间。最好的部分是,您还可以进行音乐结构或节奏分析等其他操作。

2

转发我的回答:做到这一点的简单方法是让用户按照节奏轻敲按钮,并计算时间内轻敲次数的数量。


2

其他人已经描述了一些节拍检测方法。我想补充说明的是,有一些可用的库提供了这种任务所需的技术和算法。

Aubio 是其中之一,它具有良好的声誉,并使用C编写了一个C++包装器,因此您可以轻松地将其与可可应用程序集成(苹果框架中的所有音频内容也都是用C/C++编写的)。


-2

我想在4-4的舞曲中会更容易实现,因为每秒应该有一个低频重击。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接