アーキテクチャ
libsonare の内部アーキテクチャについて説明します。
このページは、はじめにと各言語の実行環境ページに慣れてから開く内部地図です。libsonare を拡張したり、より大きなシステムに組み込んだりする人向けで、チュートリアルではありません。API を呼びたいだけなら、まずはじめにから始めてください。ここでは、公開 API が C++ コアのどこにつながるかを示します。
レイヤー図の読み方
外側の API レイヤーはアプリが呼ぶ入口です。コアレイヤーと特徴レイヤーは、再利用される信号処理の実体です。バインディングはできるだけ薄く保ち、各言語の形を同じ C++ の挙動へ橋渡しする役割に留めます。
このページで身につくこと
このページを読むと、次のことを判断・追跡できるようになります。
- WASM、C、quick API、
sonare.hからの公開呼び出しが、解析、ストリーミング、エフェクト、マスタリング、ミキシング、エンジンの各モジュールへどう流れるかを追える。 - 各サブシステムを所有するソースディレクトリを特定できる。
- 共有 DSP、特徴抽出、リアルタイム処理、言語バインディングがどこで接続するかを理解できる。
- 変更をコアモジュール、バインディングラッパー、デモコンポーネント、ドキュメントのどこに入れるべきか判断できる。
モジュール概要
ページ対応表
| 見ている領域 | 読むページ |
|---|---|
analysis/ と feature/ | JavaScript API、Python API、librosa 互換性 |
analysis/acoustic_analyzer.*、analysis/room_estimator.*、src/acoustic/、effects/acoustic/ | ルーム音響解析、アルゴリズム根拠 |
streaming/ | リアルタイムとストリーミング |
mastering/ | マスタリングプロセッサ、DSP 実装解説、マスタリングアシスタント |
mixing/ | ミキシングエンジン、ミキシングシーン JSON |
engine/, transport/, automation/, graph/, rt/ | リアルタイムとストリーミング、特に RealtimeEngine |
editing/ と effects/ | 編集 DSP、DSP 実装解説 |
sonare_c*.h と binding フォルダ | バインディング対応表、ネイティブバインディング、C++ API |
ディレクトリ構造
src/
├── util/ # レベル 0: 基本ユーティリティ
│ ├── types.h # MatrixView, ErrorCode, 列挙型
│ ├── exception.h # SonareException
│ └── math_utils.h # mean, variance, argmax 等
│
├── core/ # レベル 1-3: コア DSP
│ ├── convert.h # Hz/Mel/MIDI 変換
│ ├── window.h # Hann, Hamming, Blackman
│ ├── fft.h # KissFFT ラッパー
│ ├── spectrum.h # STFT/iSTFT
│ ├── audio.h # オーディオバッファ
│ ├── audio_io.h # WAV/MP3 読み込み、任意で FFmpeg 対応形式
│ └── resample.h # r8brain リサンプリング
│
├── filters/ # レベル 4: フィルターバンク
│ ├── mel.h # Mel フィルターバンク
│ ├── chroma.h # Chroma フィルターバンク
│ ├── dct.h # MFCC 用 DCT
│ └── iir.h # IIR フィルター
│
├── feature/ # レベル 4: 特徴抽出
│ ├── mel_spectrogram.h
│ ├── chroma.h
│ ├── cqt.h
│ ├── vqt.h
│ ├── inverse.h
│ ├── spectral.h
│ ├── onset.h
│ └── pitch.h
│
├── effects/ # レベル 5: オーディオエフェクト
│ ├── hpss.h
│ ├── phase_vocoder.h
│ ├── time_stretch.h
│ ├── pitch_shift.h
│ ├── normalize.h
│ ├── preemphasis.h
│ ├── silence.h
│ ├── decompose.h
│ ├── remix.h
│ ├── delay/ modulation/ reverb/
│ ├── acoustic/ # room_morph
│ └── common/
│
├── acoustic/ # 幾何ベースのルーム音響
│ ├── room_model.* room_types.* material.*
│ ├── image_source.* # 初期反射
│ ├── late_reverb.* # 決定的な後期テール
│ └── rir_synthesizer.*
│
├── analysis/ # レベル 6: 音楽解析
│ ├── music_analyzer.h
│ ├── bpm_analyzer.h
│ ├── key_analyzer.h
│ ├── beat_analyzer.h
│ ├── downbeat_analyzer.h
│ ├── meter_analyzer.h
│ ├── chord_analyzer.h
│ ├── section_analyzer.h
│ ├── boundary_detector.h
│ ├── melody_analyzer.h
│ ├── rhythm_analyzer.h
│ ├── timbre_analyzer.h
│ ├── dynamics_analyzer.h
│ ├── acoustic_analyzer.h
│ ├── room_estimator.h
│ └── ...
│
├── streaming/ # レベル 6: リアルタイムストリーミング
│ ├── stream_analyzer.h # メインストリーミングアナライザー
│ ├── stream_config.h # 設定オプション
│ └── stream_frame.h # フレームとバッファ型
│
├── mastering/ # マスタリングエンジン
│ ├── api/ # チェーン・レジストリ・25 プリセット・76 solo processors + pair/stereo registries
│ ├── eq/ dynamics/ spectral/ stereo/ final/
│ ├── maximizer/ multiband/ saturation/ repair/
│ ├── match/ assistant/ # リファレンスマッチ+アシスタント/プロファイル
│ └── common/ # 共有 biquad/ラウドネスヘルパー
│
├── mixing/ # ミキシングエンジン
│ ├── channel_strip.* # ストリップ: トリム/インサート/パン/幅/センド
│ ├── bus.* sends.* vca_group.* panner.*
│ └── api/ # シーン JSON +シーンプリセット
│
├── engine/ # リアルタイムエンジン(トランスポート/クリップ/グラフ)
├── automation/ # オートメーションレーン+カーブ形状
├── metering/ # LUFS・トゥルーピーク・位相スコープ/ゴニオメーター
├── graph/ rt/ transport/ # DSP グラフ・RT セーフ基盤・トランスポート
├── editing/ # ピッチエディター・ボイスチェンジャー・ノートストレッチ
│
├── quick.h # シンプル関数 API
├── sonare.h # 統合インクルードヘッダー
├── sonare_c*.h # C API 集約・モジュール別ヘッダー
└── wasm/
└── bindings.cpp # Embind バインディングデータフロー
オーディオ解析パイプライン
オーディオエフェクトパイプライン
フェーズボコーダーとは?
フェーズボコーダーは、目立ったアーティファクトを抑えながら音声をタイムストレッチする標準的な手法です。リサンプリングと組み合わせれば、ピッチシフトにも使えます。
まず STFT を取り、再構成の前に各周波数ビンの位相を新しい時間軸に合わせて進めます。これにより、ピッチやスペクトルの質感を保ったまま音を長く・短くできます。
libsonare は timeStretch / pitchShift や、編集 DSP のボイス系ツールでこの方法を使っています。
ストリーミングパイプライン
ストリーミングパイプラインは、チャンク間のオーバーラップ状態を維持しながらリアルタイムで音声を処理します。
プログレッシブ推定
音声がストリーミングされるほど、パイプラインはクロマとオンセットのデータを蓄積していき、BPM/キー推定が根拠にできる材料が増えます。推定は定期的に更新され(デフォルト: BPM は 10 秒ごと、キーは 5 秒ごと)、ストリームが長く続くほど信頼度が高まります。
主要な設計判断
遅延初期化
MusicAnalyzer は個別のアナライザーを遅延初期化します。必要になったタイミングで初めて中間特徴量(STFT、クロマ、オンセットなど)を計算し、その後の問い合わせでは結果を再利用します。
// BPM のみ計算(オンセット包絡線まで)
float bpm = analyzer.bpm();
// キー検出はクロマ計算をトリガー
Key key = analyzer.key();
// 完全解析は残りすべてを計算
AnalysisResult result = analyzer.analyze();何が嬉しいか
キーだけ欲しい呼び出しでコード認識やセクション検出まで計算しないので、無駄な処理が発生しません。逆に analyze() を 1 回呼ぶと、すでに計算済みの中間結果がそのまま使われます。
ゼロコピースライシング
Audio は shared_ptr とオフセット/サイズでゼロコピースライシングを実現:
auto full = Audio::from_file("song.mp3");
// 両方とも同じバッファを共有
auto intro = full.slice(0, 30); // 0-30 秒
auto chorus = full.slice(60, 90); // 60-90 秒WASM 互換性
「デコード済みサンプル」とは、.mp3 や .wav ファイルのバイト列ではなく、生のオーディオ振幅値(Float32Array)を指します。デコードとは、圧縮されたファイルをその値へ変換する工程のことです。ほとんどの WASM 呼び出しは、すでにデコードされたサンプルを受け取ります。
npm / WebAssembly パッケージは主にサンプルベースの API を公開しています。多くの呼び出しはデコード済みのモノラル Float32Array サンプルを受け取ります。エンコード済みバイト列については、Audio.fromMemory(...) が WAV/MP3 をメモリ内でデコードし、Audio.fromMemoryWithBrowserFallback(...) は同じサンプルベース API に渡す前に Web Audio API などのブラウザコーデックへフォールバックできます。
WASM ビルドでは、ネイティブのファイル I/O や FFmpeg ベースのデコードは使いません。将来ブラウザスレッドを明示的に有効化したビルドを用意しない限り、実行はシングルスレッドです。
librosa 互換性
多くの DSP パラメータは librosa で一般的な値に寄せていますが、libsonare は librosa の完全なドロップイン置き換えではありません。特に libsonare は通常、呼び出し側がサンプルレートを渡します。librosa.load() のように標準で 22050 Hz へ暗黙にリサンプルするわけではありません。
| パラメータ | デフォルト |
|---|---|
| sample_rate | ユーザー指定 |
| n_fft | 2048 |
| hop_length | 512 |
| n_mels | 128 |
| fmin | 0 |
| fmax | sr/2 |
サードパーティライブラリ
| ライブラリ | 用途 | ライセンス |
|---|---|---|
| KissFFT | FFT | BSD-3-Clause |
| Eigen3 | 行列演算 | MPL-2.0 |
| dr_libs | WAV デコード | Public Domain |
| minimp3 | MP3 デコード | CC0-1.0 |
| FFmpeg | 任意の拡張ファイルデコード | リンクするビルドにより LGPL/GPL |
| r8brain | リサンプリング | MIT |
WASM コンパイル
出力: WASM 単体 ~2,986 KB(gzip ~1,070 KB)+ JS グルー。
合計 ~3,210 KB(gzip ~1,121 KB)— src/wasm/meta.json を参照
ビルド: Emscripten + Embind
フラグ: -sWASM=1 -sMODULARIZE=1 -sEXPORT_ES6=1バンドルサイズはマスタリング+ミキシング+解析の全機能を含むためで、解析のみのビルドはより小さくなります。