オンセット検出
オンセットは、音楽的イベントが始まる瞬間です — 弾かれた音、叩かれたドラム、歌われた子音。オンセットを見つけることはリズムファミリー全体の根で、テンポ、ビート、さらにはセクション境界もすべてオンセット情報から育ちます。本ページは MIR の全体像 のタイミングの節を掘り下げます。
オンセット・トランジェント・ビートの違い
この 3 つは混同しやすいです。
- オンセットは、ビートに乗るかどうかに関わらず、あらゆる音イベントの始まりです。
- トランジェントは、音の先頭にある短く高エネルギーの立ち上がり(スティックがドラムに当たる瞬間)です。オンセットはトランジェントやその他のスペクトル変化から検出されます。
- ビートは音楽の知覚される拍です。ビートは通常オンセットと一致しますが、すべてのオンセットがビートではありません(速いドラムフィルは 2 拍の間に多くのオンセットを持ちます)。
つまりパイプラインは、スペクトル変化 → オンセット → テンポ/ビート、です。
実例で考えると、スネアを 1 回叩いた瞬間はオンセットです。その直後の鋭い「パチッ」という立ち上がりがトランジェントです。曲全体で 1、2、3、4 と感じる規則的な拍がビートです。速いフィルではオンセットはたくさん出ますが、ビートはその一部だけです。
オンセット強度包絡線
libsonare はオンセット時刻のリストを出すだけではありません。まずオンセット強度包絡線、つまりスペクトルが急変するところで立ち上がる連続曲線を計算します。
この曲線は、フレーム間の帯域ごとのレベル上昇を測って作ります。これはスペクトルフラックスの考え方で、libsonare はメル帯域ごとにデシベルで差分を取るため、静かな箇所が大音量の箇所に埋もれません。新しいエネルギーが現れると曲線が跳ね、持続音の間は低いままです。
この包絡線のピークが、候補のオンセットです。
包絡線が重要なのは、ピークのリストだけでなく曲線の形状こそ、テンポやビートのアルゴリズムが解析するものだからです。くっきりとピークの立った曲線は自信のあるテンポ推定を与え、にじんだ曲線は与えません。
ピーク拾い(どの山を実際のオンセットとみなすか)はしきい値と最小間隔に依存します。間隔を詰めすぎると 1 つの打撃を二重に数え、緩めすぎると速いフィルを取りこぼします。リズムが密な素材ほど、この調整が結果を左右します。
オンセット検出の結果が多すぎるときは、細かいノイズや余韻までイベントとして拾っている可能性があります。少なすぎるときは、しきい値が高すぎるか、素材の立ち上がりが柔らかく、スペクトル変化が目立たない可能性があります。
なぜこれがテンポとビートに効くのか
安定したグルーヴはオンセット包絡線を周期的にします — ピークがほぼ等間隔で繰り返されます。テンポ推定はその周期を探し、ビート追跡はピークの上に拍の列を置きます。両者は同じ包絡線を読むため、オンセット検出を改善するとテンポとビートの精度が同時に上がります。
libsonare がオンセット強度をどう計算するか
OnsetAnalyzer は STFT 振幅ではなくメルスペクトログラムから包絡線を導きます。メル段は省略できません。メルパワーをデシベルへ変換し(ピークから 80 dB 下でクリップ)、1 つ前のフレームとの差分(lag = 1)を半波整流し、残った正の差分をメル帯域方向に平均して 1 本の曲線にします。デシベルで差分を取るため、曲線は比の変化に反応し、静かな箇所でも大音量の箇所と同程度のピークが立ちます。これを線形の振幅で再実装すると、大音量の区間ばかりが目立つ曲線になります。STFT 振幅の L1 スペクトルフラックスは spectralFlux() という別のヘルパーが提供しますが、オンセット・BPM・ビートに使われるのはそちらではありません。
OnsetConfig は差分のラグ(lag = 1 フレーム)、ゆるやかなベースラインを取り除く detrend、各値をフレーム中央へそろえる center などを公開します。
この包絡線は BpmAnalyzer のテンポグラムと BeatAnalyzer のビート追跡(動的計画法)で使われ、オンセットに反応する動きを作りたいビジュアライザー向けに onsetEnvelope() としても公開されます。
自分で取得した包絡線と、検出器が使う包絡線は同じではありません
OnsetConfig.detrend の既定は false で、librosa.onset.onset_strength に合わせてあります。一方、オンセット・BPM・ビートの各アナライザーは内部でこれを true にします。ゆるやかなベースラインを引くとピーク検出が鋭くなるためです。したがって onsetEnvelope() で自分が取得する曲線には、検出器側ではすでに除去されているベースラインの変動が残っています。両者の形は一致しないので、片方で調整したしきい値をもう片方に流用しないでください。