Skip to content

アーキテクチャ

libsonare の内部アーキテクチャについて説明します。

このページは、はじめにと各言語の実行環境ページに慣れてから開く内部地図です。libsonare を拡張したり、より大きなシステムに組み込んだりする人向けで、チュートリアルではありません。API を呼びたいだけなら、まずはじめにから始めてください。ここでは、公開 API が C++ コアのどこにつながるかを示します。

レイヤー図の読み方

外側の API レイヤーはアプリが呼ぶ入口です。コアレイヤーと特徴レイヤーは、再利用される信号処理の実体です。バインディングはできるだけ薄く保ち、各言語の形を同じ C++ の挙動へ橋渡しする役割に留めます。

このページで身につくこと

このページを読むと、次のことを判断・追跡できるようになります。

  • WASM、C、quick API、sonare.h からの公開呼び出しが、解析、ストリーミング、エフェクト、マスタリング、ミキシング、エンジンの各モジュールへどう流れるかを追える。
  • 各サブシステムを所有するソースディレクトリを特定できる。
  • 共有 DSP、特徴抽出、リアルタイム処理、言語バインディングがどこで接続するかを理解できる。
  • 変更をコアモジュール、バインディングラッパー、デモコンポーネント、ドキュメントのどこに入れるべきか判断できる。

モジュール概要

ページ対応表

見ている領域読むページ
analysis/feature/JavaScript APIPython APIlibrosa 互換性
analysis/acoustic_analyzer.*analysis/room_estimator.*src/acoustic/effects/acoustic/ルーム音響解析アルゴリズム根拠
streaming/リアルタイムとストリーミング
mastering/マスタリングプロセッサDSP 実装解説マスタリングアシスタント
mixing/ミキシングエンジンミキシングシーン JSON
engine/, transport/, automation/, graph/, rt/リアルタイムとストリーミング、特に RealtimeEngine
editing/effects/編集 DSPDSP 実装解説
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 のボイス系ツールでこの方法を使っています。

PARAM SWEEP · TIME STRETCHIDLE
タイムストレッチ — 音程はそのまま、長さを変える

タイムストレッチはピッチシフトのちょうど逆で、音程はそのままに、音の長さを変えます。レート(rate)をドラッグするとドラムの打点が広がったり詰まったりして波形がパネルを占める幅も変わりますが、下のスペクトルはほとんど動きません。1.0 より下では遅く長く、1.0 より上では速く短くなります。再生すると、チップマンク効果なしにグルーヴのテンポだけが変わるのが聴けます。

レート
1 ×

ストリーミングパイプライン

ストリーミングパイプラインは、チャンク間のオーバーラップ状態を維持しながらリアルタイムで音声を処理します。

プログレッシブ推定

音声がストリーミングされるほど、パイプラインはクロマとオンセットのデータを蓄積していき、BPM/キー推定が根拠にできる材料が増えます。推定は定期的に更新され(デフォルト: BPM は 10 秒ごと、キーは 5 秒ごと)、ストリームが長く続くほど信頼度が高まります。

主要な設計判断

遅延初期化

MusicAnalyzer は個別のアナライザーを遅延初期化します。必要になったタイミングで初めて中間特徴量(STFT、クロマ、オンセットなど)を計算し、その後の問い合わせでは結果を再利用します。

cpp
// BPM のみ計算(オンセット包絡線まで)
float bpm = analyzer.bpm();

// キー検出はクロマ計算をトリガー
Key key = analyzer.key();

// 完全解析は残りすべてを計算
AnalysisResult result = analyzer.analyze();

何が嬉しいか

キーだけ欲しい呼び出しでコード認識やセクション検出まで計算しないので、無駄な処理が発生しません。逆に analyze() を 1 回呼ぶと、すでに計算済みの中間結果がそのまま使われます。

ゼロコピースライシング

Audio は shared_ptr とオフセット/サイズでゼロコピースライシングを実現:

cpp
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_fft2048
hop_length512
n_mels128
fmin0
fmaxsr/2

サードパーティライブラリ

ライブラリ用途ライセンス
KissFFTFFTBSD-3-Clause
Eigen3行列演算MPL-2.0
dr_libsWAV デコードPublic Domain
minimp3MP3 デコード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

バンドルサイズはマスタリング+ミキシング+解析の全機能を含むためで、解析のみのビルドはより小さくなります。