C/C++/Obj-C实时算法,用于确定人声输入中的音符(非音高)

P i*_*P i 3 iphone algorithm signal-processing detection pitch

我想要检测的不是音高,而是发出唱音的音高等级.

因此,无论是C4还是C5都不重要:它们必须都被检测为C.

想象一下,12个半音安排在钟面上,针指向音高等级.这就是我追求的!理想情况下,我希望能够分辨出唱歌音符是点亮还是稍微偏离.

这与先前提出的问题不重复,因为它引入了以下约束条件:

  1. 声源是一个人的声音,希望背景干扰可以忽略不计(虽然我可能需要处理这个问题)

  2. 八度音阶并不重要,只有音高等级

编辑 - 链接:
实时音高检测
使用Apple FFT和加速框架

Kpm*_*y91 7

见我的答案在这里为获得平滑的频率检测:/sf/answers/772978601/

至于将此频率捕捉到最近的音符 - 这是我为调谐器应用创建的方法:

- (int) snapFreqToMIDI: (float) frequencyy {

    int midiNote = (12*(log10(frequencyy/referenceA)/log10(2)) + 57) + 0.5;
    return midiNote;
}
Run Code Online (Sandbox Code Playgroud)

这将返回MIDI音符值(http://www.phys.unsw.edu.au/jw/notes.html)

为了从此MIDI音符值中获取字符串:

- (NSString*) midiToString: (int) midiNote {
    NSArray *noteStrings = [[NSArray alloc] initWithObjects:@"C", @"C#", @"D", @"D#", @"E", @"F", @"F#", @"G", @"G#", @"A", @"A#", @"B", nil];
    return [noteStrings objectAtIndex:midiNote%12];
}
Run Code Online (Sandbox Code Playgroud)

有关使用输出平滑的音调检测的示例实现,请查看musicianskit.com/developer.php


hot*_*aw2 6

音高是人类的心理感知现象.峰值频率含量与音高或音高等级不同.FFT和DFT方法不会直接提供音调,只提供频率.零交叉测量也不适用于人类语音源.尝试AMDF,ASDF,自相关或倒谱法.关于音高估计的主题也有很多学术论文.

这里还有一长串音高估计算法.

编辑补充:Apple的SpeakHere和aurioTouch示例应用程序(可从其iOS开发中心获得)包含从iPhone麦克风获取PCM样本块的示例源代码.


joh*_*yrd 5

其他答案中引用的大多数频率检测算法都不适用于语音。要直观地理解为什么会出现这种情况,请考虑一种语言中的所有元音都可以用一个特定的音符来演唱。尽管所有这些元音具有非常不同的频率内容,但它们都必须被检测为相同的音符。任何语音音符检测算法都必须以某种方式考虑到这一点。此外,人类的言语和歌曲包含许多摩擦音,其中许多没有隐含的音高。

在通用(非语音情况)中,您正在寻找的功能称为色度功能,并且关于该主题有相当多的工作。它相当于谐波音级曲线。关于这个概念的原始参考论文是 Tayuka Fujishima 的“音乐声音的实时和弦识别:使用 Common Lisp 音乐的系统”。维基百科条目概述了该算法的更现代的变体。有大量关于色度特征检测的免费论文和 MATLAB 实现

然而,由于您只关注人声,并且人声自然包含大量泛音,因此在这个特定场景中您实际上需要的是基频检测算法,或f0 检测算法。有几种这样的算法明确针对语音进行了调整。此外,这里还有一个被广泛引用的算法,可以同时处理多个语音。然后,您将根据等律音阶检查检测到的频率,然后找到最接近的匹配。

由于我怀疑您正在尝试构建一个自动调谐的音调检测器和/或校正器,因此您可能需要使用 M. Morise 出色的WORLD实现,它允许对语音流上的 f0 进行快速且高质量的检测和修改。

最后,请注意,只有少数音高检测器可以在人声音域中正常工作。几乎所有这些,包括 WORLD,在声音炸裂和非常低的声音方面都失败了。许多论文将发声弗莱称为“吱吱作响的声音”,并开发了特定的算法来专门帮助处理这种类型的语音输入。