Skip to main content
Glama

cochlea

CI docs

A headless audio engine for agents. Write a score as data, render it offline to deterministic PCM, then listen through numbers — loudness, onsets, pitch, key, spectrograms — and assert what you heard. Compose → render → probe → verify, with no human ear (and no audio device) in the loop.

Mel spectrogram of first_light.ron: six note onsets followed by a reverb tail decaying to silence

What the agent sees: the mel spectrogram of examples/scores/first_light.ron — the score used in the example below — after render and probe. No PCM in sight.

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);

Or entirely from the command line, score as 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 works on any WAV, plus FLAC (decoded bit-exact), mp3, and ogg — still without ffmpeg, and with no score required. That's the front door: point it at audio you didn't render, and you get the same JSON report and spectrogram an agent uses to review its own work.

How an agent listens

compose → render → probe (JSON) → spectrogram (one vision call) → verify

  1. compose a score as data (RON, or the Rust builder above).

  2. render it to deterministic PCM — cochlea render score.ron --out mix.wav.

  3. probe the mix into a compact JSON report (loudness, onsets, pitch, key, silence, clipping) — cochlea probe mix.wav --json report.json. No image, no audio: the agent reads numbers.

  4. look, when numbers aren't enough — cochlea spectro mix.wav --out spec.png renders one small PNG the agent reviews in a single vision call instead of reasoning about raw samples.

  5. verifycochlea render score.ron --verify runs the score's embedded assertions and exits nonzero on failure. An agent can retry on its own, without a human confirming "yes, that sounds right."

When something in the middle of a long file needs a closer listen, every read tool takes --from/--to. Probe just bars 17–19, or draw a spectrogram of just the drop. The cut is frame-exact, report times are relative to it, and source.start_ms records where it came from. That turns the whole stack into a zoom lens instead of a whole-file-only report.

The economics are the point here, not an afterthought. The first_light render above is 7 seconds of 48 kHz 32-bit-float PCM, which is 2.7 MB. A 3-minute piece at the same settings runs about 66 MB. You would not hand that to an agent as text, and reading it sample by sample is worse.

Its probe report is a few KB of JSON instead. Here is schema v5, trimmed to the interesting fields. Note pitch.melody: the piece's bass line and melody read back as note events, which is the read-back half of the compose loop.

{
  "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 }
}

And the spectrogram is one small image. Here's the title_cue demo — a pad whose cutoff_hz automation sweeps 250 Hz → 5000 Hz across bars 1–3:

Mel spectrogram of the title_cue demo: the quiet band at the top of the frame narrows across the first two bars as the filter sweep lets more high-frequency energy through

The dark band at the top of the frame narrows as the sweep runs, letting more high-frequency energy through over time. An agent reads that straight off the image. The demo's Monotone(track: "pad", param: "cutoff_hz", ...) assertion checks the same thing numerically.

To get a whole piece in one image no matter how long it is, --sheet tiles the spectrogram into a contact sheet instead of one long strip. Two bars per tile here, via --bars-per-tile 2:

Contact-sheet spectrogram of first_light.ron tiled two bars per row

Related MCP server: Talky Talky

Reading audio without a context window

probe --digest skips JSON and prints a deterministic text summary instead: one line per feature dimension, then a windowed timeline capped at about 40 rows. Here's real output for the drum_groove demo — 20.8 seconds and four tracks, with the rhythm, stereo, and structure dimensions all in one screenful:

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  -
     ...

Tempo and rhythm are reported as separate axes, because they change independently. A drum solo can hold a rock-steady pulse while its pattern turns unrecognizable, and that difference is exactly what an agent needs to see.

Here the tempo reads 110.3 BPM, matching the authored 110, and stability 1.00 says the speed never moves across the piece. The alts list surfaces the genuine half-tempo reading at 54.9 BPM — which is actually the stronger raw peak, with the octave prior breaking the tie toward the beat. Metrical ambiguity like that is data an agent can weigh, rather than a coin flip hidden inside the detector.

The rhythm line then says how the hits relate to that pulse: 98% of onsets sit on the beat-subdivision grid and 56% land on off-beat subdivisions, so clear=true. That's an eighth-note hat groove, with its syncopation reported as a number.

Under the pre-0.2.0 metric this same groove read clear_rhythm=false at confidence 0.01. Layering hats, kick, snare, and pad across three metrical levels diluted every lag's share of a mass-fraction score. The grid-based rule asks the right question instead.

The (straight) tag is the grid hypothesis test: alignment is measured against both straight sixteenths and eighth-note triplets, and the report carries whichever more hits land on. A shuffle or swing take reads grid_align=1.00 (triplet) — recognized as an aligned triplet rhythm — instead of being force-fit to sixteenths and scored sloppy.

cochlea diff compares two files in feature space instead of byte-for-byte — "did my change do what I meant," not "is the file bitwise equal." Real output diffing first_light.wav against 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

The timbre row is an MFCC spectral-shape distance, with c0 excluded since that's just loudness. The same instrument re-rendered measures around 0, while swapping a sine for a saw at matched loudness measures well above it. It's the "did the re-render keep the instrument's character" axis, which loudness and pitch can't see.

Add --spectro delta.png and the diff also renders a signed difference heat map: red where B is louder, blue where it's quieter, black where nothing changed. A moved onset shows up as a blue/red vertical pair, and a brightened sweep as a red wedge. What changed becomes visible structure, not just a number.

Diff a render against itself, or a re-render of the same score, and the verdict reads byte-identical instead — the determinism contract above, checked from the outside. --tier2 turns that verdict into a gate: exit 0 for byte-identical or Tier-2-equivalent, exit 1 otherwise, so a CI job or an agent can catch a regression without ever reading a raw sample.

Agents as MCP clients

cochlea-mcp is a stdio MCP server built on the same libraries the CLI uses. It exposes twelve tools — render_score, probe_audio, spectrogram, lint_score, probe_digest, loudness_timeline, beat_grid, audio_diff, import_midi, export_midi, transcribe_audio, and score_reference — each a thin wrapper over the matching library call. Any MCP client gets the same compose → render → probe → spectrogram → verify loop as tool calls, rather than as shelled-out subprocesses.

cargo install cochlea-mcp
claude mcp add cochlea -- cochlea-mcp

What makes it agent-native rather than a CLI in a trenchcoat:

  • It teaches itself. score_reference returns the complete authoring reference — the RON grammar, the live preset catalog with every automatable parameter (generated from the same registry that validates scores, so it can't go stale), all verify: assertions, and a worked example the test suite itself renders. An agent connected cold can compose without ever seeing this repo.

  • It shows, not points. spectrogram returns the image inline as MCP image content (base64 PNG, size-capped), so a client with no filesystem access still gets the one-vision-call review; out_path is optional. annotate: true draws the detected beats, onsets, and pitch onto the image, and audio_diff can return the signed difference heat map the same way.

  • It zooms. probe_audio and spectrogram take from_s/to_s — lean into 42.0–44.5 s of a long file the way a human replays a bar, instead of paying for whole-file analysis every call.

  • It can be confined. cochlea-mcp --root DIR refuses any read or write that resolves (canonically — symlinks and .. included) outside DIR, before touching the filesystem.

Full tool schemas, arguments, and the JSON-RPC framing are in docs/mcp.md.

Install

All nine crates are on 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

Or from source: git clone https://github.com/richer-richard/cochlea && cd cochlea && cargo install --path crates/cli.

Concepts

Score IR (cochlea-score). A score is plain data: tracks, notes, per-parameter automation, a tempo map of step changes, and an optional master section. It serializes to RON (version: 1) and round-trips both ways under test.

Positions read the way you'd say them — bar(3).beat(2) — and durations are exact fractions: Dur::quarter(), "3/16", with dotted and triplet sugar. A position that doesn't land on the tick grid is an error, not something quietly rounded. cochlea import reads Standard MIDI Files with timing intact: SMF ticks land on the grid verbatim, and GM programs become labeled preset guesses.

Integer time is ground truth. Everything is ticks at 960 PPQ. BPM is converted once, up front, to integer nanoseconds per quarter note. Turning ticks into samples is exact rational u64/u128 arithmetic (fenestra-anim's mul_div), applied once when events are scheduled. Nothing accumulates floating-point seconds, nothing reads a wall clock, and a property test holds it drift-free across 10⁹ ticks.

Synth (cochlea-synth). Eleven presets built on fundsp. Eight are subtractive: sine, saw_lead, square_bass, chord_pad (genuinely stereo — its detuned saws pan apart), noise_hat, pluck, kick, and snare. Three are not: fm_bell (harmonic FM with an automatable brightness), marimba (a modal struck bar), and organ (an additive drawbar). There's also a reverb insert.

Each instrument declares its automatable params with a name, unit, range, and default. Scores are validated against that registry, and the same registry generates the authoring reference, so the docs can't drift from the code. All noise comes from a counter-based RNG keyed on (seed, sample_index) — random access, with no stateful generator anywhere.

Renderer (cochlea-render). Audio is rendered in 64-sample blocks, split at event boundaries, so note timing is sample-accurate while automation runs at control rate (~1.3 ms at 48 kHz). Tracks render independently, which is both the parallelism unit and where stems come from for free. Voice allocation and oldest-note stealing are pure functions of the schedule.

The master bus sums stems at f64 in fixed track order, then applies the score's optional master stage: an output gain, and a brick-wall lookahead limiter whose sample-peak ceiling holds exactly (offline, lookahead is just a forward window maximum — no delay line). That's the tool for hitting a LUFS target while leaving TruePeakBelow headroom. With no master section, the mix is byte-equal to the sum of the stems, both by definition and by test.

Features (cochlea-features). One schema-versioned JSON report, covering:

  • loudness — integrated LUFS, momentary max, true peak, and LRA, via ebur128;

  • onsets from spectral flux, and YIN pitch with cents deviation;

  • a quantized melody: note events an agent can diff against what it wrote;

  • an MFCC timbre digest, and chroma plus Krumhansl-Schmuckler key;

  • tempo and rhythm as separate axes — tempo gives pulse clarity, octave alternatives, and windowed stability, while rhythm gives grid alignment (with a straight-vs-triplet hypothesis test), offbeat ratio, and a calibrated clear_rhythm;

  • stereo width, correlation, and balance;

  • structure boundaries via Foote novelty, plus silence, tail, and clipping.

On top of that: a windowed segment timeline, an LLM-sized text digest, a feature-space diff between two files, and frame-exact windowing (Audio::window) behind every --from/--to.

Spectro (cochlea-spectro). Mel spectrogram PNGs, with an HTK filterbank, viridis colors, a time ruler, and bar markers. It can draw analysis overlays on the image (beat grid, onsets, pitch), render a signed A→B difference heat map, and tile a whole piece into a contact sheet so an agent can review it in a single vision call.

Verify (cochlea-verify). The assertion DSL shown above. The same assertions embed in score RON under verify:, and cochlea render score.ron --verify runs them, exiting nonzero with a machine-readable JSON failure report.

Determinism, precisely scoped

Audio is a fold, not a map: filters and delays carry state, so per-sample purity is not the contract. The contract is three tiers:

Tier

Claim

Where

1

Byte-identical PCM for identical inputs

pinned CI target (x86_64-linux, pinned toolchain); same-machine repeatability tested on every platform

2

Feature tolerances across platforms

integrated LUFS ±0.1 LU, onsets ±2 ms, pitch ±5 cents

3

Spectrogram sentinels

image diff with per-pixel tolerance

Tier 1 is bought with a specific set of choices:

  • libm for every transcendental in a DSP path. The std float methods are banned by clippy config, not by convention.

  • No fast-math and no implicit FMA. mul_add is banned too.

  • Denormals are honored everywhere. Flushing them is a realtime performance hack, and x86 and aarch64 can't even do it uniformly. We render offline and eat the rare slow tail.

  • Fixed summation order, and an f64 master bus.

  • Voices tick sample by sample. fundsp's SIMD block path provably diverges from its scalar path, so it's banned.

  • Analysis FFTs use FftPlannerScalar, which does no runtime CPU dispatch.

The full audit trail — per fundsp node family, ebur128's internals, rustfft's dispatch — lives in docs/determinism.md.

Feature accuracy (synthesized ground truth, 48 kHz)

Feature

Fixture

Measured

Pitch (YIN)

440 Hz sine

440.017 Hz — 0.07 cents off A4

Onsets

click track, 0.5 s grid

≤ 4 ms offset (frame-center convention, 256-sample hop)

Key

C major triad

C major, confidence 0.79

Key

I–IV–V–I pad progression (demo)

C major

Loudness

−18 dBFS-peak 997 Hz sine

−21.0 LUFS (≈ −3 LU sine crest factor — physics, not error)

Silence/tail

1 s tone + 1 s silence

trailing 960 ms, last-audible within one RMS window

Clipping

driven square, clamped

counted; true-peak-over-0 flagged

Tempo

120/90 BPM click track

±1 BPM, pulse clarity 0.96, clear_rhythm=true

Tempo

drum_groove demo (110 BPM groove)

110.29 BPM (Δ 0.01), pulse clarity 0.79, stability 1.0; the 55 BPM half-tempo surfaces as a candidate (salience 0.89) instead of a hidden coin flip

Rhythm

quarter-note clicks vs straight eighths

grid alignment 1.0 for both; offbeat ratio 0.0 vs 0.49 — syncopation as a number

Rhythm robustness

click track, ±5/±10 ms human timing jitter

BPM exact, alignment 1.0, clear_rhythm holds (clarity 0.77 / 0.51)

Rhythm robustness

click track, ±20/±30 ms jitter

BPM octave-folds to the half tempo (smeared beats make the two-beat lag as clear as one) — but alignment stays 1.0 and clear_rhythm holds

Rhythm robustness

one dropped + one extra hit in 22

BPM and clear_rhythm unaffected

Rhythm false-positive guard

uniformly random onset times

alignment 0.57 (vs the 0.7 clear-rhythm bar), pulse clarity 0.10 — rejected on two independent gates

Tempo vs rhythm

pattern change at constant speed (quarters → dense eighths)

stability stays ≥ 0.75 — the drum-solo case: the rhythm changed, the speed didn't

Tempo vs rhythm

real speed change (100 → 140 BPM mid-buffer)

stability drops ≤ 0.75 — the axis that separates the two

Swing

shuffle (beats + upbeats at 2/3 beat)

grid: triplet, alignment 1.0, clear_rhythm holds — recognized, not scored sloppy

Melody

three authored tones (A4 C5 E5)

reads back as A4 C5 E5, starts within 60 ms, centers within 5 cents

Timbre

sine vs saw, same note, same level

MFCC distance separates decisively; identical input measures exactly 0

Lossy decode

the same tone via WAV, mp3, and ogg

pitch agrees within 5 cents across codecs

Structure

two 8 s segments, distinct timbre

boundary within 1.5 s of the true 8.0 s cut

Structure

three 8 s segments (A/B/A)

boundaries within 1.5 s of the true 8.0 s and 16.0 s cuts

ffmpeg-free by design

cochlea reads WAV, FLAC, mp3, and ogg/vorbis using hound and symphonia, both pure Rust. It writes plain WAV, and renders PNGs on the CPU with rustfft, a hand-rolled mel filterbank, a viridis LUT, and image.

There are no subprocess calls, no system codecs, no GPU, and no audio device. The whole pipeline is a pure Rust dependency graph, and CI blocks GUI, GPU, and device crates from ever entering Cargo.lock (deny.toml).

Decoding comes with two different promises, and it's worth being clear about which is which. WAV and FLAC decode bit-exact — FLAC is lossless by spec, and it's checked against WAV twins in-tree. mp3 and ogg are analysis input only: reproducible for a given build, but a lossy codec already threw the original samples away, so there's no exactness claim left to make.

Assertion cookbook

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();

The same assertions embed in score 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 runs them; failures come back as JSON ({"passed": false, "checks": [...]}) and a nonzero exit.

To actually hit a loudness target rather than just assert it, give the score a master bus — gain to push, a limiter to hold the ceiling:

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
]

Four worked demos live in demos/:

  • metronome — sample-exact scheduling and onset tolerances.

  • chord_pad — harmony reads back as written.

  • title_cue — a four-bar cinematic sting that asserts a LUFS target, a monotone filter sweep, click-freedom, and silence after the fade.

  • drum_groove — a 110 BPM eight-bar groove on the real kick and snare patches, hats panned right and snare left. It asserts detected tempo, HasClearRhythm(true) with grid alignment ≥ 0.9, stereo width, loudness range, and section count.

drum_groove is also the fixture that motivated splitting tempo from rhythm: the old single confidence metric read it as rhythm-less at 0.01, despite getting the BPM spot on.

Workspace

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 and spectro depend on neither score nor synth — enforced in CI — which is why probe works on arbitrary audio files with no score in sight.

License

MIT OR Apache-2.0, at your option.

Available Tools

12 tools
audio_diffA

Compare two audio files (WAV, FLAC, mp3, or ogg) in feature space (loudness, onsets, pitch, key, timbre distance, per-segment RMS) rather than byte-for-byte, and report a verdict: byte-identical, tier-2 equivalent (within this workspace's cross-platform tolerances), or different (naming which dimensions diverge). Set spectrogram=true to also get a signed A→B difference heat map inline (red = louder in B, blue = quieter, black = unchanged) — 'what changed' as visible structure. Use this to check whether a re-render, edit, or platform change actually altered the audio in a way that matters — a different verdict is a normal, successful answer, not a tool failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
jsonNoAlso append the full CompareReport as pretty JSON after the text summary. Default false.
window_msNoSegment window length, milliseconds, for the per-segment comparison. Default 1000.
spectrogramNoAlso return the signed A→B difference spectrogram as inline image content (requires both files to share a sample rate). Default false.
audio_path_aYesPath to the first audio file (WAV, FLAC, mp3, or ogg).
audio_path_bYesPath to the second audio file (WAV, FLAC, mp3, or ogg).

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It discloses that comparison is in feature space (not byte), reports verdicts with dimension names, and describes the optional spectrogram output with color coding (red/blue/black). It also notes the sample rate constraint for spectrogram. This is transparent, though it does not cover potential side effects, permissions, or file size limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single dense paragraph but remains informative without excessive length. It front-loads the main purpose and then details parameters and usage. The length is appropriate, and every sentence contributes value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must explain return values. It does so by listing verdict categories (byte-identical, tier-2 equivalent, different) and stating that different names diverging dimensions. It also covers optional outputs (json report, spectrogram). For 5 parameters and a complex comparison tool, this is fairly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds value by explaining the spectrogram parameter's output (signed difference heat map with color meanings), the json parameter's effect (append full report), and the window_ms parameter's role (segment window length). It also reiterates supported formats for audio paths. This goes beyond the schema's descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it compares two audio files in feature space (loudness, onsets, pitch, key, timbre distance, per-segment RMS) and reports a verdict. It distinguishes from byte-byte comparison and mentions supported formats (WAV, FLAC, mp3, ogg). This is specific and differentiates from siblings like spectrogram or probe_audio.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use context: 'Use this to check whether a re-render, edit, or platform change actually altered the audio in a way that matters.' It also clarifies that a 'different' verdict is normal and not a tool failure. However, it does not explicitly mention when not to use it or name alternative tools despite the sibling list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

beat_gridA

The full beat grid of a whole WAV, FLAC, mp3, or ogg file, as JSON: every detected beat time (ms), the estimated downbeats, the tempo with its octave-alternative candidates, and a windowed stability score. This is the detail the compact tempo summary inside probe_audio drops — that one keeps only the count and mean interval to stay small. Use it to line events up to the beat, see where the downbeats fall, or weigh a half/double-tempo alternative. All times are measured from the start of the file.

ParametersJSON Schema
NameRequiredDescriptionDefault
audio_pathYesPath to a WAV, FLAC, mp3, or ogg file.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It specifies the output format (JSON), the scope (whole file), units (ms), the measurement origin (start of file), and the relationship to `probe_audio`. It does not mention potential side effects or failure modes, but for an analysis-only tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences long with no wasted words. Each sentence serves a purpose: stating the output, contrasting with `probe_audio`, and listing concrete use cases. It is well-structured and front-loaded with the core function.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that the tool has a single parameter and no output schema, the description is quite complete. It lists all the key output contents (beat times, downbeats, tempo candidates, stability score) and gives usage context. It could mention limitations or error conditions, but for this level of complexity it is sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% as the sole parameter `audio_path` is described as 'Path to a WAV, FLAC, mp3, or ogg file.' The description restates the supported formats but does not add new semantic meaning beyond what the schema already provides, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool returns the full beat grid of an audio file as JSON, enumerating the contained data (beat times, downbeats, tempo candidates, stability score). It also distinguishes itself from the sibling `probe_audio` by explaining that this is the detailed version of the compact `tempo` summary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit use cases are provided: 'line events up to the beat, see where the downbeats fall, or weigh a half/double-tempo alternative.' The alternative for compact tempo needs is clearly identified as `probe_audio`, which keeps only count and mean interval, making the choice between tools explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_midiA

Convert a cochlea RON score into a Standard MIDI File (format 1) — the inverse of import_midi. Timing exports exactly (score ticks become SMF ticks, the tempo map and time signature carry over); instruments become rough General MIDI program labels, since a synth preset isn't a GM instrument. Use this to hand a composed score to a DAW or notation tool, or to round-trip through external MIDI editing.

ParametersJSON Schema
NameRequiredDescriptionDefault
out_pathYesWhere to write the Standard MIDI File (.mid).
score_pathYesPath to a RON score file (data form version 1).

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses that timing is exact, instruments become rough GM program labels (not exact), and output is format 1, providing valuable behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with core purpose, no wasted words, efficient and clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity, complete schema, and no output schema, the description sufficiently covers purpose, behavior, and usage, leaving no critical gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for both parameters. The description adds minimal extra meaning beyond schema, such as clarifying that the output is a Standard MIDI File; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the tool converts a cochlea RON score to a Standard MIDI File (format 1) and explicitly names the inverse tool 'import_midi', clearly distinguishing its purpose from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit use cases: hand a composed score to a DAW or notation tool, or round-trip through external MIDI editing, and implies when not to use (if exact instrument presets are needed) by noting instruments become rough GM labels.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

import_midiA

Convert a Standard MIDI File (format 0 or 1) into a cochlea RON score. Timing imports exactly (SMF ticks become score ticks, tempo events become the tempo map); General MIDI programs map to rough preset families and channel-10 percussion to kick/snare/hat tracks — every mapping guess comes back in the response so you can re-voice the score afterwards. Use this to bring existing musical material into the compose→render→probe loop.

ParametersJSON Schema
NameRequiredDescriptionDefault
out_pathYesWhere to write the imported RON score.
midi_pathYesPath to a .mid/.midi file (SMF format 0 or 1, metrical division).
sample_rateNoSample rate for the imported score (MIDI files carry none). Default 48000.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full disclosure burden. It reveals that timing imports exactly, General MIDI programs map to preset families, mapping guesses are returned, and the score can be re-voiced. However, it does not cover side effects, required permissions, or error behaviors.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of two concise sentences that front-load the core purpose and follow with key use case and behavior details. No extraneous information is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (MIDI import with mapping) and lack of output schema, the description covers essential aspects: timing fidelity, mapping approach, and response contents. It could be more complete by describing the output RON structure explicitly, but it is sufficient for typical usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all three parameters documented inline. The description adds limited extra meaning beyond what the schema already provides (e.g., sample rate default), so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool converts Standard MIDI Files (format 0 or 1) into cochlea RON scores, specifying the verb 'convert' and the resources (MIDI file to RON score). It distinguishes itself from siblings like export_midi by highlighting the import direction and the mapping process.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this to bring existing musical material into the compose→render→probe loop,' providing when to use. However, it does not mention when not to use or alternatives beyond the sibling context, which is acceptable given the tool's unique role.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lint_scoreA

Statically validate a RON score against the instrument/preset catalog — catches unknown instruments or inserts, empty tracks, and other semantic problems without rendering any audio. Use this before render_score to fail fast on authoring mistakes.

ParametersJSON Schema
NameRequiredDescriptionDefault
score_pathYesPath to a RON score file.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It discloses that the tool is static (no audio rendering), catches specific error types, and is non-destructive. Could be improved by mentioning whether it modifies files or output format, but current info is good.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two efficient sentences with zero waste. Front-loaded purpose and usage. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given one parameter, no output schema, and no annotations, the description covers purpose, usage, and key behaviors. Could add return value or error handling details, but current info is largely complete for a validation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (score_path described). The description repeats 'Path to a RON score file' which adds no new meaning beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool validates a RON score against a catalog, catching unknown instruments, inserts, and empty tracks. It uses specific verb 'validate' and resource 'RON score', and distinguishes itself from siblings by mentioning 'use this before render_score'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this before render_score to fail fast on authoring mistakes', providing clear context for when to use and the benefit over alternative. No additional guidance needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

loudness_timelineA

The loudness-over-time curve of a whole WAV, FLAC, mp3, or ogg file, as JSON: momentary (400 ms) and short-term (3 s) LUFS sampled every ~100 ms. This is the dynamics view the single integrated-LUFS / LRA summary in probe_audio can't give — where a mix gets loud, where a gate opens, how the level moves through a build or a chorus. Use it to check whether a change actually moved the dynamics, or to find the loudest moment. Every point's time is measured from the start of the file. (For a windowed analysis with an anchored offset, use probe_audio with from_s/to_s.)

ParametersJSON Schema
NameRequiredDescriptionDefault
hop_msNoSpacing between timeline points, milliseconds. Default 100 (the EBU R128 momentary update rate).
audio_pathYesPath to a WAV, FLAC, mp3, or ogg file.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains the output format, sampling behavior, and that times are measured from the start of the file. It does not explicitly state that the operation is read-only, but the nature of the tool (analyzing audio) implies no side effects; still, a brief note about computational cost or error conditions would push it to 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized: it states the tool's output first, then the use case, and closes with an important time-origin note and cross-reference to an alternative. Every sentence adds value without redundancy, making it quick to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there is no output schema, the description names the expected data (momentary and short-term LUFS) and the file-format support, which is sufficient for an agent to invoke the tool. It also addresses a key subtlety (time origin) and points to an alternative for a different scenario. It stops just short of fully describing the exact JSON structure, but the information provided is enough for typical selection and invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides full descriptive text for both parameters (audio_path and hop_ms), including the EBU R128 context for the default hop. The description adds little beyond the schema, only reiterating the ~100ms sampling and time origin. It does not enrich parameter understanding beyond what the schema gives, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly defines the tool as producing a loudness-over-time curve in JSON, with specific measurement windows (momentary and short-term). It explicitly contrasts this with the integrated-LUFS/LRA summary of probe_audio, making the tool's unique value unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete use cases (checking if a change moved dynamics, finding the loudest moment) and explicitly points to probe_audio as the alternative for windowed analysis with an anchored offset. This is exactly the kind of when-to-use and when-not-to-use guidance that helps an agent select correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

probe_audioA

Extract the full feature report (integrated LUFS/true peak/LRA, onsets, YIN pitch track plus quantized melody notes, MFCC timbre digest, chroma/key, a chord timeline and per-section key (harmony), tempo with octave-alternative candidates and stability, rhythm with grid alignment and a straight-vs-triplet grid call, stereo image, structural sections, silence, clipping — schema v5) from any WAV, FLAC, mp3, or ogg file, no score needed. Use this to 'listen' to audio through numbers: check loudness targets, confirm onset timing or tempo, read back the melody you composed, or see the chord progression. Pass from_s/to_s to zoom into a time window instead of probing the whole file (report times are then relative to the cut; source.start_ms anchors them).

ParametersJSON Schema
NameRequiredDescriptionDefault
to_sNoOptional: analyze only up to this time (seconds into the file).
from_sNoOptional: analyze only from this time (seconds into the file).
audio_pathYesPath to a WAV (8/16/24/32-bit PCM or 32-bit float), FLAC, mp3, or ogg file.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full responsibility. It discloses that times are relative to the cut and anchored by source.start_ms, and lists all extracted features. It does not mention performance, file size limits, or side effects, but for a read-only analysis tool, this is reasonably transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and provides a wealth of detail. However, it is lengthy due to listing many features in the first sentence; a slightly more concise listing or use of categories could improve readability without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of the tool (audio analysis with many output features), the description is highly complete. It covers input formats, output content, use cases, and time-windowing behavior. No output schema exists, but the description implicitly covers what the report contains, making it sufficient for an agent to understand the tool's capabilities.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, but the tool description adds value by explaining the behavior of from_s/to_s: 'zoom into a time window instead of probing the whole file (report times are then relative to the cut; source.start_ms anchors them).' This clarifies the effect and timing, going beyond the schema's simple 'analyze only from this time' description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Extract') and clearly defines the resource ('full feature report') with extensive detail on what is extracted (LUFS, true peak, LRA, onsets, pitch track, melody notes, MFCC, chroma, key, chord timeline, tempo, rhythm, stereo image, sections, silence, clipping). It distinguishes itself implicitly from siblings like 'probe_digest' which likely does a lighter analysis, though not explicitly stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states use cases ('check loudness targets, confirm onset timing or tempo, read back the melody, see chord progression') and explains the optional time windowing ('Pass from_s/to_s to zoom into a time window'). It does not explicitly state when not to use or name alternative tools, but the context makes it clear this is the comprehensive analysis tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

probe_digestA

The token-cheap way to listen to a WAV or FLAC file: a ~40-line deterministic text digest (duration, loudness, onsets, pitch, key, and a windowed timeline table) instead of a full JSON report or raw PCM. Reach for this first when you just need a sense of what's in a file, and only fall back to probe_audio when you need exact numbers to assert against.

ParametersJSON Schema
NameRequiredDescriptionDefault
window_msNoSegment window length, milliseconds, for the digest's timeline rows. Default 1000.
audio_pathYesPath to a WAV or FLAC file.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses that the digest is token-cheap, deterministic, ~40 lines, and provides a windowed timeline table. It does not explicitly state read-only behavior or error conditions, but the context implies passive analysis. Slightly lacking in safety disclosure, but overall good.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero wasted words, front-loaded with the core purpose. Perfectly concise while conveying all necessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description lists the digest's contents (duration, loudness, etc.) and mentions the format (~40 lines, windowed timeline table). It compares to probe_audio, providing context. Missing explicit return structure, but sufficient for most use cases.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for both parameters. The description adds value by linking window_ms to the digest's timeline rows ('windowed timeline table') and reinforcing audio_path's accepted formats (WAV or FLAC). This enhances understanding beyond the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool produces a deterministic text digest for WAV or FLAC files, listing specific fields (duration, loudness, etc.). It distinguishes itself from probe_audio by being a 'token-cheap' alternative, thus achieving high purpose clarity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises to 'Reach for this first when you just need a sense of what's in a file, and only fall back to probe_audio when you need exact numbers to assert against.' This provides clear when-to-use and when-not-to-use guidance, effectively differentiating from siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_scoreA

Render a cochlea RON score (the declarative tick/track/note/automation IR) to a deterministic WAV mix. Use this to turn a composed score into audible PCM before probing or inspecting it. Set verify=true to also run the score's embedded verify: assertions and get the pass/fail report back in the same call.

ParametersJSON Schema
NameRequiredDescriptionDefault
bitsNoPCM encoding for the WAV: 'float' (32-bit, lossless, the render's ground truth — default), '24', or '16' (integer, for a small ordinary file).float
verifyNoRun the score's embedded verify: assertions after rendering and include the report; the tool call reports isError:true if verification fails. Default false.
out_pathYesWhere to write the rendered mix (stereo WAV).
stems_dirNoOptional directory to also write one WAV per track (created if missing).
score_pathYesPath to a RON score file (data form version 1).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses key behaviors: the render is deterministic, and the verify parameter triggers assertions with isError result. However, it does not cover authorization or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with no filler. First sentence states primary purpose, second explains additional feature (verify). Ideal front-loading.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool that writes output to a file and has no output schema, the description covers the key behavior (rendering to WAV and optional verify report). It does not describe the return value format, but the context is sufficient for basic usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds value for the verify parameter (explaining the error behavior) but does not provide additional meaning beyond schema for other parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'render', the resource 'cochlea RON score', and the output 'deterministic WAV mix'. The description distinguishes the tool from siblings like probe_audio or spectrum by specifying its unique purpose of converting a score to audio.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit context: 'Use this to turn a composed score into audible PCM before probing or inspecting it.' This guides the agent on when to use the tool, though it does not mention when not to use it or alternative tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

score_referenceA

The score-authoring reference: the complete RON score grammar (tracks, notes, durations, automation, easing), the live instrument-preset catalog with every automatable parameter and range, all embeddable verify: assertions, and a worked example. Call this FIRST when composing — everything render_score accepts is documented here; do not guess the format.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears the full burden. It describes the tool as a read-only reference with no side effects, which is transparent. A higher score would require mentioning response length or potential limitations, but the core behavior is clearly stated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence plus a directive, front-loaded with the tool's purpose. Every clause adds value: what it covers, why call it first, and what not to do. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's purpose as a reference and no output schema, the description comprehensively lists what it contains: grammar, instrument presets with parameters, assertions, and a worked example. It also connects to render_score, making the context complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are no parameters, and the schema coverage is 100% by default. The description goes beyond the schema by detailing the content returned (grammar, presets, assertions, examples), which fully compensates for the absence of parameters. The baseline is 4 for 0 parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it is a reference for the RON score grammar, instrument presets, assertions, and a worked example. It distinguishes itself from sibling tools like render_score by explicitly being a reference companion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs to 'Call this FIRST when composing' and explains that render_score accepts what is documented here, warning against guessing the format. This provides clear when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

spectrogramA

Render a mel spectrogram (or a tiled contact sheet covering the whole file) from a WAV, FLAC, mp3, or ogg file, for visual inspection of harmonic content, sweeps, or silence. The image comes back inline as MCP image content (base64 PNG) whenever it fits the size cap, so you can look at it directly without filesystem access; pass out_path to also (or instead) write the PNG to disk. Set annotate=true to draw what the analyzers heard onto the image — detected beats (orange ticks, top), onsets (cyan ticks, bottom), pitch segments (magenta lines) — and from_s/to_s to zoom into a time window. Use this when a numeric probe report isn't enough and you want to look at the audio.

ParametersJSON Schema
NameRequiredDescriptionDefault
to_sNoOptional: render only up to this time (seconds into the file).
sheetNoTile the piece into a contact sheet instead of one long strip — useful for reviewing a whole piece in one vision call. Default false. Incompatible with annotate.
from_sNoOptional: render only from this time (seconds into the file).
annotateNoDraw analysis overlays (beat grid, onsets, pitch) on the image. Default false.
out_pathNoOptional: also write the PNG here. Required in practice only when the image exceeds the inline size cap (the call says so if that happens).
audio_pathYesPath to the input WAV, FLAC, mp3, or ogg.
bars_per_tileNoTime sections per tile when sheet is true. Default 8.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavior: inline PNG return, optional disk write, annotate overlays, zoom, sheet mode, and incompatibility between sheet and annotate. It also mentions size caps and practical usage notes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with front-loaded purpose and concise details. Every sentence adds value, though slightly more brevity could be achieved without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and lack of output schema, the description covers all key behaviors: inline vs. disk output, optional analysis overlays, time zoom, and sheet mode. It adequately prepares the agent for common scenarios.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds significant context beyond the schema, such as the purpose of zooming, the meaning of annotate overlays, and the sheet mode's time tiling, making parameter selection more informed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool renders a mel spectrogram for visual inspection of audio files, distinguishing it from numeric analysis tools like probe_audio. It specifies the supported audio formats and the primary use case, making it easy for the agent to select.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to use this tool when a numeric report isn't enough and visual inspection is needed, implying alternatives for other scenarios. While it could be more explicit about when not to use, it provides clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transcribe_audioA

Transcribe a WAV, FLAC, mp3, or ogg file into an editable cochlea RON score — the inverse of render_score, and the arrow that closes the compose loop: hear a sketch, get score back, revise it, render it again. Pitch-tracks the melody, reads its timing against a tempo (detected from the audio unless you pass bpm), quantizes to a note grid, and estimates each note's velocity from its peak level. Deliberately monophonic: it hears one line, so chords, drums, and dense mixes come back as whichever line the tracker locked onto. Every assumption — the tempo, the grid, the preset, clamped or dropped notes — comes back in the response, so treat the result as a draft to re-voice rather than a faithful score.

ParametersJSON Schema
NameRequiredDescriptionDefault
bpmNoTempo to notate against, 1..=4000. Detected from the audio when omitted; a wrong tempo renotates the same sound with odd note values.
ppqNoTick resolution of the written score. Default 960.
gridNoQuantization grid as a note duration ("1/16", "1/8", "1/4", "1/8t" for triplets, "1/8." for dotted), or "none" to keep the analyzer's raw timing. Default "1/16".1/16
presetNoInstrument preset for the transcribed track. Default "sine"; call score_reference for the catalog.sine
out_pathYesWhere to write the transcribed RON score.
audio_pathYesPath to a WAV, FLAC, mp3, or ogg file.
track_nameNoTrack name in the written score. Default "lead".lead

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so exceptionally: it discloses the monophonic limitation, quantize behavior, tempo detection, velocity estimation, and that the result is a draft with assumptions returned in the response. This is far richer than merely stating 'transcribes audio'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but every sentence adds value, explaining purpose, workflow, behavior, and caveats. The opening metaphor is evocative but not strictly necessary; still, it earns its place by reinforcing the tool's role in the compose loop. Slightly less polish would drop this to 3.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters and a complex audio-analysis behavior, the description covers purpose, limitations, output expectations, and integration with siblings. It is complete enough for an agent to select and invoke the tool correctly, even without an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds contextual meaning for bpm (detected unless passed) and grid (quantization), but doesn't go beyond the schema for individual parameters. The schema already adequately documents each parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource ('Transcribe a WAV, FLAC, mp3, or ogg file into an editable cochlea RON score') and explicitly distinguishes itself from siblings by calling out its relationship to render_score. It also sets clear scope with the monophonic limitation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly frames when to use the tool ('the arrow that closes the compose loop') and gives behavioral context, but it doesn't explicitly name alternative tools for cases like polyphonic audio, only implying they exist. This is strong context but lacks an explicit when-not-to-use with alternative names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.2
    • Addedbeat_grid
    • Addedloudness_timeline
    • Addedtranscribe_audio
  2. 7 tool updatesv0.1.1
    • Changedaudio_diff3 fields changed
      • changedInput schema / properties / audio_path_a / description
        Previous value: -"Path to the first audio file (WAV or FLAC)."New value: +"Path to the first audio file (WAV, FLAC, mp3, or ogg)."
      • changedInput schema / properties / audio_path_b / description
        Previous value: -"Path to the second audio file (WAV or FLAC)."New value: +"Path to the second audio file (WAV, FLAC, mp3, or ogg)."
      • addedInput schema / properties / spectrogram
        Added value: +{
        +  "default": false,
        +  "description": "Also return the signed A→B difference spectrogram as inline image content (requires both files to share a sample rate). Default false.",
        +  "type": "boolean"
        +}
    • Addedexport_midi
    • Addedimport_midi
    • Changedprobe_audio3 fields changed
      • changedInput schema / properties / audio_path / description
        Previous value: -"Path to a WAV (8/16/24/32-bit PCM or 32-bit float) or FLAC file."New value: +"Path to a WAV (8/16/24/32-bit PCM or 32-bit float), FLAC, mp3, or ogg file."
      • addedInput schema / properties / from_s
        Added value: +{
        +  "description": "Optional: analyze only from this time (seconds into the file).",
        +  "type": "number"
        +}
      • addedInput schema / properties / to_s
        Added value: +{
        +  "description": "Optional: analyze only up to this time (seconds into the file).",
        +  "type": "number"
        +}
    • Changedrender_score2 fields changed
      • addedInput schema / properties / bits
        Added value: +{
        +  "default": "float",
        +  "description": "PCM encoding for the WAV: 'float' (32-bit, lossless, the render's ground truth — default), '24', or '16' (integer, for a small ordinary file).",
        +  "enum": [
        +    "float",
        +    "24",
        +    "16"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / out_path / description
        Previous value: -"Where to write the rendered mix (32-bit float stereo WAV)."New value: +"Where to write the rendered mix (stereo WAV)."
    • Addedscore_reference
    • Changedspectrogram7 fields changed
      • addedInput schema / properties / annotate
        Added value: +{
        +  "default": false,
        +  "description": "Draw analysis overlays (beat grid, onsets, pitch) on the image. Default false.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / audio_path / description
        Previous value: -"Path to the input WAV or FLAC."New value: +"Path to the input WAV, FLAC, mp3, or ogg."
      • addedInput schema / properties / from_s
        Added value: +{
        +  "description": "Optional: render only from this time (seconds into the file).",
        +  "type": "number"
        +}
      • changedInput schema / properties / out_path / description
        Previous value: -"Where to write the output PNG."New value: +"Optional: also write the PNG here. Required in practice only when the image exceeds the inline size cap (the call says so if that happens)."
      • changedInput schema / properties / sheet / description
        Previous value: -"Tile the piece into a contact sheet instead of one long strip — useful for reviewing a whole piece in one vision call. Default false."New value: +"Tile the piece into a contact sheet instead of one long strip — useful for reviewing a whole piece in one vision call. Default false. Incompatible with annotate."
      • addedInput schema / properties / to_s
        Added value: +{
        +  "description": "Optional: render only up to this time (seconds into the file).",
        +  "type": "number"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "audio_path",
        -  "out_path"
        -]New value: +[
        +  "audio_path"
        +]
  3. 6 tool updatesv0.1.0
    • First observedaudio_diff
    • First observedlint_score
    • First observedprobe_audio
    • First observedprobe_digest
    • First observedrender_score
    • First observedspectrogram

TDQS

A4.3/5.0

Scored across 12 tools

Disambiguation4/5

Each tool targets a distinct artifact or operation: score authoring/validation/rendering, MIDI conversion, full/digest/visual audio analysis, and comparison. The analysis tools do overlap in feature space, but the descriptions explicitly differentiate probe_digest, loudness_timeline, beat_grid, and spectrogram from probe_audio, so an agent can reliably pick between them.

Naming Consistency4/5

The majority of tools follow a clear snake_case two-word pattern (lint_score, render_score, probe_audio, import_midi, transcribe_audio), and the remaining names are still descriptive and readable. Minor deviations exist: spectrogram is a single word, and several output-oriented names like audio_diff, loudness_timeline, and beat_grid are noun phrases rather than verb_noun commands.

Tool Count5/5

Twelve tools is a well-scoped count for a music/audio composition and analysis server. Each tool adds a distinct capability, and there is no obvious redundancy or filler; the set feels intentionally sized for the compose-render-probe-revise workflow.

Completeness5/5

The server covers the full workflow: score reference, validation, rendering, multiple analysis modalities, audio diffing, MIDI import/export, and audio-to-score transcription. The loop from composing a score to hearing, inspecting, comparing, and revising it is fully closed, with no critical dead ends for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides audio inspection, conversion, processing, and generation capabilities via SoX, enabling AI agents to 'hear' and manipulate audio files through structured JSON interfaces.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes audio processing tools (inspect, normalize, trim, fade, gain, filter, speed, reverse) as MCP tools, enabling Claude to manipulate WAV files through natural language commands.
    MIT