ネイティブバインディング
libsonare には 3 つのバインディングがあります。ブラウザ向けの WASM、Python、そして Node.js ネイティブアドオン です。このページでは 3 つの違い(初期化、インストール、解放の作法、エラー、Node ネイティブ固有の事項)を扱います。Node ネイティブの関数リファレンスは専用ページにあります。各言語の詳細は個別の API ページを参照してください。
- Python API — ctypes ベースのバインディング、PyPI でホイールを配布
- Node.js Native API — C++ の性能を直接活用するネイティブアドオン
初学者向けには、選び方は単純です。スクリプトやノートブックなら Python、ブラウザアプリなら WASM、Node.js からネイティブのファイルデコードや実行性能が必要な場合だけ Node ネイティブを選びます。
| 作りたいもの | 使う | パッケージ |
|---|---|---|
| ブラウザアプリ | WASM | @libraz/libsonare |
| Python スクリプトやノートブック | Python | pip install libsonare |
| ネイティブデコードや性能が必要な Node.js アプリ | Node ネイティブ | @libraz/libsonare-native(ソースからビルド。npm 未公開) |
このページで身につくこと
このページを読むと、次のことを判断・実行できるようになります。
- ブラウザ WASM、Python、Node ネイティブを、同じものとしてではなく用途で選べる。
- ネイティブデコードや実行性能が必要なときに、Node N-API アドオンをビルドして import できる。
- どの例が
@libraz/libsonareを使い、どの例が@libraz/libsonare-nativeを使うかを区別できる。 - ネイティブアドオンの関数を、JavaScript、Python、マスタリング、ミキシングの広いドキュメントへ対応づけられる。
比較
| WebAssembly | Python | Node.js(N-API) | |
|---|---|---|---|
| プラットフォーム | ブラウザ | デスクトップ | デスクトップ |
| 初期化 | await init() | 不要 | 不要 |
| 配布 | npm (@libraz/libsonare) | PyPI (pip install libsonare) | ソース (bindings/node) |
| ビルド | Emscripten | ビルド済みホイール(または CMake + pip) | CMake + cmake-js |
| パフォーマンス | ネイティブに近い | ネイティブ | ネイティブ |
| ハンドルの解放 | delete() | with/close() | destroy()。ランタイムが対応していれば using |
| ファイル I/O | サンプルベース API。Audio.fromMemory(...) は WAV/MP3 バイト列をデコードでき、ブラウザ側デコード経路では追加の対応形式も読めます | 標準は WAV/MP3。FFmpeg 有効ビルドでは FFmpeg 対応形式 | 標準は WAV/MP3。FFmpeg 有効ビルドでは FFmpeg 対応形式 |
| 通常の解析、エフェクト、特徴量、変換、マスタリング、ミキシング、ストリーミング | 同じ機能 | 同じ機能 | 同じ機能 |
Node.js(N-API)
Node.js バインディングは N-API を使用したネイティブアドオンで、WebAssembly のオーバーヘッドなしに C++ の性能を直接活用できます。
N-API と「ネイティブアドオン」とは?
ネイティブアドオン は、Node が通常のパッケージのように読み込むコンパイル済み C/C++ モジュールで、JavaScript や WebAssembly ではなく実際の機械語で動きます。
N-API(Node-API) は、こうしたアドオンを作るために Node が提供する安定したインターフェースで、V8 エンジンの内部実装からアドオンを隔離します。そのため、コンパイル済みバイナリ 1 つが再ビルドなしで Node の各バージョンで動き続けます。
利点はネイティブ速度と Node からの直接ファイルデコードです。一方で、WASM パッケージのようにどこでも同じバイナリが動くわけではないため、プラットフォームごとにビルド/インストールが必要です。
Node パッケージの選び方
| パッケージ | 初期化 | 使いどころ |
|---|---|---|
@libraz/libsonare | 使う前に await init() を呼ぶ | ブラウザ互換の WASM パッケージ、またはブラウザデモと同じ API が必要な場合 |
@libraz/libsonare-native | WASM 初期化は不要。import して直接呼び出す | ネイティブのファイルデコード、ネイティブ実行性能、ソースツリー内アドオン開発が必要な場合 |
JavaScript API の例は WASM パッケージを使います。ネイティブアドオンを使う例は @libraz/libsonare-native の import パスを持ちます。ネイティブの完全なリファレンスは Node.js Native API を参照してください。
要件
- Node.js 22 以上
- CMake 3.16 以上
- C++17 対応コンパイラ
- Yarn 4 以上
インストール
@libraz/libsonare-native は npm に公開されていません。ソースツリーの bindings/node でビルドしてください。別プロジェクトから使う場合は、ビルド済みのローカルパッケージをワークスペースや file: 依存として参照します。
git clone https://github.com/libraz/libsonare.git
cd libsonare/bindings/node
yarn install
yarn buildABI バージョン
バインディングと、それが読み込む共有ライブラリは、同じツリーから作られている必要があります。C ABI はサブシステムごとにバージョンを持ち、それぞれがそのサブシステムのフラットな POD 構造体のサイズとメンバーオフセットを保証します。バインディングは読み込み時にこれを照合するため、レイアウトの不一致は 1 バイトもやり取りする前に検出されます。運用上の指針は単純で、バインディングを再ビルドするときは必ずライブラリも再ビルドし、別のチェックアウトにある共有ライブラリをバインディングから参照させないことです。
| ABI | 現在の値 | 対象 |
|---|---|---|
| Feature | 7 | フラットな解析・特徴量の結果構造体と、公開する一般 C 関数の契約(SonareKey、SonareAnalysisResult、SonareChordDetectionOptions など) |
| Project | 2 | ヘッドレス DAW のプロジェクト・アレンジ構造体。アレンジ機能なしのビルドでは 0 を返します |
| Voice changer | 3 | リアルタイムボイスチェンジャーの設定構造体 |
| Acoustic | 5 | ルーム音響の構造体 |
| Engine | 3 | リアルタイムコマンドキュー |
sonare_abi_version() は上の 4 つを 1 つの uint32_t に詰めて返します。ビット 0〜7 が Feature、8〜15 が Project、16〜23 が Voice changer、24〜31 が Acoustic(集約値は 0x05030207)で、1 回の比較で全体を照合できます。Engine の ABI はここに含めず、専用のアクセサ sonare_engine_abi_version() を持ちます。POD 構造体ではなく SharedArrayBuffer のレコードレイアウトをバージョン管理しているためです。各サブシステムのヘッダーが自分のマクロ(SONARE_FEATURE_ABI_VERSION、SONARE_PROJECT_ABI_VERSION、SONARE_VOICE_CHANGER_ABI_VERSION、SONARE_ACOUSTIC_ABI_VERSION)を持ちます。Feature のマクロは公開する一般 C 関数の契約も保証するため、ノート API の voiced 引数のようなシグネチャ変更で値が進みます。それ以外のマクロは、保証対象の構造体のレイアウトが変わるたびに値を進めます。Project のバージョンだけは、レイアウトが変わったリリースごとに 1 回進みます。したがって値が等しければレイアウトと保証対象の契約は同一であり、保証対象の構造体へのフィールド追加は「追加的な変更」ではなくバージョンの更新です。
この値をどう使うかはバインディングごとに異なり、古いライブラリがどこで露見するかもそれで決まります(ほかの失敗と並べた一覧はエラー契約に、対処はインストールにあります)。
- Python はライブラリを最初に読み込むとき、個々のシンボルを設定する前に、詰め込まれた値をビルド時に想定した値と比較し、
libsonare ABI mismatchで始まるメッセージのErrorCode.ABI_MISMATCH(10)のSonareErrorを送出します。別のチェックアウトの共有ライブラリは、呼び出しの途中ではなく最初のライブラリ使用時に失敗します。RealtimeEngineとProjectのコンストラクター、およびProject.from_jsonも、エンジンとプロジェクトのバージョンを同じように照合します。Python CLI は終了コード 13 で終了します。 - Node ネイティブと WASM も同じ比較を自分で行い、
ErrorCode.AbiMismatch(10)のSonareErrorを投げます。Node はアドオンの require 時、WASM はinit()です。両パッケージとも問い合わせ関数abiVersion()・projectAbiVersion()・engineAbiVersion()・voiceChangerAbiVersion()と定数EXPECTED_PROJECT_ABI_VERSION・EXPECTED_ABI_VERSION・EXPECTED_ENGINE_ABI_VERSIONをエクスポートします(WASM はEXPECTED_ABI_VERSIONを/workletからも公開します)。Node アドオンはRealtimeEngineの構築時にエンジン ABI を照合します。projectAbiVersion()はアレンジ機能がコンパイルされていれば想定定数と等しく、そうでなければ0です。WASM のengineCapabilities()はengineAbiVersion・expectedEngineAbiVersion・abiCompatibleを報告します。エンジン ABI はパック値に含まれないので、各RealtimeEngineのコンストラクターが別に照合し、エンジンを作る前にAbiMismatchを投げます。Node のProjectコンストラクターとProject.fromJsonも、プロジェクトのバージョンについて同じことをします。 - C の呼び出し側 は
sonare_abi_version()をコンパイル時のSONARE_ABI_VERSIONと一度だけ比較します。JSON の入口(ボイスチェンジャーの JSON 設定、機能カタログ)はレイアウトのずれを許容するので関門は不要です。C ABI のバージョン も参照してください。
構造体へのフィールド追加は、構造体ごとの struct_version で段階的に有効化されるため、既存の C 呼び出し側はソースレベルでも呼び出しレベルでも影響を受けません。覚えておくとよい例が SonareNoteSegmenterConfig です。末尾の voiced_threshold は struct_version が 2 のときだけ読まれるので、従来どおりに埋めた設定はそのまま同じ挙動になり、ゼロ初期化した設定は既定値 0.5 を保ちます。変わるのはライブラリが報告するバージョンのほうです。自分のコードに手を入れていなくてもライブラリをバインディングと一緒に再ビルドする必要があるのは、このためです。
マスタリング API
Node.js では WASM npm パッケージとネイティブアドオンの 2 経路があります。
| パッケージ | 使いどころ |
|---|---|
@libraz/libsonare | ブラウザデモと同じ API を使いたい、または Web 互換の WASM が必要な場合。 |
@libraz/libsonare-native | Node.js でネイティブのファイルデコードやネイティブ実行性能が必要な場合。 |
import {
masterAudioStereo,
masteringChainStereo,
masteringAssistantSuggest,
masteringAssistantSuggestStereo,
masteringAudioProfile,
masteringAudioProfileStereo,
masteringPresetNames,
masteringPairAnalyze,
masteringProcessorNames,
masteringStreamingPreview,
masteringStreamingPreviewStereo,
} from '@libraz/libsonare-native'
console.log(masteringProcessorNames())
console.log(masteringPresetNames())
const mastered = masteringChainStereo(left, right, sampleRate, {
dynamics: {
compressor: {
thresholdDb: -18,
ratio: 2.2,
autoMakeup: true,
},
},
loudness: {
targetLufs: -14,
ceilingDb: -1,
truePeakOversample: 4,
},
})
console.log(mastered.outputLufs, mastered.stages)
const presetMaster = masterAudioStereo(left, right, sampleRate, 'pop', {
loudness: { targetLufs: -14 },
})
console.log(presetMaster.outputLufs, presetMaster.stages)
const matchReport = JSON.parse(
masteringPairAnalyze('match.referenceLoudness', source, reference, sampleRate),
)
const masteredWithProgress = masteringChainStereo(left, right, sampleRate, {
loudness: { targetLufs: -14, ceilingDb: -1, truePeakOversample: 4 },
}, (progress, stage) => {
console.log(`render ${(progress * 100).toFixed(0)}%: ${stage}`)
})
console.log(masteredWithProgress.outputLufs)
const profile = JSON.parse(masteringAudioProfile(samples, sampleRate, {
nFft: 2048,
hopLength: 512,
truePeakOversample: 4,
}))
const suggestions = JSON.parse(masteringAssistantSuggest(samples, sampleRate, {
targetLufs: -14,
ceilingDb: -1,
preferStreamingSafe: true,
}))
const deliveryPreview = JSON.parse(masteringStreamingPreview(samples, sampleRate, [
{ name: 'Streaming', targetLufs: -14, ceilingDb: -1 },
]))
console.log(profile, suggestions, deliveryPreview)
// The stereo entry points are request-object only — there is no positional
// overload, so a positional call throws.
const stereoProfile = JSON.parse(masteringAudioProfileStereo({
left,
right,
sampleRate,
params: { nFft: 2048, hopLength: 512, truePeakOversample: 4 },
}))
const stereoSuggestions = JSON.parse(masteringAssistantSuggestStereo({
left,
right,
sampleRate,
params: { targetLufs: -14, ceilingDb: -1, preferStreamingSafe: true },
}))
// Omitting platforms uses the built-in Spotify / Apple Music / YouTube set.
const stereoPreview = JSON.parse(masteringStreamingPreviewStereo({ left, right, sampleRate }))
console.log(stereoProfile, stereoSuggestions, stereoPreview)2 チャンネルの素材を扱うときは、ステレオ入口を使ってください。モノラル側は 0.5 * (left + right) のダウンミックスを測定するため、相関の低いステレオ素材では約 6 dB 低く出ます。その分だけ、積分ラウドネスとそこから導かれる値がまとめて過小評価されます。ステレオプロファイルのうち両チャンネルから測るのは loudness ブロックだけです。測定の比較とデモは C++ API のステレオのプロファイル・アシスタント・プレビュー にあります。数値は LUFS(LUFS)です。
呼び出し規約の違いに注意してください。上のマスタリング例が位置引数なのに対し、この 4 つはリクエストオブジェクト 1 つだけを取ります。メータリング側の meteringCrestFactorDbStereo({ left, right, sampleRate }) も同じリクエストオブジェクト形式で、number を返します。リクエスト型の名前は Node ネイティブと WASM で異なります。Node は関数ごとにリクエスト型(MasteringAudioProfileStereoRequest、MasteringAssistantSuggestStereoRequest、MasteringStreamingPreviewStereoRequest)を宣言し、WASM は共通の MasteringStereoParamsRequest を使います。
アシスタント/プロファイル系ヘルパーは、WASM 入口と同じオプション名を受け取ります。プロファイル設定は nFft、hopLength(どちらも 48 kHz でのサンプル数で、入力のレートに換算されます)、truePeakOversample、アシスタント設定は targetLufs、ceilingDb、enableRepair、preferStreamingSafe、speechMonoAmount です。共有ネイティブパーサーを通るため、snake_case の別名も受け付けます。
長尺のオフラインレンダリングでは、masteringChain(...)、masteringChainStereo(...)、masterAudio(...)、masterAudioStereo(...) の最後に進捗コールバックを渡し、そこから Node UI を更新します。
WASM パッケージは、ブラウザデモと同じ camelCase のマスタリング API を公開しています。主なグループは次のとおりです。
| グループ | API 名 |
|---|---|
| プリセットと簡易入口 | mastering()、masteringPresetNames()、masteringPresetParams()、masteringPlatformNames()、masterAudio()、masterAudioStereo()、masterAudioWithProgress()、masterAudioStereoWithProgress() |
| フルチェーン | masteringChain()、masteringChainStereo()、masteringChainWithProgress()、masteringChainStereoWithProgress() |
| オフラインのダイナミクス(単発) | masteringDynamicsCompressor()、masteringDynamicsGate()、masteringDynamicsTransientShaper() |
| 1 回の呼び出しで測定とリペア(任意のチャンネル数) | masteringRepairAnalyze()、masteringRepairApply() — 測定とリペアを 1 回の呼び出しで行う を参照 |
| オフラインのリペア — モノラル | masteringRepairDeclick()、masteringRepairDeclip()、masteringRepairDecrackle()、masteringRepairDehum()、masteringRepairDenoiseClassical()、masteringRepairDereverbClassical()、masteringRepairTrimSilence() |
| オフラインのリペア — ステレオペア | masteringRepairDeclickStereo()、masteringRepairDeclipStereo()、masteringRepairDecrackleStereo()、masteringRepairDehumStereo()、masteringRepairDenoiseClassicalStereo()、masteringRepairDereverbClassicalStereo()、masteringRepairTrimSilenceStereo() |
| オフラインのリペア — チャンネルリンク(任意のチャンネル数) | masteringRepairDenoiseClassicalLinked()、masteringRepairDereverbClassicalLinked() |
| リペアの計測(音声を返さない) | masteringRepairDetectClicks()、masteringRepairDetectClipping()、masteringRepairDetectCrackle()、masteringRepairDetectHum()、masteringRepairDetectNoiseFloor()、masteringRepairDetectReverb()、masteringRepairDetectTrimRange()、masteringRepairDetectTrimRangeStereo()、masteringRepairNoiseBandBins()、masteringRepairDereverbConfigForRoom() |
| アシスタントとプロファイル | masteringAudioProfile()、masteringAssistantSuggest()、masteringAssistantSuggestChain()、masteringStreamingPreview()、masteringAudioProfileStereo()、masteringAssistantSuggestStereo()、masteringAssistantSuggestChainStereo()、masteringStreamingPreviewStereo()、masteringAbMatchLoudness()、masteringAbMatchLoudnessStereo() |
| 名前付きプロセッサ | masteringProcessorNames()、masteringProcessorCatalog()、masteringAmpPresetCatalog()、masteringInsertNames()、masteringInsertParamNames(name)、masteringInsertParamInfo(name, sampleRate?)、masteringInsertTiming(name, params, sampleRate)、masteringProcess()、masteringProcessStereo() |
| ペア処理とステレオ解析 | masteringPairProcessorNames()、masteringPairProcess()、masteringPairProcessStereo()、masteringPairAnalysisNames()、masteringPairAnalyze()、masteringStereoAnalysisNames()、masteringStereoAnalyze() |
| ストリーミングレンダー | StreamingMasteringChain |
ペアプロセッサ、ペア解析、2 種類の A/B ラウドネスマッチは、WASM と同じくリクエストオブジェクトで referenceSampleRate を受け取ります。リファレンスはソースのレートへリサンプルされます。StreamingEqualizer.match はオプションで referenceSampleRate を受け取り、長さの異なるバッファも受け付けます。
Node ネイティブは同じ基本名を使いますが、進捗は個別の *WithProgress ヘルパー関数ではなく、最後のオプション引数に渡すコールバックとして受け取ります。
リペアの入口
リペア系の関数はいずれも、リクエストオブジェクトと位置引数のどちらでも呼べます。これは両パッケージ共通です。形によって入力の数と戻り値が変わります。
| 形 | 呼び出し | 戻り値 |
|---|---|---|
| モノラル | masteringRepairDeclick(samples, sampleRate, options?) | リペア後の Float32Array |
| ステレオペア | masteringRepairDeclickStereo(left, right, sampleRate, config?) | リペア後のペアとレポートのフィールド |
| チャンネルリンク | masteringRepairDenoiseClassicalLinked(channels, sampleRate, config?) | { channels, report }。入力順に 1 チャンネルずつ出力を返します |
| 計測 | masteringRepairDetectClicks(samples, sampleRate, options?) | 検出レポートのみで、音声は返しません |
ステレオ版は、モノラル版を 2 回呼ぶのとは別物です。ステレオイメージを動かしてしまう判断はペア全体で共有されます。レポートのフィールドの形、計測用ヘルパー、masteringAbMatchLoudness は JavaScript マスタリングリファレンス に、段とその固定順序はオーディオリペアにあります。
ミキシング API
ネイティブアドオンと WASM パッケージのどちらからも、ミキシング API を使えます。入口は mixStereo(...)、mixingScenePresetNames()、mixingScenePresetJson()、保持して使う Mixer クラスです。
チャンネルストリップ処理、シーンプリセット、センド、バス、オートメーション、メーター、オフラインのステムレンダーに使います。
ランタイム横断の説明は ミキシングエンジン を参照してください。
永続ミキサーでは、Node ネイティブは多くのストリップ制御メソッドで StripRef(number | string)を受け取ります。WASM メソッドは数値のストリップインデックスを使い、ID からは stripById(id) で引きます。
Node の stripMeter(strip) はポストフェーダーメーターを読みます。タップを明示したい場合は meterTap(strip, 'preFader' | 'postFader') を使います。シーン JSON の読み込み後は、mixer.sceneWarnings() がシーンリーダーの消費しなかったすべてのキー(典型的にはタイプミス)を、パス付きの非致命的な警告として一覧します。
プロジェクト・インストゥルメント・ライブ MIDI
Node ネイティブアドオンは、WASM や Python と同じヘッドレス DAW 向け API を公開しています。Project クラス(トラック、クリップ、テンポ、undo/redo、SMF/MIDI 2.0 入出力)と、インストゥルメント付きバウンス(bounceWithSynthInstrument(s) と SoundFont のロード)が使えます。NativeSynth プリセットカタログ(synthPresetNames()/synthPresetPatch()/SynthPatch)、chordFunctionalAnalysis(...)、ライブ MIDI 入力付きの RealtimeEngine も使えます。
エンジンには他のバインディングと同じレーンミキサーと MIDI クリップスケジュールが載っています。setTrackLanes(最大 MAX_TRACK_LANES、32 レーン)/ setTrackBuses、トラック/マスター/バスのストリップ JSON とインサート操作、インサートオートメーション id の解決(未知のトラック・バス・インサート・デスティネーション・パラメータには、どれも RangeError を投げます)、setParamSmoothingMs、ワイド/スコープテレメトリ、setMidiClips、sampleAtPpq を、WASM と同じ camelCase 名で使えます。外部機器へのルーティングも setMidiDestinationExternal、setExternalMidiClockEnabled、drainExternalMidi、externalMidiDroppedCount から利用できます(リアルタイムエンジンを参照)。ブラウザ専用のつなぎ込み(bindWebMidi、bindMicrophoneInput)は WASM 固有で、ネイティブアドオンには含まれません。
詳細は各ガイドを参照してください: プロジェクト編集、プロジェクトのバウンス、内蔵シンセサイザー、SoundFont プレイヤー、MIDI 入力。
エラーハンドリング
WASM パッケージと同じく、ネイティブアドオンもライブラリやオブジェクトの状態が報告する失敗を構造化された SonareError として投げます。Error のサブクラスで、C ABI のエラー enum を映した数値の code と正準名 codeName を持ちます。両パッケージとも ErrorCode・SonareError・型ガード isSonareError(value) をエクスポートし、同じ失敗はどのバインディングでも同じ数値コードを報告します。拒否された引数は、どちらのパッケージでもネイティブの RangeError(範囲外、非有限、未知の ID や名前)または TypeError(型の誤り)で、isSonareError は一致しません。破棄済みオブジェクトの呼び出し(破棄済みの HrtfSet、ProjectTimeline、SampleBank を引数に渡した場合を含む)と、以前の設定が原因の失敗(テーブルの満杯、先のルーティングが禁じる変更)は、InvalidState の SonareError です。どの失敗がどのクラスとコードになるかは、全ランタイム分をエラー契約にまとめています。ErrorCode enum と使用例はエラーハンドリングを参照してください。
SonareError は両パッケージとも実行時のクラスです。値としてインポートすればコンストラクターが得られ、共有の TypeScript モジュールがどちらのパッケージからインポートしても同じ種類のものが手に入ります。instanceof はプロトタイプ判定ではなくブランド判定で、SonareError という名前を持ち数値の code を持つ Error であれば絞り込めます。
import { ErrorCode, isSonareError, SonareError } from '@libraz/libsonare-native'
try {
// ...
} catch (err) {
if (err instanceof SonareError && err.code === ErrorCode.InvalidParameter) {
console.error(err.codeName, err.message)
}
}これが効くのは、プロトタイプ判定では取り逃がす 2 つの場合です。アドオンはクラスを構築せず、同じ形を持つ素の Error を送出します。また、ワーカー境界や structuredClone() を越えたエラーはプロトタイプを失っています。どちらもこの判定なら絞り込めます。isSonareError(value) は同じダックタイピング判定を型ガードとして書いたもので、instanceof はこれに委譲するため両者が食い違うことはなく、どちらを使っても構いません。プロトタイプを保持しない境界の向こうへネイティブの失敗を投げ直す用途のために、SonareError を直接構築することもできます。
Audio メソッドの違い
WASM の Audio クラスは、よく使う単発ヘルパーをメソッド形式で呼ぶための入口です。使用頻度が低い、または呼び出し方が異なるヘルパーはスタンドアロン関数のままです。
Audio メソッドとして使える | WASM でスタンドアロンのまま |
|---|---|
| BPM/キー/ビート/コードなどの基本解析 | analyzeSections(...) |
| HPSS/編集ヘルパー | analyzeMelody(...) |
| マスタリングヘルパー | analyzeDynamics(...) |
| 特徴量抽出 | analyzeTimbre(...) |
| ラウドネス、リサンプリング | ルーム音響ヘルパー、セクション/メロディ/ダイナミクス/音色ヘルパー |
Node ネイティブの Audio オブジェクトは、ネイティブアドオンへ直接委譲できるためメソッドの範囲が広くなっています。
| 機能 | Node ネイティブ | WASM |
|---|---|---|
追加の Audio メソッド | より詳細な解析・ルーム音響系メソッドをインスタンスメソッドとして持つ | 使えるところはスタンドアロンの詳細ヘルパーを使う |
| ファイル構築 | Audio.fromFile(...)、Audio.fromFileChannel(...)、Audio.fromBuffer(...)、Audio.fromMemory(...) | Audio.fromBuffer(...)、Audio.fromMemory(...)、Audio.fromMemoryWithBrowserFallback(...) |
| サンプル取得 | audio.getData() はコピーを返す | audio.data もコピーを返す |
共通メソッドに加えて、用途を絞った次のヘルパーも Audio のメソッドとして持ちます。analyzeBpm(...)、analyzeImpulseResponse(...)、detectAcoustic(...)、analyzeRhythm(...)、analyzeDynamics(...)、analyzeTimbre(...)。ルーム系ヘルパーの estimateRoom(...)、synthesizeRir(...)、roomMorph(...) はスタンドアロン関数のままです。
メソッドと関数の完全なリファレンスは Node.js Native API を参照してください。
StreamingMasteringChain
ネイティブアドオン(および WASM パッケージ)は、ブロック単位でレンダリングする StreamingMasteringChain クラスも公開しています。Electron アプリや Worker、音声入力パイプラインなどから、masteringChain() と同じネスト構造の設定に loudnessStaticGainDb と任意の loudnessStaticGainPeakDb を加えて、ブロックごとに処理を進められます。
import { StreamingMasteringChain } from '@libraz/libsonare-native';
const chain = new StreamingMasteringChain({
eq: { tilt: { tiltDb: 0.5 } },
dynamics: { compressor: { thresholdDb: -20 } },
maximizer: { truePeakLimiter: { ceilingDb: -1, oversampleFactor: 4 } },
});
chain.prepare(48000, /*maxBlockSize=*/512, /*numChannels=*/2);
// processMono は numChannels = 1 で prepare したチェーンが必要
const { left, right } = chain.processStereo(leftBlock, rightBlock);
console.log(chain.stageNames(), chain.latencySamples());
chain.setParameter('eq.tilt.tiltDb', 1.0); // ブロック境界でリアルタイム安全な値を更新
chain.reset(); // 状態だけクリア(prepare し直さない)prepare() の後は setParameter(key, value) で、リアルタイム安全なフルチェーンパラメータをブロック境界で直列化して変更できます。ネイティブチェーンはプロセッサのインスタンス、音声履歴、レイテンシを保持します。eq.tilt.tiltDb のような完全なドット区切りキーを使い、構造を変えるキー、無効な段のキー、未知のキーは拒否されます。呼び出しは process*()、flush*()、reset()、prepare() と直列化します。変更は境界で反映され、自動的にはスムージングされません。
numChannels === 1 のときはステレオ専用の段はスキップされます。ストリーミングチェーンはオフライン専用のリペア段を拒否します。loudness 段を使うには事前計算した静的ゲインを loudnessStaticGainDb で指定し、必要に応じて音源の True Peak を loudnessStaticGainPeakDb で渡します。後者を指定すると、静的ゲインは設定したシーリングを超えないように制限されます。WASM ビルドは delete()(別名の destroy() と [Symbol.dispose] もあります)でハンドルを解放します。ネイティブアドオンは冪等な destroy() と [Symbol.dispose] を公開します。using は TypeScript 5.2 以降でコンパイルしたコードか、明示的なリソース管理に対応したランタイムで使えます(Node 22 自体は using を解釈しません)。ネイティブハンドルは最終的には GC でも回収されますが、リクエストごとにチェーンを生成するような長寿命プロセスでは明示的に解放しないとネイティブメモリが積み上がります。
関連するマスタリングガイド: ブラウザ内ローカル処理、リファレンスマッチ、品質チェックリスト。
StreamingEqualizer
StreamingEqualizer は Node ネイティブ、Python、WASM で使えます。Node ネイティブでは、小数、NaN、大きすぎる maxBlockSize やスロープは RangeError です。
processMono / processStereo の呼び出しをまたいで EQ の状態を保持し、スペクトラムスナップショットを出せます。リファレンスマッチからバンドを設定することもできます。match(source, reference, { sampleRate?, referenceSampleRate?, maxBands? }) はどんな長さのバッファも受け付け、リファレンスは独自のレートでも構いません。
Node ネイティブと WASM は同じフェーズモード値を受け取ります。Python はさらにコンテキストマネージャ構文もサポートします。
| ランタイム | フェーズモード |
|---|---|
| Node ネイティブ | 'zero', 'natural', 'linear', または 1/2/3 |
| WASM | 'zero', 'natural', 'linear', または 1/2/3(Node ネイティブと同じ) |
| Python | 文字列または数値モード |
Python では with StreamingEqualizer(...) as eq: / eq.close() で解放できます。
import { StreamingEqualizer } from '@libraz/libsonare-native';
const eq = new StreamingEqualizer({ sampleRate: 48000, maxBlockSize: 512 });
eq.setBand(0, { type: 'HighShelf', frequencyHz: 8000, gainDb: 4, enabled: true });
eq.setPhaseMode('natural');
eq.setAutoGain(true);
const { left, right } = eq.processStereo(leftBlock, rightBlock);
console.log(eq.spectrum(), eq.latencySamples(), left, right);ネイティブビルドは pkg-config で FFmpeg 開発ライブラリを自動検出します。FFmpeg がない場合は WAV/MP3 のみをデコードします。明示的に指定する場合は次の環境変数を使います。
SONARE_FFMPEG=1 yarn build # FFmpeg デコードを必須にする
SONARE_FFMPEG=0 yarn build # WAV/MP3 のみに固定する関数リファレンス全体
Node ネイティブの関数ごとの完全なリファレンスは専用ページにあります: Node.js Native API。解析、エフェクト、特徴抽出、逆再構成、librosa 互換、変換、メータリング、スケール量子化の各関数、ストリーミング/リアルタイムクラス、エクスポートされる TypeScript 型を掲載しています。