结合Python代码介绍音符起始点检测 (onset detection)
音符起始点检测介绍
音符起始点检测(onset detection)是音乐信号处理中非常重要的一个算法。节拍和速度(tempo)的检测都会基于音符起始点的检测。
音符起始点就是其字面意思,表示琴键🎹按下的那个时刻。
音符起始点检测仍然是一个非常活跃的研究方向,MIREX的年度音乐信号处理竞赛的一个题目便是音符起始点检测。
本文里,我会结合代码,介绍一种简单的算法。
注:代码使用了Python的librosa库。
音符起始点的一个特征是,能量的突然增加,或是频谱能量分布的改变。
根据这一特征,我们可以设计如下算法。算法是在频域进行的。
算法
输入为音乐的离散时间信号,输出为所有音符起始点的时间。
1. 计算对数梅尔时频图幅度
mel = np.abs(librosa.feature.melspectrogram(y, fmax=11025))
amp_db = librosa.power_to_db(mel)
2. 计算对数梅尔时频图幅度的一阶时间差分,并计算每一帧所有频率点幅度的均值。
diff = np.maximum(amp_db[:,1:] - amp_db[:,:-1], 0.0)
onset_amp = np.mean(diff, axis=0)
3. 归一化到[0,1]之间,并进行峰值检测。
onset_my -= onset_my.min() onset_my /= onset_my.max() onset_peak = librosa.util.peak_pick(onset_my)
上图中蓝色实线表示算法中第二步所计算得到的结果,红色虚线是峰值检测后的结果。
库函数用法示例
Python的librosa库中已有音符起始点检测的函数,使用的算法便是上面介绍的算法。如果希望了解算法的一些细节以及参数的选择,可以阅读函数的源码。
下面是库函数的一个示例用法:
import librosa y, sr = librosa.load('music.mp3') onsets_frames = librosa.onset.onset_detect(y) D = librosa.stft(y) librosa.display.specshow(librosa.amplitude_to_db(D)) plt.vlines(onsets_frames, 0, sr, color='r', linestyle='--')