Skip to content

ストリーミング解析 ​

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

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

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

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

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

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

検出

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

この 4 語の取り違えが、ストリーミングのバグの多くを生みます。

  • ブロック(チャンク): ホストがコールバックごとに渡すサンプルの塊(AudioWorklet では固定のレンダークォンタムである 128 フレーム、ネイティブのコールバックでは 256〜1024 フレームがよく使われます)。サイズは音声システムが決め、呼び出し側では選べません。
  • フレーム: STFT(short-time Fourier transform、短時間フーリエ変換) の解析窓 1 つ分の出力。サイズ次第で、アナライザーは 1 ブロックにつき複数フレームを出すことも、0 のこともあります。
  • ホップ(hopLength): フレーム間で解析窓を進める量。ブロックサイズとは独立にフレームレートを決めます。
  • nFft: 解析窓のサイズ。大きいほど周波数が細かく、時間は粗くなります。44100 Hz でのサンプル数として読まれ、それより低いレートではストリームのレートに合わせて窓が縮められます(hopLength より短くはなりません)。そのため 22050 Hz のストリームでは、より小さな振幅スペクトルでフレーム数が増えます。

呼び出し側はブロックを流し込み、フレームを読み出します。2 つのレートは切り離されているので、アナライザーは内部でバッファします。

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

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

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

フレームは process() 呼び出しの間にバッファへたまります。process() はサンプルを追加し、完了したフレームごとに FFT と有効なフレーム特徴量を同期的に計算し、進行中の音楽推定も更新します。readFrames(...) はすでに公開されたフレームを消費するだけで、解析は開始しません。1 ブロックにつき 1 フレームとは限らないため、利用可能なフレームをまとめて読み出し、コピーや描画はコンシューマー側で行います。

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

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

StreamAnalyzer は sampleRate、nFft、hopLength、nMels、compute* フラグで一度構築し、process() でブロックを与えます。

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

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

コンストラクターは通常のコールバックブロック向けに作業用バッファと保留出力の容量を先に確保します。現在の実装は 16,384 サンプル分(nFft が大きい場合はそれ以上)の入力容量を予約し、一般的な 128〜2,048 サンプルのブロックを想定しています。それより大きい単発チャンクを渡すと、入力の非有限値除去・リサンプル・オーバーラップ用バッファが拡張されることがあります。厳しいリアルタイム制約で使う場合は、コールバック外で構築・設定し、一定サイズのブロックを供給するストリーミングソースから process() を呼び出してください。process() は単なるキューイングではなく解析を行います。

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