Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

多段適応ノッチフィルタで複数の正弦波を除去/ドラム・打楽器音の抽出(Python実装)

前回の記事では、適応ノッチフィルタを使って音高が未知の正弦波を除去しました.

www.wizard-notes.com

しかし、正弦波が複数ある区間ではうまく動作しませんでした

そこで、今回は複数の正弦波を除去できる、多段適応ノッチフィルタを紹介します。

また、多段適応ノッチフィルタの活用方法としてドラム・打楽器音を抽出してみます。

多段適応ノッチフィルタの構成

[px]

構成方法としては、任意の数の適応ノッチフィルタを直列で接続すればOKです。

基本的には、接続した適応ノッチフィルタの数だけパワーの大きいサイン波を除去できます

しかし、適応ノッチフィルタの数が除去したいサイン波の数を超えている場合、所望信号の周波数成分を削ってしまい音質が劣化する恐れがあります。

実装

前回実装したAdaptiveNotchFilterクラスを単純に直列接続しています。

if __name__ == "__main__":
    filepath = "./music.wav"
    savefilepath = "./save.wav"
    sig, sr = sf.read(filepath, always_2d=True)

    M = 8 #16 #32
    anf_list = [[AdaptiveNotchFilter(sr), AdaptiveNotchFilter(sr)] for m in range(M)]

    current_frame = 0
    blocksize = 512
    tmpdata = np.zeros((blocksize, sig.shape[1]))
    tmpdata2 = np.zeros((blocksize, sig.shape[1]))
    savedata = np.zeros(sig.shape)

    def callback(outdata, frames, time, status):
        global current_frame, tmpdata, tmpdata2, anf, anf_list
        chunksize = min(sig.shape[0] - current_frame, frames)
        tmpdata[:] *= 0.0
        tmpdata[0:chunksize] = sig[current_frame:current_frame + chunksize]

        for m in range(M):
            for k in range(outdata.shape[1]):
                anf_list[m][k].online(tmpdata[:,k], tmpdata2[:,k])
            tmpdata[:] = tmpdata2
            tmpdata2[:] *= 0.0
        outdata[:] = tmpdata
        
        if chunksize < frames:
            raise sd.CallbackStop()
        else:
            savedata[current_frame:current_frame + chunksize] = outdata[:]
        current_frame += chunksize


    event = threading.Event()
    with sd.OutputStream(
        samplerate=sr, 
        blocksize=blocksize,
        channels=sig.shape[1],
        callback=callback,
        finished_callback=event.set
    ):
        event.wait()
        
    sf.write(savefilepath, savedata, sr)

適用結果

■正弦波1~2本+白色雑音(前回の記事の音源

www.youtube.com

まず、前回と同じ「正弦波1~2本+白色雑音」の音源に適用してみました。

適応ノッチフィルタの数は 8 としています。

上図は入力信号の波形・スペクトログラム、下図がフィルタリング後の信号の波形・スペクトログラムです。

前回は2つの正弦波が同時になっている区間ではうまく除去できていませんでしたが、今回は除去できていることが確認できます。

オルゴール 次に、正弦波として除去できそうな楽器音であるオルゴールの音で試してみました。

適応ノッチフィルタの数は 8 としています。

こちらも綺麗に除去できており、鳴り始めのアタック音のみ残っています。

■楽曲 (白亜の庭園、白昼の夢) 最後に、楽曲信号に対して多段適応ノッチフィルタを適用できるか試してみました。

適応ノッチフィルタの数は 8, 16, 32 の3パターンを比較しました。

予想通り、適応ノッチフィルタの数が増えるほど打楽器的な音のみが残りますが、音質の劣化も確認できます。

まとめ

多段適応ノッチフィルタで複数の正弦波を除去/ドラムや打楽器音の抽出を試してみました。

C言語でのプログラミングやチューニングのコツについては、プログラム101付き 音声信号処理 が参考になると思います。