音频样本关键字的确定算法

58

我对确定音频样本的音乐键感兴趣。一种(或者可能的)算法如何尝试近似计算出一个音乐音频样本的键呢?

Antares Autotune和Melodyne是两个能够完成这种任务的软件。

有没有人可以用通俗易懂的方式解释一下这是如何工作的呢?使用数学方法通过分析和弦进程等频谱来推导一个歌曲的键。

这个话题非常吸引我!

编辑 - 来自所有为这个问题做出贡献的人的精彩资源和丰富信息。

尤其是来自: the_mandrill 和 Daniel Brückner。


@Moron - 谢谢。很高兴看到是否有任何SO用户能够给出一个好的答案 :) - Alex
2
就我所知,Antares Autotune并没有进行键检测,而只是将音符弯曲到你指定的某些半音上进行音高校正。可以查看其维基百科文章以获取界面屏幕截图。它可能会执行某种形式的音高检测,在处理单声道人声轨时,并不是太困难。我认为如何进行键检测是一个有趣的问题!:) - Colin Barrett
2
这并不会回答你有关算法的问题,但如果你对音乐处理的前沿技术感兴趣,并且愿意使用外部API,你可以查看 The Echo Nest - Justin L.
8个回答

65
值得注意的是,这是一个非常棘手的问题,如果您没有信号处理背景(或者对学习它感兴趣),那么您将会遇到非常沮丧的时期。如果您希望通过几个FFT解决问题,那么您将无法走得很远。我希望您有兴趣,因为这是一个非常迷人的领域。
首先,存在音高识别问题,对于简单的单声部乐器(例如声音),使用自相关或谐和和谱等方法可以相对容易地完成。但是,您通常会发现这会导致错误结果:您通常会得到一半或两倍于预期的音高。这称为音高周期加倍八度误差,基本上是因为FFT或自相关假定数据在时间上具有恒定的特征。如果您有一个由人类演奏的乐器,总会有一些变化。
有些人认为识别的问题是先进行音高识别,然后从音高序列中找到键。如果你除了单声部音高序列以外还有其他东西,那么这是难以想象的困难。即使您有一个单声部音高序列,确定键仍不是一种清晰的方法:例如如何处理半音符,或者确定它是大调还是小调。因此,您需要使用类似于Krumhansl的key finding algorithm算法的方法。
因此,考虑到这种方法的复杂性,另一种选择是同时查看所有正在播放的音符。如果您有和弦或多个乐器,则会产生许多正弦波同时播放的丰富光谱汤。每个单独的音符由多个谐波基频组成,因此A(在440Hz处)将由440、880、1320...的正弦波组成。此外,如果您播放E(请参见此diagram以获取音调),那么它的频率为659.25Hz,几乎是A的1.5倍(实际上是1.498)。这意味着A的每个第三谐波与E的每个第二谐波重合。这就是和弦听起来愉悦的原因,因为它们共享谐波。(顺带一提,西方和声之所以有效,是因为2的12次方根号7几乎等于1.5的怪异缘故。)
如果你将目光超越了这个五度音程的大调、小调和其他和弦,那么你会发现其他的比例关系。我认为许多关键查找技术会枚举这些比例关系,然后为信号中的每个谱峰填充一个直方图。因此,在检测A5和弦的情况下,你应该期望在440、880、659、1320、1760、1977处找到峰值。对于B5来说,它将是494、988、741等。因此,创建一个频率直方图,并为信号中的每个正弦峰(例如来自FFT功率谱)增加直方图条目。然后,对于每个键A-G,在你的直方图中累加箱子,具有最多条目的箱子最有可能是你的键。

那只是一个非常简单的方法,但可能足以找到弹奏或持续和弦的键。你还必须将信号分成小间隔(例如20ms),并分析每个间隔以建立更健壮的估计。

编辑:
如果你想尝试一下,我建议下载像OctaveCLAM这样的软件包,它可以更轻松地可视化音频数据并运行FFT和其他操作。

其他有用的链接:


3
一个良好的音高检测算法不应该检测和弦或确定“大调或小调”。它应该检测单个音符。这就是具有绝对音高能力的耳朵的工作方式(我具备这种能力+音乐教育) - 我听到的不是“C大调和弦”,而是听到了C+E+G,然后判断它确实是C大调和弦。即使你坐在钢琴键盘上或按下一组随机键(如C+Cis+D+Fis+G+Bes+B),我仍然能够命名每个音符,尽管它不是一个“和弦”。这是因为(我的)耳朵不是通过和弦或调式来运作的,而是通过音符来运作的。 - SigTerm
2
@SigTerm:问题并不像你所说的那样清晰明了。当有多个乐器演奏时(尤其是管弦乐谱),不可能听到每一个音符,但却可以简单地听到和弦。从信号处理的角度来看,问题是模糊的,因为你有几个乐器演奏相同的音高,或者(几乎)整数倍。因此,每个乐器的信号不是正交的。我认为唐基安的一篇论文表明,复杂的音调可以与和弦无法区分。(请参见上面的链接) - the_mandrill
1
@the_mandrill:对于听觉识别音高(当你无法立即命名所有音符时)的复杂谐波,它是这样的:你集中注意一个乐器的声音,然后对于每个乐器当前“活跃”的所有声音,你集中注意个别音符并“命名”它们。一个音符(耳朵)的识别是瞬间完成的。不确定大脑是如何做到的,“集中注意力”可能相当于设置过滤器灵敏度,而捕捉个别音符可能等同于直方图扫描。此外,不要忘记可以使用经过训练的神经网络。 - SigTerm
1
@SigTerm:并非总是必要或可能听到每个音符。一个由C4+C5组成的和弦可能与C4的复杂音相似,你之所以能够听出它是两个音符,是因为你对特定乐器的谐波结构有先前期望。如果你将其构造成正弦波(本质上就是你在检测的内容),那么可能无法检测到它。同样,C4+C5+G5听起来就像是C4的复杂音。因此和弦识别问题是模糊的。请参阅Terhardt的虚拟音高理论了解更多信息。 - the_mandrill
1
+1 对于 2^(7/12) 约等于 1.5 位。我已经想了一段时间了。 - Tomer Vromen
显示剩余11条评论

18

我在大学里致力于将多声部CD录音转写成乐谱的问题上工作了两年多。这个问题是出了名的难。与该问题相关的第一篇科学论文可以追溯到20世纪40年代,直到今天为止,对于一般情况还没有强大的解决方案。

通常所说的所有基本假设都不完全正确,其中大部分都错得足以使它们除了非常简单的情况外都无法使用。

泛音频率不是基础频率的倍数——存在非线性效应,因此高谐波会偏离预期的频率——而且不仅仅是几赫兹的偏差;在你期望第6个时,很常见地发现第7个谐波。

傅里叶变换与音频分析并不相容,因为人们感兴趣的频率是按对数间隔排列的,而傅里叶变换产生的频率是线性排列的。在低频时,你需要高频率分辨率来区分邻近的音高——但这会导致时间分辨率变差,你就失去了能够分离快速演奏的音符的能力。

音频录音(可能)并不包含重建乐谱所需的所有信息。我们的音乐感知的很大一部分发生在我们的耳朵和大脑中。这就是为什么一些最成功的系统是专家系统,拥有有关(西方)音乐结构的大型知识库,只依靠信号处理从音频录音中提取信息的一小部分。

当我回到家后,我会翻阅我已经阅读过的论文,并选择20到30篇最相关的论文并在此添加。我真诚地建议在决定实现某些东西之前先阅读它们——如前所述,大多数常见假设都有些不正确,你真的不想在实施和测试时重新发现这些已经发现和分析了50年以上的事情。

这是一个难题,但也很有趣。我真的很想听听你尝试了什么以及它的效果如何。


现在您可以了解一下常量Q变换、倒谱法和Wigner(-Ville)分布。还有一些关于如何从短时傅里叶谱的相移中提取频率的好论文 - 这允许使用非常短的窗口大小(以获得高时间分辨率),因为可以确定频率的精度比基础傅里叶变换的频率分辨率高数千倍。

所有这些变换都比普通的傅里叶变换更适合音频处理问题。如果要改进基本变换的结果,请查看能量重新分配的概念。


对我来说,就目前而言,我没有像你一样完全理解常数Q变换所需的数学知识。但是,我可以根据我不是特别广泛的计算机和编程知识尝试思考实际解决方案。 - Alex
在提到泛音系列的不和谐性时加1分。我可以通过使用多个同时调谐到泛音系列的闪光灯调音器来实际观察到这一点。随着时间的推移,音符的频率也会“弯曲”。 - hotpaw2
+1 对于提到Wigner-Ville的内容。如果我现在再次面对这个问题,我肯定会研究可以在时间和空间之间进行权衡的时频方法。这也是我们感知音调的更好模型。 - the_mandrill
有没有关于“如何从短时傅里叶谱中的相位变化中提取频率”的好论文示例?不确定在这里应该搜索什么。 - woojoo666
很想看看您建议阅读哪些具体论文以开始学习! - Meekohi

6
你可以使用傅里叶变换来计算音频样本的频谱。从此输出中,您可以使用特定音符的频率值将其转换为在样本期间听到的音符列表。选择一系列样本中听到的最强音符应该会给您一个不错的不同音符的映射,您可以将其与不同的音乐音阶进行比较,以获取包含该音符组合的可能音阶列表。
为了确定使用的是哪个特定的音阶,请记录(不是音符的双关语)最常听到的音符。在西方音乐中,音阶的根音通常是最常听到的音符,其次是第五音,然后是第四音。您还可以寻找模式,例如常见的和弦, 琶音, 或者 进程

在这里,样本大小可能非常重要。理想情况下,每个样本将是单独的音符(这样就不会在一个样本中得到两个和弦)。如果您过滤并集中于低频率,您可能可以利用通常与打击乐器相关联的音量峰来确定歌曲的节奏,并将算法“锁定”在音乐的节拍上。从半拍长的样本开始,然后进行调整。准备好丢弃一些没有太多有用数据的样本(例如,在滑动中间取样的样本)。


从功率谱中提取音高并不容易,有更好的音高检测算法。 - Paul R
整个过程非常复杂,但非常有趣。我认为和弦会产生很多复杂性,因为它们会产生自己的共鸣和谐频率,在算法中要考虑这些因素可能非常困难! - Alex
@AlexW- 是的,谐振是存在的,但它的幅度要比和弦本身低得多。如果你知道和弦,就可以预测可能会听到的谐波,并相应地过滤掉它们,以得到更准确的结果。 - bta
@bta 是的,那是真的。根据这个页面生成的材料,这是一个全面棘手的任务。也许如果你能剥离音乐中不必要的元素,就可以更容易地确定键(首先添加一个带通滤波器来去除高低频)。 - Alex
@AlexW- 我建议你从一些以电子音调序列记录的东西开始(比如来自电子键盘)。简单的音调更容易处理,一旦你掌握了这个技巧,就可以慢慢转向更复杂的声音。现实世界中的乐器(尤其是人声)是由多种声音组合而成的,更难以破解;如果你针对特定的乐器进行处理,最好能过滤掉超出该乐器范围的任何声音。 - bta

5
据我从这篇文章所了解的,不同的键盘有着各自的常见频率,因此它可能会分析音频样本以检测最常见的音符和和弦。毕竟,你可以有多个具有相同升降号配置的键,区别在于键开始的音符和因此这些键的和弦,因此似乎只有显著音符和和弦出现的频率是你能够弄清楚这种事情的唯一真正方法。我认为你不能得到一个普通人可以理解的实际数学公式的解释,除非省略很多信息。
请注意,这是来自一个完全没有经验的人的意见,他的第一次接触是在这篇答案中链接的文章中。

3

这是一个复杂的话题,但确定单个键(单个音符)的简单算法如下:

对包含音符的样本的一部分进行傅里叶变换,例如4096个样本(确切大小取决于您的分辨率要求)。确定频谱中的功率峰值 - 这是音符的频率。

如果有和弦、不同的“乐器/效果”或非同音乐模式,则情况会变得更加紧密。


是的,我认为您需要一个相当干净的样本才能使用。当然,还要符合西方的音调结构。很好的回答,非常感谢。 - Alex
峰值的频率并不等于音高,至少对于乐器来说是这样。最好使用其中一种流行的音高检测算法。 - Paul R
@Paul R - 是的,我知道音高的“音量”感受是由其频率决定的,而不是其他什么因素。但这也让我有些困惑。 - Alex
@AlexW:音高是一种感知而非实际的物理量,但它通常与所奏乐音的基频非常接近。然而,在某些乐器中,基频可能具有相当低的振幅,甚至完全不存在,因此需要使用适当的音高检测算法而不是功率谱。 - Paul R

3
首先,你需要一个音高检测算法(例如自相关)。
接下来,你可以使用该音高检测算法来提取一定数量的短时间窗口内的音高。之后,你需要确定这些采样到的音高最匹配哪个音乐调。

我不确定这个方法是否适用于和弦,因为你会同时听到许多音高。 - Alex
@AlexW:是的,和弦会很棘手 - 你需要采样音乐中更具旋律和单声部的部分。 - Paul R
目前,说实话,这是一个相当模糊的概念。数学很吓人,但重要的是要记住,存在工具来帮助处理“样板”傅里叶变换。这是理解数据并尝试算法的情况。 - Alex

1
分析调性并不等同于分析音高。不幸的是,整个调性概念有些模糊不清,不同的定义通常只共享主音的概念,即中心音/和弦。即使存在良好的自动转录系统,也没有可靠的算法来确定调性。

1
如果你现在需要对一堆歌曲进行分类,那么可以使用类似 Mechanical Turk的众包方法来解决这个问题。

2
那将是一个“具有完美音乐理解的机械土耳其人”...祝你找到你的来源! - Alex

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