我想写一个简单的程序(最好用C#编写),我用麦克风唱一个音高,程序识别音高对应的音符。
非常感谢您的及时回复。我澄清道:
我想要一个(最好是.NET)库来识别我唱的音符。我喜欢这样的图书馆:
我打算用这样一个库一次唱一个音符。
答案 0 :(得分:20)
这个问题的关键部分是快速傅立叶变换。该算法将波形(您的唱歌音符)转换为频率分布。计算完FFT后,您可以识别基频(通常是FFT中幅度最高的频率,但这在某种程度上取决于您的麦克风的频率响应曲线以及您的麦克风正在收听的确切类型的声音)。
一旦找到基频,就需要在将频率映射到音符的列表中查找该频率。在这里你需要处理两者之间(所以如果你的唱歌音符的基本频率是452Hz,它实际上会响应什么音符,A或A#?)。
CodeProject上的这个人在C#中有一个FFT示例。我确定那里有其他人......
答案 1 :(得分:8)
您正在寻找frequency estimation或pitch-detection算法。大多数人建议找到FFT的最大值,但这过于简单,并且不像您想象的那样有效。如果fundamental is missing(例如一个定音鼓)或其中一个谐波大于基波(例如小号),它将无法检测到正确的频率。小号谱:
(来源:cam.ac.uk)
此外,如果您只是在寻找特定频率,那么您在浪费处理器周期来计算FFT。您可以使用Goertzel algorithm之类的内容更有效地查找特定频段的音调。
你真的需要找到“第一个显着频率”或“具有强谐波分量的第一个频率”,这比找到最大值更加模糊。
Autocorrelation或harmonic product spectrum更能找到真实乐器的真正基础,但如果乐器是inharmonic(大多数是),那么波形会随着时间而变化,我怀疑如果你一次测量超过几个周期就不会有效,这会降低你的准确度。
答案 2 :(得分:7)
您通常会对输入进行傅里叶变换,然后确定最突出的频率。这可能不是整个故事,因为任何非合成声源都会产生许多频率(它们构成所谓的“音色”)。无论如何,它可以有效地完成;有实时自动调节器(你不相信流行音乐明星可以真的唱歌,是吗?)。
答案 3 :(得分:4)
几乎每个答案都说做FFT。我自己编写了这个程序,我发现FFT很好地粗略地识别出最强的频率,但是结果有一些“拖尾” - 精确并不总是那么容易使用FFT识别目标音高的微小变化,特别是在样本很短的情况下。
Erik Kallen的方法看似合理,但还有其他方法。我发现效果相当好的是使用FFT和简单的“过零”检测算法的组合来缩小信号的确切频率。
也就是说,计算信号在给定间隔内穿过零线的次数,使其适合FFT产生的粗略频率“桶”,您可以获得非常精确的结果。
答案 4 :(得分:3)
执行傅里叶变换将为您提供样本中找到的每个频率的值。频率越突出,值越高。如果您寻找最大值,您将找到根频率,但也会出现泛音。
如果您正在寻找特定频率,使用Goertzel算法可能非常有效。
答案 5 :(得分:3)
我过去做过 pitch detection ,“采用FFT并查看峰值”的简单解决方案根本不适用于语音。我使用 cepstral analysis 的运气相当不错。在Lawrence Rabiner的publications中可以找到许多有用的论文。我建议从"A comparative performance study of several pitch detection algorithms"开始。
正如警告一样,我可能花了大约30到40个小时的工作才能到达我可以将wav文件发送到我的程序中并让它吐出一个合理的数字。我对说话者声音的基本频率也更感兴趣。我确信处理音乐会增加更多的皱纹。
答案 6 :(得分:2)
您需要捕获原始输入,累积一些样本,然后对它们进行FFT。 FFT会将您的样本从时域转换为频域,因此它产生的有点像信号在不同频率上包含多少能量的直方图。
从那里到“频率”可能有点困难 - 人类的声音不只包含一个清晰的声音频率。相反,你通常会有相当数量的不同频率的能量。你通常会做的是从最低的声音范围开始,然后逐步前进,寻找能量明显高于背景噪音的第一个(最低)频率。
答案 7 :(得分:2)
您必须对样本进行FFT,然后对其进行分析。使分析复杂化的两件事是:
色彩。如果您以440 Hz(A4)演唱/播放A,您还将获得A5(880Hz)的音调,E6(1320 Hz)的音调等。根据频率的相对强度,可以感知到此音调作为A4,A5或E6,并且对音调进行去音不仅仅是最强度的地方,人耳比这更复杂。但是,您可以合理地猜测它将被视为A。
粒度。您的FFT的粒度仅取决于样本的持续时间,而不取决于采样频率。如果我没记错的话,你需要一个两秒钟的样本才能获得1 Hz的粒度,这仍然有点粗糙。解决此问题的一种方法是在每个尖峰周围取三个频率,逼近它们周围的二次多项式,然后确定该多项式的最大值。我读过一篇论文,声称使用相位比使用相位更准确,但我不记得在哪里,所以我不能引用它。
答案 8 :(得分:2)
我对这里建议使用FFT的所有答案感到惊讶,因为FFT对于音调检测通常不够精确。 可以,但只有一个不切实际的大FFT窗口。例如,当基音在音乐会A(440 Hz)附近时,为了确定半音准确度的1/100(基本上是准确音高检测所需的基准),您需要一个带有524,288的FFT窗口元素。 1024是更典型的FFT大小 - 窗口越大,计算时间越长。
我必须在我的软件合成器中识别WAV文件的基本音高(其中“未命中”可以立即听到作为失调乐器)并且我发现自相关确实是最好的工作。基本上,我在8个音高范围内迭代12音阶中的每个音符,计算每个音符的频率和波长,然后使用该波长作为滞后执行自相关(自相关是测量相关性的地方)在一组数据和相同的数据集之间偏移一些滞后量)。
具有最高自相关分数的音符因此大致是基本音调。然后我通过从一个半音向下迭代到一个半音调的1/1000的半音来“磨练”真正的基音,以找到局部峰值自相关值。这种方法非常准确,更重要的是它适用于各种乐器文件(弦乐,吉他,人声等)。
此过程非常慢,但是,特别是对于长WAV文件,因此无法用于实时应用程序。但是,如果你使用FFT来粗略估计基波,然后使用自相关将真值调零(并且你满足于不那么准确,那么半音的1/1000,这是荒谬的 - 准确的)你会有一个相对快速和极其准确的方法。
答案 9 :(得分:2)
也许这个来自codeplex的完全托管的文件库适合您:Realtime C# Pitch Tracker
作者列出了自相关及其算法实现的以下优点:
快速。如上所述,算法非常快。它可以轻松地每秒进行3000次俯仰测试。
准确。与实际频率的测量偏差小于+ -0.02%。
在大范围的输入级别上准确无误。因为算法使用不同峰值的比率而不是绝对值,所以它在很宽的输入电平范围内保持准确。在-40dB至0dB输入电平范围内,精度不会下降。
在整个频率范围内准确无误。在从50 Hz到1.6 kHz的整个检测频率范围内,精度保持很高。这是由于在计算滑动窗口的样本时应用的插值。
对任何类型的波形都准确无误。与许多其他类型的音调检测算法不同,该算法基本上不受复杂波形的影响。这意味着它适用于任何类型的男性和女性声音,以及吉他等其他乐器。唯一的要求是信号是单声道的,因此无法检测到和弦。这种音高检测器可以很好地作为一个非常灵敏的吉他调音器。
不依赖以前的结果。该算法足够精确,不需要依赖以前的结果。每个音调结果都是一个全新的计算值。通过“锁定”到音高来跟踪音高的音高算法遇到的问题是,如果它们检测到错误的音高(通常是一个太高或太低的音高),它们对于许多后续测试也会继续出错。
答案 10 :(得分:1)
如果您只想要结果 - 我,e,使用该软件,有一个名为SingAndSee的程序就是这样做的。这大约是25英镑
答案 11 :(得分:1)
由于您正在处理单声道声源,因此使用FFT检测到的大多数音高应该是谐波相关的,但您并不能确保基波是最强的音高。事实上,对于许多乐器和一些语音寄存器,它可能不会。它应该是检测到的谐波相关(在基波的整数倍)中的最低音调。
答案 12 :(得分:0)
要转换来自麦克风的时域信号,您需要a 离散傅立叶变换(DFT)或快速傅立叶变换(FFT)。 FFT将更快地工作,但代码将更加复杂(DFT可以在5-10行代码中完成)。完成后,您必须将基本频率映射到音符,遗憾的是,根据您使用的调音系统,有几种映射方案。其中最常见的是Equal Temperament。 Frequencies here。关于Equal Temprement的维基百科文章也给出了平等气质的背景。
使用任何傅里叶数学时,您需要了解频率的处理方式,理想情况下,在变换前执行抗混叠滤波,并在执行变换时注意频率反射。由于Nyquists theorum,您需要至少两倍于最大频率采样麦克风内容,即。如果最高频率为10Hz,则必须以20Hz进行采样。
答案 13 :(得分:0)
D3D11包含FFT implementation