テンポと BPM
テンポは音楽の体感的な速さで、BPM(beats per minute、1 分あたりの拍数)で測ります。120 BPM は 1 秒に 2 拍です。libsonare はビートを直接数えるのではなく、オンセット強度包絡線 の周期性から推定します。本ページは MIR の全体像 のタイミングの節を掘り下げます。
オンセットからテンポへ
音楽に安定した拍があれば、そのオンセット包絡線は周期的で、ピークが等間隔で繰り返されます。テンポ推定はその間隔を測ります。標準的な手段が 2 つあります。
- 自己相関は、オンセット包絡線を時間シフトした複製と突き合わせ、各ラグでどれだけ一致するかを測ります。曲線が自分自身とそろうラグが繰り返し周期を示し、その周期は直接 BPM に変換できます。
- テンポグラムはそれを画像にします。各時点での候補テンポの強さを示す、時間×テンポの地図です。強い水平の帯は安定したテンポ、ずれていく帯は加速・減速する曲を示します。
単純に言えば、テンポ推定は「山と山の間隔がどれくらいか」を探しています。山が 0.5 秒ごとに来るなら 1 秒に 2 拍、つまり 120 BPM です。実際の曲では山が完全に等間隔ではないため、自己相関やテンポグラムで、もっとも説得力のある間隔を選びます。
オクターブ誤り: テンポ推定の定番の罠
テンポ推定の結果は、「本当の」テンポの半分や 2 倍になりやすいことでよく知られています。75 BPM が 150 と報告されたり、140 が 70 になったりします。これはバグではなく、本当に曖昧なのです。同じグルーヴに合わせて手を叩くリスナーは、ハーフタイムでもダブルタイムでも妥当に叩けますし、周期性は両方を支持します。こうした誤りは(ピッチのオクターブになぞらえて)オクターブ誤りと呼ばれます。
曖昧さは 2 倍・半分だけにとどまりません。3 連系の関係も同じくらいよく起きます。シャッフルや 6/8 のグルーヴは、聴き手が刻むテンポの 2/3 や 3/2 として報告されがちです。libsonare の倍音クラスタリングも、推定値そのものと並べて 1/2、2/3、3/4、4/3、3/2、2、3、4 の比率を検討します。
libsonare は 80〜180 BPM を優先します
30〜300 BPM の探索範囲の中でも、推定器はすべてのオクターブを同じには扱いません。候補テンポを倍音関係ごとのクラスターにまとめ、最も支持の多いクラスターを選び、そのクラスターの中に十分な支持を持つ 80〜180 BPM のメンバーがあればそれを報告します(なければ 60〜200 BPM のメンバー)。そのため、半分や 1/3 のテンポにも根拠がある速いテンポは、その遅い関係のテンポで報告されます。合成したクリックトラックでは、200 BPM と 240 BPM がそれぞれ約 100 と 80 になります。一方、より速い関係のテンポに根拠がなければ遅いテンポはそのまま残り、60 BPM のクリックトラックは 60 と読まれます。速いテンポをそのまま報告させたいときは、analyzeBpm(...) の bpmMin を遅い関係のテンポより上に設定します。bpmMin: 150 なら、200 BPM と 240 BPM のトラックはそれぞれ約 199 と 238 になります。detectBpm(...) は範囲を受け取りません。
実用的な対処は、素材に応じた妥当な BPM 範囲を選び(ポップスなら 70〜180 など)、推定値を確定した正解ではなく、3 連系も含めて拍節的に関係し合う候補のうちの 1 つとして扱うことです。特にストリームの序盤、十分な音声がたまる前は注意が必要です。
UI に表示する場合は、候補を 1 つだけ断定するより、「120 BPM 付近、または 60 BPM / 180 BPM / 240 BPM の可能性」といった扱いのほうが安全です。イントロだけ、ドラムなし、ライブ演奏、テンポが揺れる曲では、最初の数秒の値を確定値として使わないでください。
信頼度と安定性
BPM の数値 1 つでは、推定がどれだけ確かかは分かりません。きっちり反復するグルーヴの曲では周期性の根拠が 1 つのテンポ系列に集まり、ルバート(テンポを自由に伸び縮みさせる演奏)・アンビエント・まばらな素材では互いに無関係なテンポへ散らばります。
bpmConfidence(analyze(...))と confidence(analyzeBpm(...))が測っているのは、まさにこの散らばりです。自己相関の各ピークがその強さに応じた重みで自分のテンポに票を入れ、票は倍音関係のクラスターにまとめられます。信頼度は、全票のうち勝ったクラスターに入った票の割合で、範囲は [0, 1] です。ここから次のことが言えます。
- 倍音関係のテンポは同じクラスターに入るので、ハーフタイムやダブルタイムの読みでも値は下がりません。
- 値が示すのは根拠がどれだけ一致していたかで、聴き手が刻むテンポと一致する確率ではありません。
- フォールバックは固定値です。測るのに十分な音声がなければ
0、局所テンポ曲線だけが答えを出した場合は0.25になります。
BPM を表示するか、ぼかすか、隠すかの判断に使ってください。候補ごとの confidence は別の数値で、そのテンポのビン自身の得票率です。analyzeBpm(...) は candidates の先頭に選んだテンポを置き、残りを得票率の順に並べるため、より大きな得票率のビンがほかにあっても candidates[0] が報告される bpm です(120 BPM のクリックトラックは 119.7 を先頭に報告し、続いて得票率 0.40 の 60 BPM のビンが来ます。119.7 のビン自身は 0.30 です)。
libsonare がテンポをどう推定するか
BpmAnalyzer はメルベースのオンセット強度包絡線を読み、その自己相関を計算します。探索範囲内の自己相関ピークはそれぞれ重み付きの票としてテンポのヒストグラムに入り、上位のビンが倍音関係のクラスターにまとめられます。代表テンポは、最良のクラスターの中から前述の 80〜180/60〜200 BPM の優先順位で選ばれます。同じ包絡線の Fourier テンポグラム(TempogramConfig)は局所テンポ曲線を与え、自己相関にピークが見つからないときだけそれが答えになります。なお TempogramMode は単体の tempogram() 特徴量が自己相関とコサイン類似度のどちらを使うかを選ぶもので、BPM 推定には影響しません。
| 項目 | 内容 |
|---|---|
| 探索範囲 | bpm_min = 30、bpm_max = 300 |
| 初期値 | フォールバックの start_bpm = 120 |
| オンセット設定 | n_fft = 2048/hop_length = 512 |
| 候補 | BpmCandidate により、半分/2 倍の候補も後段で扱える |
ストリーミングアナライザーの BPM は、音声が届くにつれて更新され、少しずつ精緻化します。序盤の値は暫定として扱ってください。BeatAnalyzer は個々のビートを置く際にテンポを事前情報として使うので、テンポとビートは独立にではなく同じオンセット情報から計算されます。