Librosa 音调跟踪 - STFT

Librosa pitch tracking - STFT

我正在使用 this 算法来检测 this 音频文件。正如您所听到的,这是在吉他上弹奏的 E2 音符,背景中有一点噪音。

我使用 STFT 生成了这个频谱图:

我正在使用上面链接的算法,如下所示:

y, sr = librosa.load(filename, sr=40000)
pitches, magnitudes = librosa.core.piptrack(y=y, sr=sr, fmin=75, fmax=1600)

np.set_printoptions(threshold=np.nan)
print pitches[np.nonzero(pitches)]

因此,我几乎获得了 fminfmax 之间所有可能的频率。我与 piptrack 方法的输出有什么关系来发现时间范围的基频?

更新

不过,我仍然不确定那些二维数组代表什么。假设我想知道第 5 帧中的 82Hz 有多强。我可以使用 STFT 函数来做到这一点,它只是 returns 一个二维矩阵(用于绘制频谱图)。

但是,piptrack 做了一些额外的事情,这可能很有用,但我不太明白是什么。 pitches[f, t] contains instantaneous frequency at bin f, time t。这是否意味着,如果我想在时间帧 t 找到最大频率,我必须:

  1. 转到magnitudes[][t]数组,找到最大的bin 震级。
  2. 将 bin 分配给变量 f
  3. 查找 pitches[b][t] 以查找属于该 bin 的频率?

音高检测是一个棘手的话题,而且通常是违反直觉的。我对这个特定功能的源代码记录方式并不感兴趣——开发人员似乎混淆了 'harmonic' 和 'pitch'。

当在吉他或钢琴上发出单音符('pitch')时,我们听到的不仅仅是一种声音振动频率,而是一种复合以不同的数学相关频率发生的多种声音振动的集合,称为谐波。典型的音调跟踪技术包括在 FFT 结果中搜索与预期的谐波频率相对应的特定区间中的幅度。例如,如果我们按下钢琴上的中央 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)。但是,谐波所在的频率是对数间隔的,而FFT使用的是线性间隔。通常,FFT 的垂直间距在较低频率下分辨率不够高。

出于这个原因,当我编写音高检测应用程序 (PitchScope Player) 时,我选择创建一个对数间隔的 DFT,而不是 FFT,这样我就可以专注于音乐感兴趣的精确频率(见附件来自 3 秒吉他独奏的自定义 DFT 图)。如果你认真地追求音高检测,你应该考虑多读读这个主题,看看其他示例代码(我的链接在下面),并考虑编写你自己的函数来测量频率。

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

https://github.com/CreativeDetectors/PitchScope_Player

原来在某一帧t选择音高的方法很简单:

def detect_pitch(y, sr, t):
  index = magnitudes[:, t].argmax()
  pitch = pitches[index, t]

  return pitch

首先通过查看magnitudes数组得到最强频率的bin,然后找到pitches[index, t]处的音高。