2

Meinard Müller と Sebastien Ewert によるMatlab の " Chroma Toolbox " を Python に適応させて拡張しています。オーディオ録音の各分析フレームにどのような音楽ピッチが存在するかを検出することを目的としています。

最初のステップは、音楽のチューニングを決定することです。クロマ ツールボックスは、音楽が標準の A=440Hz でチューニングされているかどうか、または半音の 4 分の 1、3 分の 1、半分、3 分の 2、または 4 分の 3 でチューニングされているかどうかをテストします。それは問題ありませんが、私のアプリケーションでは、チューニング検出でより多くの解像度が必要です。

これらの選択肢の 1 つからチューニングが選択されると、対応するフィルターバンクが選択されます。これは、ピアノの音域全体で各音楽ピッチにどれだけのエネルギーがあるかを見つけるために使用されます。(また、波形は 22050、4410、および 882 Hz にリサンプリングされます)

フィルターバンクの係数は、Chroma Toolbox によって提供される .mat ファイルに保存されます。たとえば、標準チューニングされた中央 C (261.63 Hz) でエネルギーを検出するための係数は、b = [ 1.、-7.43749873、24.72954997、-47.94740681、59.25189976、-47.77885707、24.55599193、-7.35933913、a3 = 1.404] および 0 2.986 です。 、-0.02341175、0.07794208、-0.15134062、0.18733283、-0.15134062、0.07794208、-0.02341175、0.00314443]、中央 C のサンプルレートは 4410 Hz です。

これらの係数は filtfilt の呼び出しで使用されます: scipy.signal.filtfilt(b, a, x) を使用します。ここで、x は適切なサンプリング周波数での波形です。低い音は低く、高い音は高くなります。このステップは、ファイル「audio_to_pitch_via_FB.m」で行われます。

質問:

Chroma Toolbox に設計されているものとは異なる調整レベルを許可したいので、独自のフィルターバンクを作成する必要があり、フィルター係数の計算方法を知る必要があります。そのためには、関数coeffs(freq, fs)が必要です。この関数は、サンプル周波数fsの信号に対して、特定の周波数freqでエネルギーを見つけるための適切な係数を見つけます。どうすればいいのですか?

有用な手がかりが含まれている場合に備えて、.mat ファイルの 1 つの名前を次に示します。"MIDI_FB_ellip_pitch_60_96_22050_Q25_minusQuarter.mat"

4

1 に答える 1

2

フィルターを生成するコードは、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
于 2013-07-25T10:12:33.353 に答える