我正在将Meinard müller和Sebastien Ewert的Matlab"Chroma Toolbox"改编并扩展为python。它旨在检测音频记录的每个分析帧中存在的音高。
第一步是确定音乐的调谐,Chroma Toolbox测试音乐是在标准A=440Hz下调谐,还是在半音的四分之一、三分之一、一半、三分之二或四分之三下调谐。这没关系,但在我的应用程序中,我需要在调优检测方面有更高的分辨率。
一旦从这些选择中的一个中选择了调谐,就选择了相应的滤波器组,该滤波器组用于找出在钢琴的范围内每个音高处有多少能量。(此外,波形被重新采样到22050、4410和882Hz)
滤波器组的系数存储在由Chroma Toolbox提供的.mat文件中。例如,用于检测标准调谐中间C(261.63Hz)处的能量的系数为b=[1.,-7.43749873,24.72954997,-47.94740681,59.25189976,-47.77885707、24.55599193、-7.35933913、0.98601284]和a=[000314443、-0.02341175、0.07794208、-0.115134062、0.18733283、-0.1151340 62、0.0779420 8、-0.0234117、0.003414443],中间C的采样率为4410 Hz。
这些系数用于对filtfilt的调用:我使用scipy.signal.filt(b,a,x),其中x是适当采样频率下的波形,低音为低,高音为高。此步骤在文件"audio_to_pitch_via_FB.m"中完成。
问题:
因为我想允许与Chroma工具箱中设计的调谐级别不同的调谐级别,所以我需要制作自己的滤波器组,因此需要知道如何计算滤波器系数。为此,我需要一个函数coeffs(freq,fs),它将找到正确的系数,以找到给定频率freq下的能量,用于采样频率fs的信号。我该怎么做?
这是其中一个.mat文件的名称,以防它包含有用的线索。"MIDI_FB_ellip_pitch_60_96_22050_Q25_minusQuarter.mat"
生成过滤器的代码位于generateMultiratePitchFilterbank.m文件中。ellip函数以相反的方式返回a和b,但在其他方面基本相同。
以下配方再现了您引用的数字:
import numpy as np
import scipy.signal as ss
def coeffs(pitch, fs, Q=25, stop=2, Rp=1, Rs=50):
"""Calculate filter coeffs for a given pitch and sampling rate, fs.
See their source code for description of Q, stop, Rp, Rs"""
nyq = fs/2. # Nyquist frequency
pass_rel = 1/(2.*Q)
stop_rel = pass_rel * stop
# The min-max edges of the pass band
Wp = np.array([pitch - pass_rel*pitch, pitch+pass_rel*pitch])/nyq
# And the stop band(s)
Ws = np.array([pitch - stop_rel*pitch, pitch+stop_rel*pitch])/nyq
# Get the order, natural freq
n, Wn = ss.ellipord(Wp, Ws, Rp, Rs)
# Get a and b:
a, b = ss.ellip(n, Rp, Rs, Wn, btype="bandpass")
return a, b