Wizard Notes

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

LibROSA:音楽のBPM・テンポ分析に便利なテンポグラムを数行で実装

音楽の分析方法としてBPM・テンポの分析は非常に重要です。

BPM・テンポの分析を行うことで、楽曲の雰囲気、ノリ、音楽ジャンルといった全体的な特徴を捉えることができます。

BPM・テンポの分析方法としては、テンポグラムという便利な手法があります。

テンポグラムの実装は結構難しいですが、Pythonであれば音楽分析ライブラリ LibROSA を使うことで数行で算出することができます

そこで、この記事では LibROSAを使ったテンポグラムの算出方法を紹介します。

LibROSAでのテンポグラム算出方法

テンポグラム時間-テンポ (BPM) の行列であり、楽曲の全体的・局所的なテンポ・BPMを分析するのに使われます

テンポグラムにはフーリエテンポグラム自己相関テンポグラムという2つの手法がよく知られています。それぞれ特徴があるので,やりたい分析や対象信号に応じて使い分けていくのがよいと思います。

なお、LibROSAではどちらのテンポグラムも実装されており気軽に利用することができます

フーリエテンポグラム、自己相関テンポグラムそれぞれの算出・実装方法は以下の記事にまとめていますので、ご興味がありましたらお読みください。

www.wizard-notes.com

以下では、LibROSAのフーリエテンポグラム、自己相関テンポグラムの使い方についてみていきます。

LibROSA テンポグラム

LibROSAのフーリエテンポグラム、自己相関テンポグラムはどちらも同じような引数であるため、まとめて説明します。

librosa.feature.tempogram()

librosa.feature.tempogram(y=None, sr=22050, onset_envelope=None, hop_length=512, win_length=384, center=True, window='hann', norm=inf)

librosa.feature.fourier_tempogram

librosa.feature.fourier_tempogram(y=None, sr=22050, onset_envelope=None, hop_length=512, win_length=384, center=True, window='hann')

重要な引数:

  • y: モノラルの時間信号
  • sr: サンプリング周波数
  • onset_envelope:
    • オンセットエンベロープ
    • 2次元の場合、最初の1次元ごとにテンポグラムを算出
  • hop_length:
    • どのくらい信号をずらしながらテンポグラムを算出するか
  • win_length:
    • フーリエ変換や自己相関を算出する信号の長さ
    • デフォルト:384 * hop_length / sr ~= 8.9秒

必ず必要な引数は以下のどちらかです。

  1. y, srを与える
  2. onset_envelopeを与える

  3. の場合、tempogram()内部でonset_envelopeを計算します。

オンセットエンベロープは、発音タイミングを抽出した信号です。楽曲の時間信号はそのまま使うとテンポ・リズム分析しにくいので、拍検出やリズム分析ではこのオンセットエンベロープが良く利用されます

Librosaではオンセットエンベロープを抽出できる関数librosa.onset.onset_strength() が実装されているので、1行で算出できます。

詳細は以下の記事を参考にしてください。

www.wizard-notes.com

サンプルコード

# -*- coding: utf-8 -*-
import sys
import numpy as np
import librosa
import librosa.display
import matplotlib.pyplot as plt


sr         = 22050
hop_length = 512

filepath = sys.argv[1]
y, sr = librosa.load(filepath, sr=sr)
#y, sr = librosa.load(librosa.ex('choice'))

# オンセット包絡線の算出
onset_envelope = librosa.onset.onset_strength(y=y, sr=sr, hop_length=hop_length)

# フーリエテンポグラム
fourier_tempogram  = librosa.feature.fourier_tempogram(
                        onset_envelope=onset_envelope,
                        hop_length=hop_length
                     )
# 自己相関テンポグラム
autocorr_tempogram = librosa.feature.tempogram(
                        onset_envelope=onset_envelope,
                        hop_length=hop_length
                     )              
                     
# プロット      
plt.subplots(figsize=(8.0, 4.0))        
plt.subplot(1,2,1)                    
librosa.display.specshow(np.abs(fourier_tempogram)**0.5, 
                         sr=sr, hop_length=hop_length,
                         x_axis='time', y_axis='fourier_tempo', cmap='jet')
plt.title('Fourier tempogram')

plt.subplot(1,2,2)
librosa.display.specshow(np.abs(autocorr_tempogram), 
                         sr=sr, hop_length=hop_length,
                         x_axis='time', y_axis='tempo', cmap='jet')
plt.title('Autocorrelation tempogram')      
plt.tight_layout()
plt.show()         

プロット例

米津玄師の楽曲でテンポグラムを算出してみました。

Lemon (BPM=87)

Lemon

Lemon

  • 米津玄師
  • J-Pop
  • ¥255

パプリカ (BPM=103)

パプリカ

パプリカ

  • 米津玄師
  • J-Pop
  • ¥255

ゴーゴー幽霊船 (BPM=180)

ゴーゴー幽霊船

ゴーゴー幽霊船

  • 米津玄師
  • J-Pop
  • ¥255

まとめ

LibROSAを使ったテンポグラムの算出方法を紹介しました。

なお、BPM・テンポ分析の精度や品質を上げる方法としては、テンポグラムに与える信号を加工することが考えられます。

例えば、低域/高域通過フィルタや、調波打楽器音分離 (HPSS) が有効です。

www.wizard-notes.com

また、テンポグラムからBPMを推定することも可能であり、実例としてLibROSAのBPM推定ではテンポグラムが使われています.

www.wizard-notes.com