Skip to content

ストリーミング解析

オフライン解析はファイル全体を一度に見ます。ストリーミング解析は音声を一塊ずつ見て、進みながら結果を出さねばなりません。

libsonare の StreamAnalyzer は、同じ MIR(Music Information Retrieval、音楽情報検索) のパイプラインを少しずつ実行します。ビジュアライザーやライブ表示向けに、フレーム単位の特徴量と、音声が増えるほど更新されていく音楽推定を出力します。

使うのは、マイク・AudioWorklet・再生グラフなどから音声がライブで届き、メーターやスペクトログラム、進行中の BPM/キー推定をリアルタイムに更新したいときです。すでに全体が手元にある固定ファイルなら、バッチ(オフライン)解析のほうが簡潔で精度も高くなります。

本ページではストリーミングの考え方を説明します。API のレシピは リアルタイムとストリーミング を参照してください。

DETECTOR · ONSET / BEATIDLE
オンセットとビート — 打点から拍へ

オンセット検出は音の打点をすべて捉え、ビート追跡はそこから手拍子を打つような一定の拍を導き出す。表示を切り替え、再生するとプレイヘッドが到達するたびにマーカーが光る。

検出

ブロック・フレーム・ホップ・nFft — 混同しやすい 4 つ

混同しやすい 4 語で、取り違えがストリーミングのバグの多くを生みます。

  • ブロック(チャンク) — ホストがコールバックごとに渡すサンプルの塊(AudioWorklet なら 128 や 512 サンプルなど)。サイズは音声システムが決め、あなたは決めません。
  • フレームSTFT(short-time Fourier transform、短時間フーリエ変換) の解析窓 1 つ分の出力。サイズ次第で、アナライザーは 1 ブロックにつき複数フレームを出すことも、0 のこともあります。
  • ホップhopLength) — フレーム間で解析窓を進める量。ブロックサイズとは独立にフレームレートを決めます。
  • nFft — 解析窓のサイズ。大きいほど周波数が細かく、時間は粗くなります。

あなたはブロックを流し込み、フレームを読み出します。2 つのレートは切り離されており、だからこそアナライザーは内部でバッファします。

更新されていく推定: 暫定から安定へ

音楽推定 — BPM、キー、現在のコード、進行、パターン — は、音声が届くにつれて少しずつ精緻化します。ストリームの最初の 1 秒には自信のある BPM に足る根拠がないため、序盤の値は暫定として見せる(または隠す)べきで、後から修正されることを許容します。最初のフレームを確定として扱うのが、ストリーミングの典型的なミスです。

フレームはまとめて読み出す

フレームは process() 呼び出しの間にバッファへたまります。1 ブロックにつき 1 フレームを期待するのではなく、利用可能な分をまとめて読み出して描画します。このまとめ読みの形にすると、音声コールバックは軽く保てます(バッファするだけ)。フレーム数が揺れる処理は、多少の揺れが問題になりにくい UI ループへ移せます。

API 上の「量子化」は、8 ビット/16 ビット出力でデータ量を減らす話です。タイミングをそろえる意味ではありません。

libsonare がストリーミング解析をどう行うか

StreamAnalyzersampleRatenFfthopLengthnMelscompute* フラグで一度構築し、process() でブロックを与えます。

呼び出し役割
readFrames(availableFrames())バッファされたメル/クロマ/オンセット/スペクトルのフレームを排出
stats()BPM/キー/コード/進行/パターンの推定を返す。updated はキーまたは BPM を再計算したフレームで true になり、再計算後の値が前回と変わったフレームだけではないため、変化検出には使えない
emitEveryNFramesUI 描画向けにフレーム出力を間引く

既定サンプルレートは 44100 Hz(バッチの 22050 に対し)です。リアルタイム音声が再生/キャプチャグラフから 44100/48000 で届くため、この値にしています。オフライン解析と同じ STFT 由来の特徴量段を再利用します。

関連: リアルタイムとストリーミングスペクトログラムと STFTリアルタイムエンジンリアルタイム安全性