Hear it
Recognizable classics rebuilt from scratch — the ▶ links play right on GitHub:
| Sound | Play | The trick |
|---|---|---|
| retro-coin | ▶ | B5 grace note into a held E6 — the interval is the sound |
| jump-8bit | ▶ | exponential square sweep, gone at sustain 0 |
| waka | ▶ | per-note pitch slides alternating up/down — the chomp drawn into the notes |
| nokia-tune | ▶ | 13 notes of Gran Vals on the Karplus-Strong pluck |
| deep-note | ▶ | supersaw tracks gliding from a scattered cluster onto a five-octave D chord |
| river-flows-in-you | ▶ | a complete piano piece — 800 notes on the sampled grand |
| band-demo | ▶ | four instruments, one groove, mixed on the stereo bus |
More in docs/examples/audio/ — game-ready BGM loops and ambient beds, all deterministic renders.
What it is
A sound in tono is a symbolic graph (oscillators → envelopes → filters →
effects → mix); rendering it is a pure function of (graph, seed, sample_rate)
→ byte-identical audio. The same document sounds identical offline, streamed
in real time, or played as an instrument — so audio becomes something you can
test, diff, cache, and ship without asset files.
- Instruments & songs — a polyphonic sequencer, an 11-preset factory bank, a
GM drum kit, catalog voices (piano, bass, guitar, strings…), and a fluent
SongAPI that compiles to a plain document. - Game runtime — an embeddable
Engine/Mixerwith live DSP buses (reverb/EQ/compressor inserts + sends), voice management (polyphony caps, priority stealing), and interactive music (beat-quantized section switches, intensity layers, stingers on the downbeat). - Zero-asset SFX — a
Patchrenders infinite per-instance variations from named parameters (hardness,size, …). Impact sounds that scale with collision force, no sample library. - An ear for critique — LUFS/peak/spectral stats plus spectrogram + waveform images per render, so "does it sound right?" becomes numbers and pictures.
- SoundFont sampler — point the
samplervoice at any free GM bank for real recorded instruments, still deterministic.
Quick start
Render a document and look at what came back:
# out/blip.wav the audio (--format wav|flac|ogg)
# out/blip.png the spectrogram ← look at this
# out/blip_wave.png the waveform ← and this
# out/blip.stats.json peak / RMS / LUFS / spectral / transient analysis
That loop — emit a doc, render, read the images + stats, refine — is all a human or an agent needs to author sound by inspection.
Sampled instruments need a free General MIDI SoundFont once (FluidR3 GM, GeneralUser GS):
wave: "sampler", sf2: "/path/to/gm.sf2", sf2_preset: 0.
One engine, five faces
Every face renders the same SoundDoc byte-identically — pick the surface that
fits your workflow. New to the codebase? Start with the
architecture & getting-started guide.
| Face | What it is | Entry point |
|---|---|---|
| CLI | render → audio + spectrogram + stats | tono render f.json -o out/ |
| Rust library | the engine embedded in a game or tool | cargo add tono-core |
| Python bindings | live engine + deterministic numpy renders | make python |
| Pattern station | Tauri app: FL-style step grid, live audio, undo | make desktop |
| Playground | hear Rust snippets through the speakers | make play EXAMPLE=band |
Use it from Rust
use SoundDoc;
use render;
let doc: SoundDoc = from_str?;
let samples: = render; // byte-identical every run
Game audio, in a few lines each
use ;
// Voice management: a budget + priorities, and a bullet-hell scene stays clean.
let mut engine = new;
engine.set_max_voices;
engine.play_looping_prioritized; // never stolen
engine.play_prioritized;
engine.play; // stolen first
// Live DSP buses: inserts and sends, reusing the streaming effect kernels.
let mut mixer = new_at;
let sfx = mixer.bus;
let reverb = mixer.fx_bus?;
mixer.set_send;
use ;
// Interactive music: react on the beat, like a film score.
let mut music = new;
music.set_tempo;
music.add_section;
let battle = music.add_section;
music.transition_to; // swaps on the next bar
music.set_intensity; // stems swell with the action
music.stinger_at; // lands on the downbeat
Use it from Python
The same engine as a Python extension (crates/tono-py) — live procedural
audio for Pygame / Ren'Py / Arcade, or deterministic numpy renders for anything:
= # owns the output stream + render thread
# kick — the audio thread never touches Python
=
# zero baked WAVs
# …or pull deterministic numpy arrays (testable in CI):
=
Build it with make python (maturin; abi3 wheels for 3.9+ build in CI).
Determinism
The real-time streaming path is byte-identical to an offline bounce (verified
by a fuzzer in CI), and byte-changing kernel upgrades are gated behind a
document engine revision, so old sounds never change. A golden corpus pins
representative renders in CI. Render the same document twice, get the same bytes
— which is what makes audio testable, diffable, and cacheable.
Learn more
- Architecture & getting started — the smallest unit (a node) and the ladder up to a full game soundtrack.
- docs/cookbook.md — the
SoundDocDSL, node vocabulary, instrument table, worked recipes (validated in CI). - docs/runtime.md — embedding the engine + parametric patches.
- docs/ROADMAP.md — where 2.0 is headed.
make help— every target;make verifymirrors CI.
A personal note
Every line of code in tono was written by AI. I didn't write a single line myself — my part was direction: deciding what to build, and holding the project to the same practices and standards I use in the projects where I do still write the code.
If tono helps you in any way — as a game-audio tool, a reference, or just a kick-start on your own project — that makes me genuinely happy. The tokens are already spent; the least they can do is be useful to you too.
⚠️ Notice — versions below 2.0.0
I intend to follow SemVer, but be realistic about what this project is: AI-generated code. Diffs are large, and every release below 2.0.0 may contain breaking changes despite my best intentions.
Once the tool has proven itself, I will cut a 2.0.0 release — that is the point where I start reviewing the code in detail and contributing to it directly. 2.0.0 will be tagged by me, by hand — it is the one release an AI agent is not allowed to cut. Until then, assume that anything below 2.0.0 has not been fully reviewed by me and may contain bugs or security issues I haven't caught.
Use at your own risk.
License
MIT — permissive, no warranty.