Skip to content

ストリーミング解析

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

libsonare の StreamAnalyzer は、同じ MIR パイプラインを逐次的に実行します。ビジュアライザーやライブ表示向けに、フレーム単位の特徴量と逐次的な音楽推定を出力します。

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

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

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

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

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

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

逐次推定: 暫定から安定へ

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

量子化された読み出し

フレームは process() 呼び出しの間にバッファへたまります。1 ブロックにつき 1 フレームを期待するのではなく、利用可能な分をまとめて読み出して描画します。この量子化された読み出しモデルは音声コールバックを軽く保ち(バッファするだけ)、レートの揺らぐフレーム処理を、ジッタが無害な UI ループへ移します。

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

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

呼び出し役割
readFrames(availableFrames())バッファされたメル/クロマ/オンセット/スペクトルのフレームを排出
stats()updated フラグ付きで逐次的な BPM/キー/コード/進行/パターン推定を返す
emitEveryNFramesUI 描画向けにフレーム出力を間引く

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

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