退后一步... 要让这个工作起来,你必须找到一种方法来绘制此过程的中间步骤。 你正在尝试做的不是特别难,但容易出错且琐碎。 切割、窗口调整、错误的连线、混叠、直流偏移、读取错误通道、奇怪的FFT频率轴、阻抗不匹配、帧大小错误...谁知道呢。 但如果你能绘制原始数据,然后绘制FFT,所有的一切都会变得清晰明了。
我找到了几个实时音高跟踪的开源实现:
dywapitchtrack 使用小波算法。
“Realtime C# Pitch Tracker”使用一个修改过的自相关方法,目前已从Codeplex中删除-可以在GitHub上搜索
aubio(由piem提到;有多种算法可用)
还有一些音高跟踪器可能并非专门设计用于实时处理,但我不知道是否可以这样使用,并且作为参考,它们可能也很有用,来比较实时跟踪器:
Praat是一个开源软件包,有时被语言学家用于音高提取,您可以在http://www.fon.hum.uva.nl/paul/praat.html上找到文档化的算法。
Snack和WaveSurfer也包含音高提取器
我知道这个回答可能不会让每个人都满意,但是下面是我的建议。
这些内容很难,非常难。首先去阅读尽可能多的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组频率响应曲线。
在表现方面,有许多免费可用的库,尽管请注意各种许可模型。
最重要的是,在您的前几次尝试之后不要放弃。祝你好运。
我使用修改后的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录音的对数离散傅里叶变换图像。它展示了在演奏独奏时,吉他上的每个音符产生的谐波。对于这个对数离散傅里叶变换中的每个音符,我们可以看到它的多个谐波在垂直方向上延伸,因为每个谐波都具有相同的时间宽度。确定音符的八度后,我们就知道基频的频率。我曾经在几年前的一个项目中遇到过麦克风输入类似的问题,最终发现是由于直流偏移引起的。
在尝试FFT或其他方法之前,请确保消除任何偏差。
你也可能遇到了头部空间或削波问题。
图表是诊断大多数音频问题的最佳方式。
实时真实检测器的Java代码可在http://code.google.com/p/freqazoid/上获取。
它可以在任何运行后2008年发布的实时Java的计算机上运行良好。该项目已被放弃,任何感兴趣的人都可以接手。如果您需要更多详细信息,请与我联系。
http://www.codeproject.com/KB/audio-video/SoundCatcher.aspx
我知道这个应用程序是用C#编写的,而你需要的是C++,我也知道这是.Net/Windows,而你在使用Mac...但我想他的FFT实现可能是一个起点参考。尝试将你的FFT实现与他的进行比较。(他的是Cooley-Tukey的迭代广度优先版本)。它们相似吗?
此外,你描述的“随机”行为可能是因为你直接获取了从声卡返回的数据,而没有正确地从字节数组中组装值。你是否要求你的声卡采样16位值,并给它一个字节数组来存储这些值?如果是这样,请记住,返回数组中的两个连续字节构成一个16位音频样本。