ビートとダウンビート
ビートは音楽の中で知覚される拍の位置です。ダウンビートは小節の最初の拍、つまり拍子を支える強い「1」です。libsonare はビート検出とダウンビート検出の両方を時刻配列として公開します。
ビート・ダウンビート・小節
ビートは単一の拍です。足で刻むもの、と考えると分かりやすくなります。
小節は決まった数の拍をまとめたものです。拍子がその数を表します。4/4 なら 1 小節は 4 拍です。
ダウンビートは各小節の最初の拍で、サイクルの始まりとして感じるアクセントです。ビート追跡はグリッドを与え、ダウンビート検出はグリッドがどこで繰り返し始まるかを示します。ループ・歌詞・セクションをそろえる先はこのダウンビートです。
ビートが 60/BPM の等間隔グリッドでは済まない理由
テンポが分かればビートは自明で、タイムラインを等分するだけに見えます。実際の音楽はそうなっていません。テンポは揺れ、奏者は前後に押し引きし、イントロはルバート(テンポを自由に伸び縮みさせる演奏)で、オンセットはノイジーです。素朴な等間隔は演奏とすぐ位相がずれるため、ビート追跡は最適化問題を解きます。強いオンセットにそろい、かつテンポ付近でほぼ一定の間隔を保つビート時刻を見つけます。動的計画法は、最も近いオンセットへ貪欲に吸着して誤差をためるのではなく、全体で最も整合する置き方を選びます。
ビート追跡
ビート追跡は、オンセット強度包絡線とテンポ推定から始まります。トラッカーはオンセット根拠の強いフレームを評価し、期待される拍周期に近い間隔を保つ列を動的計画法で選びます。
ネイティブ設定で適応テンポ(adaptive tempo)が有効な場合は、急なジャンプにペナルティを与えつつ、局所的な周期変化にも追従します。ただしこれは拍の推定であり、スコアレベルの採譜ではありません。
固定されたグリッドではなく、ビートが鎖のようにつながったものを思い浮かべてください。隣り合うビートの間隔は少し伸び縮みできますが、期待される拍周期からずれるほど減点されます(減点はずれの 2 乗に比例し、tightness で重み付けされます)。一方、強いオンセットに乗ったビートは加点されます。トラッカーは曲全体で考えられる鎖をすべて採点して最良のものを残すので、1 つのビートを近くの音に合わせるのは、その前後の間隔が妥当なままのときだけです。
ダウンビート追跡
ダウンビートは、ビートを置いた後で推定されます。libsonare は拍子の位相を推定し、ビート強度、低域エネルギー、位相の事前情報を使って各拍位置を採点します。そのためダウンビート結果は、通常のビート追跡よりもアレンジ上の手がかりに左右されます。
コード変化も 4 つめの手がかりになりますが、これはコードが分かってからでないと使えません。曲全体を解析する経路はコードを検出したうえで、その根拠を加えてダウンビートをもう一度補正します。単体の detectDownbeats はこの段階まで進みません。ダウンビートの位置が重要で、かつアレンジの中でハーモニーが最も明確な手がかりである場合は、曲全体の解析を呼んでください。
疎なイントロ、アウフタクト(小節の頭より前から入る弱起)、弱いベース、曖昧な拍子では、知覚される「1」がずれることがあります。UI では絶対的な答えではなく、補助的なオーバーレイとして見せるのが適切です。
ビート追跡が「拍がどこか」を答えるのに対し、ダウンビート追跡は「どの拍が小節の頭か」を答えます。前者は規則的な目盛りだけで決まりますが、後者は低音やコードチェンジといった音楽的なアクセントに頼るため、外れやすい一段上の推定です。
判断の根拠となるデータ
ダウンビート推定が採点している根拠そのものは AnalysisResult.beatObservations として公開されています。拍子やアクセントの処理を自前で書く場合も、弱い近似を作り直さずライブラリと同じ値を採点できます。空でない各系列はビート 1 つにつき 1 要素を持ち、beats と並行に並びます。内訳は onsetStrength、lowFrequencyEnergy(対数スペクトル差分が捨ててしまうアクセント根拠。音声なしで解析した場合は空)、chordChange(コード解析が済むまで空)です。系列が空なのは「その解析では作れなかった」という意味で、全ビートが 0 点だったという意味ではありません。
beat.strength と beatObservations.onsetStrength は別の測定値
ビートが持つ strength は、そのビートの 1 フレームで標本化したオンセット包絡線の値です。生の値で上限がなく、スケールは素材に依存し、ビート位置のわずかなぶれでも動きます。曲をまたいだ比較には使えず、アクセントの手がかりとしてもノイジーです。
onsetStrength は同じ包絡線をビート周辺の窓で集約した値で、ライブラリ自身のダウンビート処理が採点しているのはこちらです。アクセントにはこちらを使い、strength は診断用として扱ってください。
libsonare がどう計算するか
BeatAnalyzer はメル由来のオンセット強度を計算し、BpmAnalyzer で BPM を推定して、候補フレーム上の動的計画法でビートを追跡します。その後、オンセット強度、低域エネルギー、拍子位相を含む内部構造体 DownbeatObservations でダウンビートを補正します。この時点ではコード変化の項は空で、MusicAnalyzer がコード検出のあとに同じ補正をもう一度呼び出して埋めます。公開されている beatObservations は同じ 3 系列を解析結果として持ち出したもので、この内部構造体そのものではありません。detectBeats や detectDownbeats などの公開ヘルパーは、秒単位の Float32Array / float 配列を返し、コードを使わない 1 回目の補正で止まります。