Wizard Notes

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

定Q変換のPython 実装のアルゴリズム/実装方法による計算速度の比較

音楽信号の音高分析に便利な定Q変換 (CQT)

これまでにいくつか計算アルゴリズムや実装方法の種類を紹介してきました。

おそらく再帰的ダウンサンプリング法が速いと思っていたのですが、条件によっては疎行列計算と変わらないことがあったりと、実環境での処理速度の違いが気になっていました。

そこで、3つのリアルタイム向け定Q変換の Python 実装と、オフライン向けであるLibROSA の定Q変換とSTFTの処理速度を比較してみました

比較環境

  • OS: Win10
  • Python環境: Anaconda

比較する手法と条件

冒頭に書いたように、比較手法は以下の5つとします。

  1. スペクトルカーネル
  2. スペクトルカーネル+疎行列計算
  3. 再帰的ダウンサンプリング法
  4. LibROSA CQT(再帰的ダウンサンプリング法+バッチ処理特化)
  5. LibROSA STFT (n_fft=8192)

1~3はリアルタイム用の実装,4, 5はバッチ処理用の実装となっています*1

1, 2 の実装は以下になります。

www.wizard-notes.com

3の実装は以下になります

www.wizard-notes.com

その他の条件は以下のように設定しました。

  • 分析する信号は90秒のJPOP楽曲
  • サンプリング周波数 44.1 kHz
  • 各手法,5回計測
  • hop_length=256
  • オクターブ数 n_octave
  • 1オクターブのビン数 n_bins_per_octave
  • 一番低い音高の周波数 fmin

比較1: 基本設定

良く使われる設定を試してみました。

  • 最も低い周波数を22.5 Hz (A0)
  • オクターブの数 8
  • 1オクターブのビン数 12

(2)疎行列計算と(3)ダウンサンプリング法であまり差がでませんでした。

この条件での疎行列計算と比べると、オクターブ分割+ローパスフィルタリングにそれなりの計算が必要なのかなという印象です。

比較2: 1オクターブあたりの周波数ビン数を増やす

1オクターブあたり24ビンにしてみました。

(1)スペクトルカーネルで疎行列計算使わないと、信号が90秒なのに処理に250秒近くかかってしまってます。。

この条件では(2)疎行列計算と(3)ダウンサンプリング法で2倍くらい差がでました。

比較3: 低周波数を分析しない場合

メロディやコード分析の場合,中~高音域のみの分析でよいケースもあります。

そこで,fminを22.5 Hzから110Hzに変え,分析するオクターブ数を8から6に変更した場合の計算量をみてみます。

こちらはどれも10秒以内に終わります。

リアルタイム向けとバッチ処理向け実装で差があまりありません。

まとめ

リアルタイム/オフライン向け定Q変換のアルゴリズム・実装の処理速度を比較してみました。

計算機、プログラミング言語、処理系で結果は変わると思いますが、Pythonでの定Q変換の処理速度の比較結果は以下のようになりました

  • リアルタイム
    • 再帰的サブサンプリング法は、1オクターブ内の周波数ビン数が多い場合に速かった
    • 1オクターブあたりのビン数が12くらいの場合や、低い音高を分析しない場合は、疎行列計算と再帰的サブサンプリング法はあまり差がなかった
    • スペクトルカーネルで疎行列計算を使わないのは実用的でない -低い音高を分析しないなら、バッチ処理との速度差は小さい
  • バッチ処理
    • librosa.cqt (librosa.vqt) でOK*2

関連ページ

www.wizard-notes.com

www.wizard-notes.com

www.wizard-notes.com

www.wizard-notes.com

www.wizard-notes.com

www.wizard-notes.com

*1:4はローパスフィルタリング+デシメーションにresampyを利用

*2:IIR-Lowpass+Decimateのオフライン向け実装した方が多少は速いかもしれません