多音高检测:使用FFT还是其他方法?

4
我研究了快速傅里叶变换,但没有找到一种方法能够从一个信号中解码出多个频率。有没有一种方法可以分解fft计算的结果,以便我们可以看到和弦中的单独音高,或者根据fft结果计算最可能的和弦呢?
如果没有,还有其他的音高检测方法可以在现场检测出多个音高吗?
编辑:我尝试一次性检测不超过六个音高,因为我正在编写的软件涉及吉他;即使程序用户有七弦吉他,也需要最多检测出七个音高。
既然如此,FFT(或其他方法)是否能够从单个麦克风信号处理它们,还是我必须制作一个吉他拾音器来单独读取每根琴弦的信号?

2
原始信号中有多少个音调或正弦波?如果只有几个(例如DTMF信号中的2个核心音调),FFT可能会起作用。只需搜索峰值即可。否则,对于音乐而言,这通常被认为是计算机科学和信号处理中的难题。您可以在互联网上搜索“自动音乐转录”,您可能会找到一些尝试解决此问题的软件程序或代码。 - selbie
有一款著名的软件叫做Melodyne,可以处理复杂声音。 - cmannett85
可能是此问题的重复:https://dev59.com/u2855IYBdhLWcg3wcz5h#4339225 - hotpaw2
3个回答

3

有两种众所周知的参数谱估计统计技术。一种是MUSIC,另一种是ESPRIT。如果您可以将信号表示为加权复指数(即正弦波),则可以应用其中任何一种。此外,相关矩阵的特征分解还将告诉您信号中的频率数量,因此您甚至不需要知道这一点。ESPRIT比MUSIC更好,因为您不需要在频域中搜索峰值。频率将直接作为结果给出。然而,已知MUSIC更加健壮。


这基本上就是我要找的东西;它是否足够快以产生实时结果(即向吉他手提供实时反馈)? - Adam
根据你的数据大小而定。我更喜欢ESPRIT,这种情况下你需要进行两次特征分解。对于一个M乘以M的自相关矩阵,这相当于M的立方次操作。问题是你的M应该比K大(K是信号中频率的数量)。所以在你的情况下,我不认为这会是一个很大的问题,因为你没有太多的频率。 - jkt
1
据报道,当人们不知道涉及的指数数量时,@YBE:MUSIC和ESPRIT表现不佳,而吉他每根弦可以产生一些大量且变化多样的泛音(可能有几十个),其中一些可能略微不谐。 - hotpaw2
@hotpaw2,你说得没错,我们不知道指数的数量,但是自相关矩阵的特征分解也可以说明一些组件数量的问题。在特征谱中,随着信号特征值大于噪声特征值,应该会出现显著的下降。然而,在噪声观测值严重干扰的情况下,噪声特征值将与信号特征值相当。还有一种称为湮灭滤波器方法的技术,它与Cadzow的迭代去噪方法一起使用,被认为具有鲁棒性。 - jkt

2
你需要先了解什么是“音高”(请查阅下面的维基百科链接)。当吉他或钢琴演奏单个音符时,我们所听到的不仅是一个声音振动频率,而是多个在不同数学相关频率下发生的声音振动的组合。这些在不同频率下的振动组合元素被称为谐波或部分波。例如,如果我们按下钢琴上的中央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)。
以下是我设计的一种不寻常的两阶段算法的 C++ 源代码,在 GitHub.com 上,可以实现对 Windows 上播放的多声部 MP3 文件进行实时音高检测。这个免费应用程序(PitchScope Player,可在网上获取)经常用于检测吉他或萨克斯风独奏录音中的音符。你可以下载 Windows 可执行文件,选择 mp3 文件来观察我的算法在工作中的情况。该算法旨在检测 MP3 或 WAV 音乐文件中任何时刻最显著的音高(一个音符)。在 MP3 录音期间,通过改变任何时刻最显著的音高(一个音符)来准确推断出音符的起始点。
我使用修改后的 DFT 对数变换(类似于 FFT)首先检测这些可能的谐波,通过查找峰值水平的频率来实现(请参见下面的图表)。由于我收集修改后的 Log DFT 的数据方式,因此不需要对信号应用窗函数,也不需要添加和重叠。我还创建了 DFT,使其频道以对数方式定位,以直接与吉他、萨克斯等乐器上的音符产生谐波的频率对齐。
我的音高检测算法实际上是一个两阶段过程:a) 首先检测“音阶”(“音阶”有12个可能的音高值:{E、F、F#、G、G#、A、A#、B、C、C#、D、D#});b) 确定“八度”,通过检查所有4个可能的八度候选音符的谐波来计算。该算法旨在检测多声部 MP3 文件中任何时刻最显著的音高(一个音符)。这通常对应于器乐独奏的音符。那些对我两阶段音高检测算法的 C++ 源代码感兴趣的人可能想从 GitHub.com 的 SPitchCalc.cpp 文件中的 Estimate_ScalePitch() 函数开始。

https://github.com/CreativeDetectors/PitchScope_Player

https://en.wikipedia.org/wiki/Transcription_(music)#Pitch_detection

enter image description here


这很有趣,但是你的描述有些令人困惑。你强调你的算法可以处理“多声部mp3文件”,但你所描述的算法只能检测到单个音高,这与OP的要求不符。单一音高检测算法已经相当普遍,并且已经存在了几十年。每个音乐商店出售的数字调音器都使用类似于你所描述的方法来实现这样的算法。你的算法有何不同之处? - Cerin

1
可能需要一款吉他拾音器来分离每个弦,否则分离所有泛音可能会是一个非常困难的问题。

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