用于识别间距的.NET库

我想写一个简单的程序(最好是在C#中),我用麦克风唱一个音高,程序识别音高对应的音符。


非常感谢您的及时回复。 我澄清一下:

我想要一个(最好是.NET)库来识别我唱的音符。 我想要这样一个图书馆:

  1. 我唱歌时识别音符(半音音符)。
  2. 告诉我,我离最近的音符有多远。

我打算用这样的库一次唱一个音符。

这个问题的关键部分是快速傅立叶变换。 该算法将波形(您的唱歌音符)转换为频率分布。 计算完FFT后,您可以识别基频(通常是FFT中幅度最高的频率,但这在一定程度上取决于您的麦克风的频率响应曲线以及麦克风正在收听的声音类型)。

一旦找到了基频,就需要在将频率映射到音符的列表中查找该频率。 在这里你需要处理它们之间(所以如果你的唱歌音符的基频是452Hz,它实际上会响应什么音符,A或A#?)。

CodeProject上的这个人在C#中有一个FFT示例。 我确定还有其他人……

您正在寻找频率估计或音高检测算法。 大多数人建议找到FFT的最大值,但这过于简单,并且不像您想象的那样有效。 如果缺少基波 (例如定音鼓),或者其中一个谐波大于基波(例如小号),它将无法检测到正确的频率。 小号谱:

小号谱http://sofzh.miximages.com/c%23/02284.jpg

此外,如果您只查找特定频率,则会浪费处理器周期来计算FFT。 您可以使用Goertzel算法等function更有效地查找特定频段的音调。

你真的需要找到“第一个重要频率”或“具有强谐波分量的第一个频率”,这比找到最大值更加模糊。

自相关或谐波积谱更好地找到真实仪器的真正基础,但如果仪器是非谐波 (大多数是),那么波形会随着时间的推移而变化,我怀疑如果你尝试它也不会有效一次测量超过几个周期,这会降低您的准确性。

您通常会对输入进行傅里叶变换,然后确定最突出的频率。 这可能不是整个故事,因为任何非合成声源都会产生许多频率(它们构成所谓的“音色”)。 无论如何,它可以有效地完成; 有实时自动调节器(你不相信流行音乐明星可以唱歌,你呢?)。

几乎每个答案都说做FFT。 我自己编写了这个程序,我发现FFT很好地粗略地识别出最强的频率,但是结果有一些“拖尾” – 精确识别目标音高的微小变化并不总是那么容易使用FFT,特别是如果样本很短。

Erik Kallen的方法似乎很合理,但还有其他方法。 我发现效果相当好的是使用FFT和简单的“过零”检测算法的组合来缩小信号的确切频率。

也就是说,计算信号在给定间隔内穿过零线的次数,使其适合FFT产生的粗略频率“桶”,您可以获得非常精确的结果。

执行傅里叶变换将为您提供样本中找到的每个频率的值。 频率越突出,值越高。 如果您寻找最大值,您将找到您的根频率,但也会出现泛音。

如果您正在寻找特定的频率,使用Goertzel算法可能非常有效。

我过去做过音调检测 ,“采用FFT并查看峰值”的简单解决方案根本不适用于语音。 我使用倒谱分析得到了相当好的运气。 在Lawrence Rabiner的出版物中可以找到许多有用的论文。 我建议从“几种音高检测算法的比较性能研究”开始 。

就像一个警告,它可能花了我大约30-40小时的工作,以达到我可以将wav文件发送到我的程序并让它吐出一个合理的数字。 我对说话者声音的基本频率也更感兴趣。 我敢肯定,处理音乐会增加更多的皱纹。

您需要捕获原始输入,累积一些样本,然后对它们进行FFT。 FFT会将您的样本从时域转换为频域,因此它产生的有点像信号在不同频率上包含多少能量的直方图。

从那里到“频率”可能有点困难 – 人类的声音不会只包含一个清晰的声音频率。 相反,你通常会有相当数量的不同频率的能量。 你通常要做的是从最低的声音范围开始,然后逐步前进,寻找能量明显高于背景噪音的第一个(最低)频率。

您必须对样本进行FFT,然后对其进行分析。 使分析复杂化的两件事是:

  1. 弦外之音。 如果您以440 Hz(A4)演唱/播放A,您还将获得A5(880Hz)的音调,E6(1320 Hz)的音调等。根据频率的相对强度,可以感知到此音调作为A4,A5或E6,并且对音调的去除不仅仅是最强度的地方,人耳比这更复杂。 但是,你可以合理地猜测它会被认为是A.

  2. 粒度。 您的FFT的粒度仅取决于样本的持续时间,而不取决于采样频率。 如果我没记错的话,你需要一个两秒钟的样本才能获得1 Hz的粒度,这仍然有点粗糙。 解决此问题的一种方法是在每个尖峰周围取三个频率,逼近它们周围的二次多项式,然后确定该多项式的最大值。 我读过一篇论文,声称使用相位比振幅更准确,但我不记得在哪里,所以我不能引用它。

我对这里建议使用FFT的所有答案感到惊讶,因为FFT对于音调检测通常不够精确。 它可以 ,但仅限于一个不切实际的大型FFT窗口。 例如,当基音在音乐会A(440 Hz)附近时,为了确定半音准确度的1/100(基本上是准确音高检测所需的基准),您需要一个带有524,288的FFT窗口元素。 1024是更典型的FFT大小 – 窗口越大,计算时间越长。

我必须在我的软件合成器中识别WAV文件的基本音调(其中“未命中”可以立即听到作为失调乐器)并且我发现自相关确实是最好的工作。 基本上,我在8个音高范围内迭代12音阶中的每个音符,计算每个音符的频率和波长,然后使用该波长作为滞后执行自相关(自相关是测量相关性的地方)在一组数据和相同的数据集之间偏移一些滞后量)。

因此,具有最高自相关分数的音符大致是基本音调。 然后我通过从一个半音向下迭代到一个半音的1/1000的半音来“磨合”真正的基音,以找到局部峰值自相关值。 这种方法非常准确,更重要的是它适用于各种乐器文件(弦乐,吉他,人声等)。

但是,此过程非常慢,特别是对于长WAV文件,因此无法用于实时应用程序。 但是,如果你使用FFT来粗略估计基波,然后使用自相关将真值调零(并且你满足于不那么准确,那么半音的1/1000,这是荒谬的 – 准确的)你会有一个相对快速和非常准确的方法。

你看过这个问题吗? C#中的快速傅里叶变换

听起来这可能会帮助你。

我想你想要这个问题: 使用FFT进行实时音高检测

如果您只想要结果 – 我,e,使用该软件,有一个名为SingAndSee的程序就是这样做的。 这大概是25英镑

由于您正在处理单声道音源,因此使用FFT检测到的大多数音高应该是谐波相关的,但您并不能确保基波是最强的音高。 事实上,对于许多乐器和一些语音寄存器,它可能不会。 它应该是检测到的谐波相关(在基波的整数倍)中的最低点。

也许这个来自codeplex的完全托管的库适合你: Realtime C#Pitch Tracker

作者列出了自相关及其算法实现的以下优点:

  1. 快速。 如上所述,算法非常快。 它可以轻松地每秒进行3000次俯仰测试。

  2. 准确。 与实际频率的测量偏差小于+ -0.02%。

  3. 准确适用于大范围的输入级别。 因为算法使用不同峰值的比率而不是绝对值,所以它在很宽的输入电平范围内保持准确。 在-40dB至0dB输入电平范围内,精度不会下降。

  4. 在整个频率范围内精确。 在整个检测到的频率范围内,精度保持很高,从大约50 Hz到1.6 kHz。 这是由于在计算滑动窗口的样本时应用的插值。

  5. 适用于任何类型的波形。 与许多其他类型的音调检测算法不同,该算法基本上不受复杂波形的影响。 这意味着它适用于任何类型的男性和女性声音,以及吉他等其他乐器。唯一的要求是信号是单声道的,因此无法检测到和弦。 这种音高检测器可以很好地作为一个非常灵敏的吉他调音器。

  6. 不依赖于以前的结果。 该算法足够精确,不需要依赖以前的结果。 每个音调结果都是一个全新的计算值。 通过“锁定”到音高来跟踪音高的音高算法遇到的问题是,如果它们检测到错误的音高(通常是一个太高或太低的音高),那么它们对于许多后续测试也将继续是错误的。

要转换来自麦克风的时域信号,您需要离散傅立叶变换(DFT)或快速傅里叶变换(FFT)。 FFT将更快地工作,但代码将更加复杂(DFT可以在5-10行代码中完成)。 完成后,您必须将基本频率映射到音符,遗憾的是,根据您使用的调音系统,有几种映射方案。 其中最常见的是Equal Temperament。 频率在这里 。 关于平等温度的维基百科文章也给出了平等气质的背景。

使用任何傅立叶数学时,您需要了解频率的处理方式,理想情况下,在变换前执行抗混叠滤波,并在执行变换时注意频率reflection。 由于奈奎斯特理论,您需要将麦克风内容采样至少两倍于最大频率,即。 对于最高频率为10Hz,您必须以20Hz采样。

D3D11包含FFT实现