实时音高检测

29

对于用户歌唱的实时音高检测,FFT自相关 得不到好的结果。我找不到C / C++方法。

麦克风输入数据是正确的,当使用正弦波时,结果或多或少是正确的音高。我通过从结果数组中取值,并将每个索引绘制在X轴上,将值绘制在Y轴上(两者都除以100,000,我使用OpenGL,不使用VST插件)。它看起来像随机点。如何可视化原始音频和自相关数据?


2
我怀疑你一直在“错误地做”。你是否解决了其他问题中的根本问题?整个“随机结果”的事情听起来像是你还没有把那些方法搞对。 - dmckee --- ex-moderator kitten
2
这个问题在我看来与“摇滚乐队”游戏中用于人声的音高检测非常相似 - 而且他们似乎已经成功地让它工作了。这让我相信一定有方法可以解决它。只是通过阅读维基百科上关于音高检测的文章,似乎这不是一个简单的问题。如果您找到了一个好的方法,我们希望您能在这里发布答案! - Mike Dinescu
9
为了进行调试,请尝试吹口哨。吹口哨的声音包含一个非常强的频率和很少的泛音。如果您还没有这样做,您也应该可视化FFT的输出。 - Thomas
1
我必须同意Thomas关于可视化的观点。绘制图形是了解分析声音特性的好方法。 - avakar
1
...或者在自相关的情况下,计算每个可能周期的相关系数。 - avakar
显示剩余8条评论
12个回答

36

退后一步... 要让这个工作起来,你必须找到一种方法来绘制此过程的中间步骤。 你正在尝试做的不是特别难,但容易出错且琐碎。 切割、窗口调整、错误的连线、混叠、直流偏移、读取错误通道、奇怪的FFT频率轴、阻抗不匹配、帧大小错误...谁知道呢。 但如果你能绘制原始数据,然后绘制FFT,所有的一切都会变得清晰明了。


如何准确地绘制原始数据和FFT? - some_id
1
@Helium3:波形和频谱图(2D)。请查看Audacity。 - MSalters
或者,将中间表示输出到CSV文件并在MATLAB或Octave中查看。 - johnwbyrd
没错。编程就是问题分解。你必须找到一种方法将问题分解成更容易解决的部分。 - Cameron Lowell Palmer

22

我找到了几个实时音高跟踪的开源实现:

  • dywapitchtrack 使用小波算法。

  • “Realtime C# Pitch Tracker”使用一个修改过的自相关方法,目前已从Codeplex中删除-可以在GitHub上搜索

  • aubio(由piem提到;有多种算法可用)

还有一些音高跟踪器可能并非专门设计用于实时处理,但我不知道是否可以这样使用,并且作为参考,它们可能也很有用,来比较实时跟踪器:


14

我知道这个回答可能不会让每个人都满意,但是下面是我的建议。

这些内容很难,非常难。首先去阅读尽可能多的FFT、自相关和小波教程。尽管我仍在苦苦探索数字信号处理,但我从以下资料中获得了一些启示。

https://www.coursera.org/course/audio 课程目前没有开设,但视频仍然可用。

http://miracle.otago.ac.nz/tartini/papers/Philip_McLeod_PhD.pdf 是一个关于开发音高识别算法的论文。

http://dsp.stackexchange.com 是一个专门讨论数字信号处理的网站。

如果像我一样数学功底不够,无法完全理解教程,也不要放弃,因为其中的一些图表和例子仍然有助于理解。

下一步是测试数据和测试。编写一个库生成测试文件,以检查您的算法。

1) 一个超级简单的纯正弦波发生器。例如,如果您想编写 YAT(Yet Another Tuner),可以使用正弦发生器创建一系列文件,约为440Hz,范围从420-460Hz,在不同的增量下测试您的代码的灵敏度和准确性。它能分辨到5Hz、1Hz甚至更细吗?

2) 然后升级您的正弦波发生器,使其添加一系列较弱的谐波信号。

3) 接下来是谐波的真实世界变化。因为空气在腔体中的行为方式不同,对于像单簧管和长笛这样的乐器,即使按照基频F0的简单倍数,其偶次谐波也会缺失或非常微弱。对于一些乐器,F0可能缺失,但可以通过其他谐波的分布确定。F0 是人耳感知到的音高。

4) 通过不规则地调整谐波峰频率的上下偏移来加入一些有意的扭曲。

重点是,如果您正在创建具有已知结果的文件,则更容易验证您构建的东西实际有效,当然除了错误之外。

还有许多包含声音样本的“库”。 https://freesound.org ,这也是上述Coursera系列中提到的一个网站。 http://theremin.music.uiowa.edu/MIS.html

接下来,请注意您的麦克风不完美,并且除非您在其上花费了数千美元,否则其频率响应范围会相当变化。特别是如果您使用低音符,则更便宜的麦克风(例如PC或手机的内置麦克风)从80-100Hz左右开始显著衰减。对于表现相对不错的外部麦克风,您可能会达到30-40Hz。去找出您麦克风的数据。

您还可以通过将音调通过扬声器播放,然后用您最喜欢的麦克风录制来检查发生了什么。但当然,现在我们谈论的是2组频率响应曲线。

在表现方面,有许多免费可用的库,尽管请注意各种许可模型。

最重要的是,在您的前几次尝试之后不要放弃。祝你好运。


9
这是我设计的一种不寻常的两阶段算法的C++源代码,可以在Windows上播放polyphonic MP3文件时进行实时音高检测。这个免费应用程序(PitchScope Player,在网上可用)经常用于检测吉他或萨克斯风独奏的音符。该算法旨在检测MP3音乐文件中任何时刻最显著的音高(音符)。通过在MP3录音过程中在任何给定时刻检测到最显著的音高(音符)的显著变化,可以准确地推断出音符的发生。
当我们按下钢琴上的一个键时,我们听到的不仅仅是一个声音振动频率,而是由多个在不同数学相关频率下发生的声音振动的组合。这个由不同频率振动组成的复合体被称为谐波或分波。例如,如果我们按下钢琴的中央C键,复合体的谐波的单独频率将从261.6 Hz开始作为基本频率,523 Hz将是第二次谐波,785 Hz将是第三次谐波,1046 Hz将是第四次谐波等等。后面的谐波是基本频率261.6 Hz的整数倍(例如: 2 x 261.6 = 523, 3 x 261.6 = 785, 4 x 261.6 = 1046)。以下链接是吉他独奏的多声部MP3录音中实际发生的谐波的快照。

我使用修改后的DFT变换,具有对数频率间距,而不是FFT,首先检测这些可能的谐波,通过查找具有峰值级别的频率来实现(见下图)。由于我收集修改后的Log DFT数据的方式,我不需要对信号应用窗函数,也不需要添加和重叠。我创建了DFT,使其频道的位置呈对数分布,以便直接与吉他、萨克斯等乐器上音符产生谐波的频率对齐。

现在退休后,我决定在一个名为PitchScope Player的免费演示应用程序中发布我的音高检测引擎的源代码。PitchScope Player可以在网上获得,您可以下载Windows可执行文件,以查看我在您选择的mp3文件上运行的算法。下面的GitHub.com链接将带您到我的完整源代码,您可以查看我如何使用自定义对数DFT变换检测谐波,然后查找其频率满足定义“音高”的正确整数关系的部分(谐波)。

我的音高检测算法实际上是一个两阶段的过程:a)首先检测到“ScalePitch”(“ScalePitch”有12个可能的音高值:{E,F,F#,G,G#,A,A#,B,C,C#,D,D#});b)并且在确定了ScalePitch之后,通过检查所有可能的4个八度候选音符的泛音来计算出八度。该算法旨在检测多声部MP3文件中任何给定时刻最显著的音高(音符)。通常对应于独奏乐器的音符。那些对我两阶段音高检测算法的C ++源代码感兴趣的人可能希望从GitHub.com的SPitchCalc.cpp文件中的Estimate_ScalePitch()函数开始。 https://github.com/CreativeDetectors/PitchScope_Player 以下是我的C++软件生成的吉他独奏多声部mp3录音的对数离散傅里叶变换图像。它展示了在演奏独奏时,吉他上的每个音符产生的谐波。对于这个对数离散傅里叶变换中的每个音符,我们可以看到它的多个谐波在垂直方向上延伸,因为每个谐波都具有相同的时间宽度。确定音符的八度后,我们就知道基频的频率。

enter image description here


5

我曾经在几年前的一个项目中遇到过麦克风输入类似的问题,最终发现是由于直流偏移引起的。

在尝试FFT或其他方法之前,请确保消除任何偏差。

你也可能遇到了头部空间或削波问题。

图表是诊断大多数音频问题的最佳方式。


3
您可以使用截止频率设置非常低的高通滤波器来消除直流偏置。我通常选择25-30赫兹,这是根据5或6条低音吉他中最低的结果来确定的。 - Nosredna
建议将您的输入通过主机,并使用免费的VST插件Fre(a)koscope和s(M)exoscope以图形方式查看频率响应和波形。 - Nosredna
有没有其他的方法可以做到这一点?VSTs Fre(a)koscope和s(M)exoscope是为Windows设计的,而我使用的是Mac。 - Niall
我认为有一个插件适配器可以让你在Intel Mac上使用PC VST。绝大多数免费插件都是PC的(这就是为什么我仍然在我的PC上制作音乐而不是我的Mac)。有一些类似的Mac工具,但它们中的大部分都不是免费的。试试BlueCat的东西。他有一个频谱分析仪和示波器。或者在kvraudio的音频插件数据库中搜索。或者只需在论坛上询问。 - Nosredna
频谱分析仪可以让你将FFT结果与他人进行比较,从而让你知道是否存在错误。示波器则可以让你看到是否出现了削波现象。 - Nosredna
显示剩余2条评论

2

实时真实检测器的Java代码可在http://code.google.com/p/freqazoid/上获取。

它可以在任何运行后2008年发布的实时Java的计算机上运行良好。该项目已被放弃,任何感兴趣的人都可以接手。如果您需要更多详细信息,请与我联系。


2
请看这个示例应用程序:

http://www.codeproject.com/KB/audio-video/SoundCatcher.aspx

我知道这个应用程序是用C#编写的,而你需要的是C++,我也知道这是.Net/Windows,而你在使用Mac...但我想他的FFT实现可能是一个起点参考。尝试将你的FFT实现与他的进行比较。(他的是Cooley-Tukey的迭代广度优先版本)。它们相似吗?

此外,你描述的“随机”行为可能是因为你直接获取了从声卡返回的数据,而没有正确地从字节数组中组装值。你是否要求你的声卡采样16位值,并给它一个字节数组来存储这些值?如果是这样,请记住,返回数组中的两个连续字节构成一个16位音频样本。


1

这是一个非常老的问题,我不知道你的答案是否仍然相关。 - stateMachine

1

看看aubio,这是一个开源库,其中包含了几种最先进的音高跟踪方法。


1

哪个问题?还是这个问题的已接受答案发生了变化? - some_id
抱歉,我已经修复了缺少链接的答案。 - P i

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