Cochlea について
Cochleaは、エージェントやオーディオ開発者向けのオフライン音声エンジンで、作曲、レンダリング、分析、検証に使えます。音声を簡潔なレポートやスペクトログラムに変換し、決定的なレンダリングと一般的な形式間の特徴比較に対応します。
主な機能
- 01RONデータによるスコア作成
- 02決定的なオフライン音声レンダリング
- 03ラウドネス、音高、テンポ、リズムの分析
- 04スペクトログラムと特徴レポートの生成
- 05知覚特徴による音声比較
- 06MIDIのインポートとエクスポート
活用シーン
- 01埋め込みアサーションでレンダリング結果を検証
- 02長い音声ファイルの指定区間を分析
- 03再レンダリングによる音楽的な変化を比較
- 04JSONレポートやスペクトログラムで音声を確認
MCP 対応
stdio MCPサーバーは、レンダリング、分析、スペクトログラム、スコア検査、音声比較、MIDI変換、文字起こし、スコア参照の12ツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
cochlea

エージェント向けのヘッドレスオーディオエンジンです。 スコアをデータとして記述し、オフラインで決定論的な PCM にレンダリングしたら、音量、オンセット、ピッチ、キー、スペクトログラムなどを使って 数値で聴き、聞こえた内容を検証できます。人間の耳もオーディオデバイスも介さずに、作成 → レンダリング → 解析 → 検証を行います。

エージェントが見るもの:examples/scores/first_light.ron のメルスペクトログラムです。以下の例で使うスコアをレンダリングし、解析した後のものです。PCM は表示されません。
use cochlea_score::*;
let score = Score::new(SampleRate(48_000), Ppq(960))
.time_signature(4, 4)
.tempo(Ticks(0), Bpm(120.0))
.track("lead", Instrument::preset("saw_lead"))
.note("lead", bar(1).beat(1), Dur::quarter(), Pitch::A4, Vel(96))
.automate("lead", Param::CUTOFF_HZ,
keys![(bar(1), 400.0, ease_in_out()), (bar(3), 4_000.0)]);
let rendered = cochlea_render::render(&score)?;
rendered.write_wav("mix.wav")?;
use cochlea_verify::{VerifyExt, Tol, Ms, Cents, Db};
let report = rendered.verify(&score)
.true_peak_below(-1.0)
.pitch_matches_score("lead", Cents(10.0))
.monotone("lead", Param::CUTOFF_HZ, bar(1)..bar(3))
.silent_after(bar(5))
.run();
assert!(report.passed);
または、コマンドラインだけで RON 形式のスコアを記述できます。
cochlea render score.ron --out mix.wav --stems stems/ --verify
cochlea probe input.wav --json report.json --spectro spec.png
cochlea probe input.wav --digest --window-ms 500
cochlea probe input.mp3 --from 42.0 --to 44.5 # zoom into a window, any format
cochlea diff a.wav b.wav --tier2 --spectro delta.png
cochlea lint score.ron
cochlea spectro input.wav --out spec.png --annotate # draw beats/onsets/pitch on the image
cochlea import song.mid --out score.ron # SMF -> score, timing exact
cochlea transcribe solo.wav --out score.ron # audio -> score, the inverse of render
cochlea reference # the full score-authoring reference, generated from the live preset bank
cochlea probe は あらゆる WAV に加えて、FLAC(ビット単位で正確にデコード)、mp3、ogg にも対応します。ffmpeg は不要で、スコアも必要ありません。これが入口です。自分でレンダリングしていない音声を指定すれば、エージェントが自分の成果を確認する際に使うものと同じ JSON レポートとスペクトログラムが得られます。
エージェントが音を聴く仕組み
作成 → レンダリング → 分析(JSON) → スペクトログラム(1回のビジョン呼び出し) → 検証
- 作成 — スコアをデータとして作成します(RON、または上記の Rust ビルダー)。
- レンダリング — 決定論的な PCM にレンダリングします —
cochlea render score.ron --out mix.wav。 - 分析 — ミックスをコンパクトな JSON レポート(ラウドネス、オンセット、ピッチ、キー、無音、クリッピング)に変換します —
cochlea probe mix.wav --json report.json。 画像も音声も必要ありません。エージェントは数値を読み取ります。 - 数値だけでは不十分な場合は確認します —
cochlea spectro mix.wav --out spec.pngで小さな PNG をレンダリングし、生のサンプルを推論する代わりに、エージェントが1回のビジョン呼び出しで確認します。 - 検証 —
cochlea render score.ron --verifyはスコアに埋め込まれたアサーションを実行し、失敗するとゼロ以外の終了コードを返します。エージェントは、人間が「そう聞こえます」と確認しなくても、自分で再試行できます。
長いファイルの途中を詳しく聴きたい場合、すべての読み取りツールで --from/--to を指定できます。17〜19小節だけを分析したり、ドロップ部分だけのスペクトログラムを描画したりできます。切り出しはフレーム単位で正確で、レポートの時刻は切り出し位置を基準とし、source.start_ms に元の位置が記録されます。これにより、スタック全体がファイル全体だけを対象とするレポートではなく、ズームレンズのように機能します。
ここでは経済性が重要であり、後付けの考慮事項ではありません。上記の first_light のレンダリングは、48 kHz、32ビット浮動小数点 PCM の7秒分で、サイズは2.7 MBです。同じ設定で3分の曲を作ると、約66 MBになります。これをテキストとしてエージェントに渡すことはできませんし、サンプルを1つずつ読み取るのはさらに非効率です。
代わりに、分析レポートは数 KB の JSON です。以下は、興味深いフィールドに絞ったスキーマ v5 です。pitch.melody に注目してください。曲のベースラインとメロディーがノートイベントとして読み戻されており、これは作成ループの読み戻し側にあたります。
{
"schema_version": 5,
"source": { "sample_rate": 48000, "channels": 2, "duration_ms": 7035.708333333333, "start_ms": 0.0 },
"loudness": { "integrated_lufs": -22.700454879284784, "true_peak_dbtp": -15.910817022082783, "lra": 10.607660373688798 },
"onsets": { "count": 6, "times_ms": [1077.33, 2149.33, 2346.67, 3221.33, 4538.67, 5034.67] },
"pitch": { "voiced_ratio": 0.9847560975609756, "median_f0_hz": 110.00194603797897,
"melody": [ { "name": "A2", "start_ms": 0.0, "end_ms": 1045.3, "cents_off": 0.1 },
{ "name": "E2", "start_ms": 1077.3, "end_ms": 2112.0, "cents_off": 0.3 },
{ "name": "F#2", "start_ms": 2154.7, "end_ms": 3178.7, "cents_off": 0.2 },
{ "name": "E2", "start_ms": 3210.7, "end_ms": 4384.0, "cents_off": 0.3 },
{ "name": "E5", "start_ms": 4394.7, "end_ms": 5813.3, "cents_off": -0.4 } ] },
"timbre": { "mfcc_mean": [-37.64, 14.47, -4.44, 1.24, "..."], "mfcc_std": ["..."], "frames": 656 },
"key": { "tonic": "E", "mode": "major", "confidence": 0.8093960265638273 },
"tempo": { "bpm": 55.97014925373134, "confidence": 0.6633739386089712, "stability": 0.3333333333333333,
"candidates": [ { "bpm": 55.97014925373134, "salience": 0.6633739386089712 },
{ "bpm": 112.5, "salience": 0.21588204941945222 } ] },
"rhythm": { "grid_alignment": 0.8333333333333334, "grid": "straight", "offbeat_ratio": 0.4, "clear_rhythm": true },
"stereo": { "width": 0.02967719705208343, "correlation": 0.9981362354107913, "balance": -0.0016380539212361243 },
"structure": { "section_count": 1, "confidence": 0.0 },
"silence": { "trailing_ms": 2485.708333333333 },
"clipping": { "clipped_samples": 0, "true_peak_over_0dbtp": false }
}
そしてスペクトログラムは小さな画像1枚です。以下は title_cue のデモです。cutoff_hz のオートメーションによって、1〜3小節にわたって250 Hzから5000 Hzまで変化するパッドです。

スイープが進むにつれてフレーム上部の暗い帯域が狭まり、時間とともにより高い周波数のエネルギーが通過します。エージェントは画像から直接これを読み取ります。デモの Monotone(track: "pad", param: "cutoff_hz", ...) アサーションは、同じことを数値で検証します。
長さに関係なく曲全体を1枚の画像に収めるには、--sheet を使うと、スペクトログラムを1本の長い帯ではなくコンタクトシートに並べます。ここでは、--bars-per-tile 2 によって、1タイルあたり2小節にしています。

コンテキストウィンドウなしでオーディオを読み取る
probe --digest は JSON を省略し、代わりに決定論的なテキスト要約を出力します。
特徴の次元ごとに1行、その後に約40行を上限とするウィンドウ化されたタイムラインが続きます。
以下は drum_groove デモの実際の出力です。20.8秒、4トラックのリズム、ステレオ、構造の各次元を一画面にまとめています。
cochlea digest: 20.755s 2ch 48000Hz
loudness: integrated=-24.06 momentary_max=-22.42 true_peak=-5.95 lra=1.61
key: A# minor (conf 0.54) pitch: voiced=23% median=63.8Hz (C2 -42.8c)
melody: 6 notes C2 C2 C2 C2 A1 A1
tempo: 110.3bpm (conf 0.79, stability 1.00) alts: 54.9bpm(0.89), 36.6bpm(0.79)
rhythm: clear=true grid_align=0.98 (straight) offbeat=0.56
stereo: width=0.07 corr=0.99 bal=-0.01
structure: 1 section
onsets: count=58 rate=2.79/s
silence: leading=0ms trailing=2545ms
clipping: clipped=0 over_0dbtp=false
timeline: window=1000ms bucket=1x rows=21
idx t(s) rms peak ons f0 flags
0 0.000-1.000 -25.55 -7.36 4 64.0 -
1 1.000-2.000 -25.61 -8.37 3 63.4 -
...
テンポとリズムは、互いに独立して変化するため、別々の軸として報告されます。 ドラムソロでは、パターンが見分けられないほど変化しても、一定のパルスを保つことがあります。エージェントが把握する必要があるのは、まさにその違いです。
ここではテンポが 110.3 BPM と表示され、作成時の 110 と一致しています。また、stability 1.00 は、曲全体を通して速度がまったく変化しないことを示しています。alts リストには、実際により強い生のピークである54.9 BPMの半テンポ読み取り値が表示されています。オクターブ事前分布によって、拍に近い方が選ばれています。このような拍節の曖昧さは、検出器の内部に隠された五分五分の判定ではなく、エージェントが考慮できるデータです。
続く rhythm の行は、ヒットがそのパルスとどのように対応するかを示します。オンセットの98%が拍の細分化グリッドに乗り、56%が拍の裏の細分化に乗っているため、clear=true です。これはシンコペーションが数値で示された、8分音符のハイハットグルーヴです。
0.2.0 より前のメトリクスでは、同じグルーヴが信頼度0.01で clear_rhythm=false と判定されていました。3つの拍節レベルにまたがるハイハット、キック、スネア、パッドの重ね合わせにより、質量比スコアにおける各ラグの割合が薄まっていたためです。グリッドベースのルールなら、適切な問いを立てられます。
(straight) タグはグリッドの仮説検定を示しています。整合性はストレートな16分音符と8分音符の3連符の両方に対して測定され、より多くのヒットが乗る方がレポートに記載されます。シャッフルやスウィングのテイクは、16分音符に無理に当てはめて乱れていると評価されるのではなく、整合した3連符のリズムとして grid_align=1.00 (triplet) と認識されます。
cochlea diff は、バイト単位ではなく特徴空間で2つのファイルを比較します。「ファイルのビット列が完全に一致するか」ではなく、「変更が意図したとおりの結果になったか」を確認します。first_light.wav と title_cue.wav の差分を取った実際の出力は次のとおりです。
verdict: different (duration, loudness, onsets, key)
duration a->b +1264.3 ms
loudness integrated -5.95 LU true_peak +5.70 dB lra -8.88 LU
onsets matched=0 mean_offset=- max_offset=- unmatched_a=6 unmatched_b=5
pitch delta +0.5 cents
key a=E major (conf 0.81) b=A minor (conf 0.86) changed=true
segments max_abs_rms_delta 120.99 dB at idx=7
tempo bpm -24.01 bpm stability -0.33
rhythm clear_rhythm_changed=false grid_align -0.03 grid_changed=true
timbre mfcc_distance 4.00
stereo width +0.14 correlation -0.08 balance -0.01
structure section_count +0
timbre の行は、音量を示すだけなので c0 を除外した、MFCC のスペクトル形状距離です。同じ楽器を再レンダリングした場合は0付近になりますが、音量を一致させてサイン波をノコギリ波に置き換えると、それを大きく上回る値になります。これは「再レンダリング後も楽器の特性が保たれているか」を示す軸であり、音量やピッチでは捉えられません。
--spectro delta.png を追加すると、差分による符号付き差分ヒートマップも描画されます。B の方が大きければ赤、小さければ青、変化がなければ黒になります。移動したオンセットは青と赤の縦線のペアとして、明るくなったスイープは赤いくさびとして表示されます。変化が単なる数値ではなく、目に見える構造になります。
レンダリング結果をそれ自体と比較するか、同じスコアを再レンダリングした結果と比較すると、判定は byte-identical と表示されます。これは、上記の決定性の契約を外部から確認するものです。--tier2 を指定すると、この判定をゲートとして使用できます。バイト単位で一致するか、Tier-2 相当であれば終了コード0、それ以外は終了コード1となるため、CI ジョブやエージェントは生のサンプルを一度も読み取らずにリグレッションを検出できます。
MCP クライアントとしてのエージェント
cochlea-mcp は、CLI と同じライブラリを基盤にした stdio MCP サーバーです。12 個のツール — render_score、probe_audio、spectrogram、lint_score、probe_digest、loudness_timeline、beat_grid、audio_diff、import_midi、export_midi、transcribe_audio、score_reference — を公開し、それぞれ対応するライブラリ呼び出しを薄くラップしています。どの MCP クライアントでも、サブプロセスとしてシェルから実行するのではなく、ツール呼び出しとして、作成 → レンダリング → プローブ → スペクトログラム → 検証の一連の流れを利用できます。
cargo install cochlea-mcp
claude mcp add cochlea -- cochlea-mcp
コートを着た CLI ではなく、エージェント向けに設計されている理由は次のとおりです。
- 自分で必要な情報を取得できます。
score_referenceは、作成に必要なリファレンス一式を返します。具体的には、RON 文法、オートメーション可能な全パラメーターを含む最新のプリセットカタログ(スコアの検証にも使われる同じレジストリから生成されるため、古くなりません)、すべてのverify:アサーション、そしてテストスイート自体がレンダリングする実例です。このリポジトリを一度も見たことがない状態で接続したエージェントでも、スコアを作成できます。 - 指し示すのではなく、見せます。
spectrogramは画像を MCP の画像コンテンツとしてインラインで返します(サイズ上限付きの Base64 PNG)。そのため、ファイルシステムにアクセスできないクライアントでも、1 回の視覚分析でレビューできます。out_pathは省略可能です。annotate: trueを指定すると、検出したビート、オンセット、ピッチを画像に描画します。また、audio_diffも同じ方法で符号付き差分ヒートマップを返せます。 - 範囲を絞って分析できます。
probe_audioとspectrogramはfrom_s/to_sを受け取るため、長いファイル全体を毎回分析する代わりに、人が小節を再生し直すように、ファイルの 42.0~44.5 秒を集中的に分析できます。 - アクセス範囲を制限できます。
cochlea-mcp --root DIRは、ファイルシステムにアクセスする前に、DIRの外部に解決される(シンボリックリンクや..を含めて正規化した)読み取りまたは書き込みをすべて拒否します。
ツールの完全なスキーマ、引数、JSON-RPC のフレーミングについては、docs/mcp.md をご覧ください。
インストール
9 個すべてのクレートが crates.io にあります。
cargo install cochlea # the CLI: render / probe / diff / lint / spectro / reference
cargo install cochlea-mcp # the MCP stdio server
cargo add cochlea-features # or any crate as a library dependency
ソースからインストールする場合は、git clone https://github.com/richer-richard/cochlea && cd cochlea && cargo install --path crates/cli を実行します。
概念
スコア IR(cochlea-score)。スコアは、トラック、ノート、パラメーターごとのオートメーション、ステップ変化を表すテンポマップ、任意のマスターセクションからなるプレーンなデータです。RON(version: 1)にシリアライズでき、テストでは双方向にラウンドトリップします。
位置は bar(3).beat(2) のように直感的に指定でき、長さは Dur::quarter() や "3/16" のような正確な分数で表します。付点音符や三連符の省略記法もあります。ティックグリッドに合わない位置はエラーになり、暗黙に丸められることはありません。cochlea import はタイミングを維持したまま Standard MIDI Files を読み込みます。SMF のティックはそのままグリッドに反映され、GM プログラムはラベル付きのプリセット候補に変換されます。
整数時間が真の基準です。 すべての時間は 960 PPQ のティックで表されます。BPM は最初に一度だけ、四分音符あたりの整数ナノ秒に変換されます。ティックからサンプルへの変換は、イベントのスケジュール時に一度だけ適用される、正確な有理数 u64/u128 算術(fenestra-anim の mul_div)です。浮動小数点の秒数が累積することも、実時間の時計を参照することもなく、プロパティテストでは 10⁹ ティックにわたってドリフトがないことが確認されています。
シンセ(cochlea-synth)。fundsp を基盤とする 11 種類のプリセットがあります。そのうち 8 種類は減算方式です。sine、saw_lead、square_bass、chord_pad(デチューンしたノコギリ波が左右に分かれて定位する、本格的なステレオ音源)、noise_hat、pluck、kick、snare です。残りの 3 種類は異なる方式です。fm_bell(オートメーション可能な brightness を備えた調波 FM)、marimba(モード共鳴する打弦バー)、organ(加算式ドローバー)です。また、reverb インサートもあります。
各楽器では、オートメーション可能なパラメーターを名前、単位、範囲、デフォルト値とともに宣言します。スコアはこのレジストリに基づいて検証され、同じレジストリから作成用リファレンスも生成されるため、ドキュメントとコードが食い違うことはありません。ノイズはすべて (seed, sample_index) をキーとするカウンターベースの RNG から生成されます。ランダムアクセスが可能で、状態を持つ乱数生成器はどこにもありません。
レンダラー(cochlea-render)。オーディオは64サンプルのブロック単位でレンダリングされ、イベント境界で分割されます。そのため、ノートのタイミングはサンプル単位で正確になり、オートメーションはコントロールレート(48 kHzで約1.3 ms)で動作します。トラックはそれぞれ独立してレンダリングされるため、並列処理の単位になると同時に、ステムもそのまま得られます。ボイスの割り当てと最も古いノートのスティーリングは、スケジュールに基づく純粋関数です。
マスターバスは、ステムを固定されたトラック順でf64に加算し、続いてスコアのオプションのマスターステージを適用します。マスターステージでは出力ゲインを調整し、サンプルピークの上限を正確に維持するブリックウォール型の先読みリミッターを使います(オフライン処理では、先読みは単なる前方ウィンドウの最大値であり、ディレイラインはありません)。これは、TruePeakBelowのヘッドルームを確保しながらLUFS目標値に合わせるためのツールです。マスターセクションがなければ、定義上もテスト上も、ミックスはステムの合計とバイト単位で一致します。
特徴量(cochlea-features)。スキーマバージョン付きの単一のJSONレポートで、以下を網羅します。
- ラウドネス — ebur128による統合LUFS、モーメンタリー最大値、トゥルーピーク、LRA;
- スペクトルフラックスによるオンセットと、セント単位の偏差を含むYINピッチ;
- 量子化されたメロディー:エージェントが自身の出力と照合できるノートイベント;
- MFCCによる音色のダイジェスト、ならびにクロマとKrumhansl-Schmucklerによるキー推定;
- 独立した2つの軸としてのテンポとリズム — テンポは拍の明瞭度、オクターブ違いの候補、ウィンドウごとの安定性を示し、リズムはグリッドへの整合性(ストレートとトリプレットの仮説検定を含む)、オフビート比率、キャリブレーション済みの
clear_rhythmを示します; - ステレオ幅、相関、バランス;
- Footeのノベルティによる構成の境界に加え、無音、余韻、クリッピング。
さらに、ウィンドウ単位のセグメントタイムライン、LLM向けの短いテキストダイジェスト、2つのファイル間の特徴空間での差分、そしてすべての--from/--toで使用されるフレーム単位で正確なウィンドウ処理(Audio::window)を備えています。
スペクトログラム(cochlea-spectro)。HTKフィルターバンク、viridisカラー、時間目盛り、拍のマーカーを使ったメルスペクトログラムのPNGを生成します。画像上に解析オーバーレイ(ビートグリッド、オンセット、ピッチ)を描画したり、符号付きのA→B差分ヒートマップをレンダリングしたり、曲全体をコンタクトシートに分割してエージェントが1回のビジョン呼び出しで確認できるようにしたりできます。
検証(cochlea-verify)。上で示したアサーションDSLです。同じアサーションをスコアのRON内でverify:の下に記述でき、cochlea render score.ron --verifyで実行すると、機械可読なJSONの失敗レポートを出力して、ゼロ以外の終了コードで終了します。
範囲を厳密に定めた決定性
オーディオはマップではなく畳み込みです。フィルターやディレイは状態を保持するため、サンプルごとの純粋性は契約ではありません。契約は次の3段階です。
| 段階 | 主張 | 適用範囲 |
|---|---|---|
| 1 | 同一の入力に対するバイト単位で一致するPCM | 固定されたCIターゲット(x86_64-linux、固定ツールチェーン);同一マシンでの再現性はすべてのプラットフォームでテスト |
| 2 | プラットフォーム間の特徴量の許容誤差 | 統合LUFS ±0.1 LU、オンセット ±2 ms、ピッチ ±5セント |
| 3 | スペクトログラムの判定基準 | ピクセルごとの許容誤差を設けた画像差分 |
段階1は、次の選択を組み合わせて実現しています。
- DSPパス内のすべての超越関数に
libmを使います。 stdの浮動小数点メソッドは、慣例ではなくclippyの設定で禁止しています。 - 高速数学と暗黙のFMAは使いません。
mul_addも禁止しています。 - 非正規化数はすべての場所で保持します。 これをフラッシュするのはリアルタイム性能のためのハックであり、x86とaarch64では統一的に実行することさえできません。オフラインでレンダリングし、まれに発生する遅い余韻を許容します。
- 加算順序を固定し、f64のマスターバスを使います。
- ボイスはサンプル単位で処理します。 fundspのSIMDブロックパスはスカラーパスと確実に異なるため、禁止しています。
- 解析FFTには
FftPlannerScalarを使います。 これは実行時のCPUディスパッチを行いません。
fundspのノードファミリーごと、ebur128の内部処理、rustfftのディスパッチに関する完全な監査記録は、docs/determinism.mdにあります。
特徴の精度(合成した正解データ、48 kHz)
| 特徴 | テストデータ | 測定値 |
|---|---|---|
| ピッチ(YIN) | 440 Hz の正弦波 | 440.017 Hz — A4 から 0.07 セントのずれ |
| オンセット | 0.5 秒間隔のクリックトラック | オフセット ≤ 4 ms(フレーム中央の規約、ホップサイズ 256 サンプル) |
| 調性 | C メジャーの三和音 | C メジャー、信頼度 0.79 |
| 調性 | I–IV–V–I のパッド進行(デモ) | C メジャー |
| ラウドネス | ピーク −18 dBFS の 997 Hz 正弦波 | −21.0 LUFS(≈ −3 LU の正弦波クレストファクター — 物理現象であり、誤差ではありません) |
| 無音/末尾 | 1 秒のトーン + 1 秒の無音 | 末尾 960 ms、最後に聞こえる音は RMS ウィンドウ 1 つ分以内 |
| クリッピング | 振幅を上げた矩形波、クランプ済み | カウント済み、true-peak-over-0 にフラグ |
| テンポ | 120/90 BPM のクリックトラック | ±1 BPM、パルスの明瞭さ 0.96、clear_rhythm=true |
| テンポ | drum_groove デモ(110 BPM のグルーヴ) | 110.29 BPM(Δ 0.01)、パルスの明瞭さ 0.79、安定度 1.0。55 BPM の半テンポは隠れたコイントスではなく、候補(顕著度 0.89)として表れます |
| リズム | 四分音符のクリックとストレートな八分音符 | どちらもグリッド整合度 1.0、オフビート率は 0.0 対 0.49 — シンコペーションを数値化 |
| リズムの堅牢性 | クリックトラック、人間らしいタイミングの揺れ ±5/±10 ms | BPM は正確、整合度 1.0、clear_rhythm を維持(明瞭さ 0.77 / 0.51) |
| リズムの堅牢性 | クリックトラック、揺れ ±20/±30 ms | BPM は半分のテンポへオクターブ折り返し(拍がぼやけると、2 拍遅れが 1 拍と同じくらい明瞭になる)— ただし整合度は 1.0 のままで、clear_rhythm も維持 |
| リズムの堅牢性 | 22 回のヒット中に 1 回抜け、1 回追加 | BPM と clear_rhythm に影響なし |
| リズムの誤検出防止 | オンセット時刻が一様ランダム | 整合度 0.57(明瞭なリズムの基準値 0.7 に対して)、パルスの明瞭さ 0.10 — 独立した 2 つの判定基準で棄却 |
| テンポとリズム | 一定の速さでパターンが変化(四分音符 → 高密度な八分音符) | 安定度は ≥ 0.75 を維持 — ドラムソロのケース:変わったのはリズムであり、速さではありません |
| テンポとリズム | 実際に速さが変化(バッファ途中で 100 → 140 BPM) | 安定度が ≤ 0.75 に低下 — この軸で両者を区別します |
| スウィング | シャッフル(拍 + 裏拍を 2/3 拍の位置に配置) | grid: triplet、整合度 1.0、clear_rhythm を維持 — 乱れていると判定せず、認識 |
| メロディー | 作成した 3 音(A4 C5 E5) | A4 C5 E5 として読み戻し、60 ms 以内に開始、中心音程は 5 セント以内 |
| 音色 | 同じ音・同じレベルの正弦波とノコギリ波 | MFCC 距離で明確に区別。同一の入力は正確に 0 と測定 |
| 非可逆デコード | 同じトーンを WAV、mp3、ogg で再生 | コーデック間でピッチの差は 5 セント以内 |
| 構成 | 音色の異なる 8 秒のセグメント 2 つ | 実際の 8.0 秒の切り替わりから 1.5 秒以内に境界を検出 |
| 構成 | 8 秒のセグメント 3 つ(A/B/A) | 実際の 8.0 秒と 16.0 秒の切り替わりから 1.5 秒以内に境界を検出 |
設計上、ffmpeg 不要
cochlea は hound と symphonia を使って WAV、FLAC、mp3、ogg/vorbis を読み込みます。どちらも純粋な Rust 製です。通常の WAV ファイルを書き出し、rustfft、手書きのメルフィルターバンク、viridis LUT、image を使って CPU 上で PNG をレンダリングします。
サブプロセスの呼び出し、システムコーデック、GPU、オーディオデバイスは一切ありません。パイプライン全体が純粋な Rust の依存関係グラフであり、CI は GUI、GPU、デバイスのクレートが Cargo.lock に入ることを阻止します(deny.toml)。
デコードには異なる 2 つの保証があり、それぞれの違いを明確にしておくことが重要です。WAV と FLAC のデコードはビット単位で完全に一致します — FLAC は仕様上ロスレスであり、同梱の WAV 版と照合して確認しています。mp3 と ogg は解析入力専用です。同じビルドであれば再現可能ですが、非可逆コーデックは元のサンプルをすでに破棄しているため、完全一致を主張することはできません。
アサーションの活用例
use cochlea_verify::{VerifyExt, Tol, Ms, Cents, Db};
rendered.verify(&score)
// Mix-level loudness and headroom:
.integrated_lufs(-14.0, Tol(0.5)) // streaming-loudness target
.true_peak_below(-1.0) // intersample-safe headroom
// Timing: did the hit land where the score says?
.onset_at("drums", bar(17).beat(1), Ms(5.0))
// Intonation: does every note read as written? (monophonic tracks)
.pitch_matches_score("lead", Cents(10.0))
// Was the sweep *written*? (authored curve, block-rate — a score lint)
.monotone("lead", Param::CUTOFF_HZ, bar(1)..bar(3))
// ...and did it audibly *happen*? (rendered stem's spectral centroid)
.brightness_rises("lead", bar(1)..bar(3), 1.3)
// Do the hits land on the detected beat grid?
.grid_alignment_at_least(0.9)
// Click detection away from note boundaries:
.no_discontinuity("lead", Db(40.0))
// Does the piece actually end?
.silent_after(bar(64))
.run();
同じアサーションをスコアの RON に埋め込めます。
verify: [
IntegratedLufs(target: -14.0, tol: 0.5),
TruePeakBelow(dbtp: -1.0),
OnsetAt(track: "drums", at: (17, 1), tol_ms: 5.0),
PitchMatchesScore(track: "lead", tol_cents: 10.0),
Monotone(track: "pad", param: "cutoff_hz", from: (1, 1), to: (3, 1), direction: Rising),
BrightnessRises(track: "pad", from: (1, 1), to: (3, 1), min_ratio: 1.3),
NoDiscontinuity(track: "lead", db: 40.0),
SilentAfter(at: (64, 1)),
TempoIs(bpm: 110.0, tol_bpm: 2.0),
HasClearRhythm(expected: true),
GridAlignmentAtLeast(min: 0.9),
]
cochlea render score.ron --verify を実行するとアサーションが検証されます。失敗した場合は JSON
({"passed": false, "checks": [...]})が返され、終了コードは 0 以外になります。
音量ターゲットを単にアサートするのではなく、実際に達成するには、スコアにマスターバスを設定します。ゲインで音量を上げ、リミッターで上限を抑えます。
master: Master(
gain_db: 4.0,
limiter: Limiter(ceiling_db: -2.0), // sample-peak ceiling holds exactly
),
verify: [
IntegratedLufs(target: -14.0, tol: 0.5),
TruePeakBelow(dbtp: -1.0), // ~1 dB headroom over the ceiling: true peak is inter-sample
]
動作例を交えたデモが demos/ に 4 つあります。
metronome— サンプル単位で正確なスケジューリングとオンセット許容誤差。chord_pad— ハーモニーが記譜どおりに再生されます。title_cue— 4 小節のシネマティックな短い曲で、LUFS ターゲット、単調なフィルタースイープ、クリックノイズがないこと、フェード後に無音になることをアサートします。drum_groove— 実際のkickパッチとsnareパッチを使った、110 BPM、8 小節のグルーヴです。ハイハットは右、スネアは左にパンされています。検出されたテンポ、グリッドとの一致度が 0.9 以上のHasClearRhythm(true)、ステレオ幅、ラウドネスレンジ、セクション数をアサートします。
drum_groove は、テンポとリズムの分離を促すきっかけになったフィクスチャでもあります。以前の単一の信頼度指標では BPM を正確に検出できていたにもかかわらず、リズムなしと判定され、値は 0.01 でした。
ワークスペース
crates/
score # IR: ticks, tempo map, bar/beat math, notes, automation, master, RON form, MIDI import
synth # Patch trait over fundsp, eleven presets, param registry, counter RNG
render # block engine, voices, stems, f64 master sum + gain/limiter, WAV out
features # LUFS/true peak, onsets, pitch+melody, timbre, chroma/key, tempo, rhythm, stereo, structure
decode # WAV + FLAC (bit-exact) + mp3 + ogg (analysis) -> Audio, pure Rust
spectro # mel spectrogram -> PNG, overlays, diff heat maps, contact sheets
verify # assertion DSL + RON-embeddable specs + JSON reports
cli # the `cochlea` binary
mcp # MCP stdio server (agents call compose/render/probe/verify as tools)
features と spectro は score にも synth にも依存しません。この依存関係は CI で検証されるため、スコアがなくても probe で任意のオーディオファイルを扱えます。
ライセンス
MIT OR Apache-2.0(お好みで選択できます)。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。