tono

Game audio as a pure function — procedural, deterministic, zero-asset.

Author a synthesis graph; get byte-identical audio from Rust, Python, a CLI, or a live keyboard. No samples, no WAVs shipped.

GitHub crates.io Cookbook Architecture

Hear it

Everything below was rendered by the engine — recognizable classics rebuilt from scratch, plus full pieces.

spectrogram of River Flows in You — 800 notes on the sampled piano

The spectrogram the engine drew of its own render — analysis is built in.

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

One engine, four pillars

A sound is a symbolic graph; rendering it is a pure function of (graph, seed, sample_rate).

Deterministic

Byte-identical renders, offline or streamed live — audio you can test, diff, and cache. A golden corpus and a fuzzer pin it in CI.

Zero-asset SFX

A patch renders infinite per-instance variations from named parameters — impacts that scale with collision force, no sample library.

Game runtime

Live DSP buses (reverb/EQ/compressor inserts + sends), polyphony caps with priority stealing, and an embeddable mixer.

Adaptive music

Beat-quantized section switches, intensity-layered stems, stingers landing on the downbeat — a score that reacts to play.

In a few lines

Rust — interactive music

use tono_core::adaptive::{AdaptiveMusic, Quantize};

let mut music = AdaptiveMusic::new(48_000);
music.set_tempo(120.0, 4);
music.add_section("explore", &explore);
let battle = music.add_section("battle", &battle);

// combat! — swaps on the next bar
music.transition_to(battle, Quantize::Bar);
music.set_intensity(0.9);
music.stinger_at(&boss_hit, Quantize::Bar);

Python — live playback

import tono

engine = tono.Engine(48000)
engine.drumkit().note_on(36, 1.0)  # kick
engine.instrument("warm_lead").note_on("C4", 0.9)

impact = engine.load_patch(open("impact.patch.json").read())
impact.trigger(hardness=0.8, size=0.3)  # zero WAVs

The CLI closes the loop: tono render doc.json → audio + spectrogram + waveform + LUFS stats. Author sound by inspection.

Get started

Two commands to the first render; the loop is: write a doc, render, look, refine.

# the CLI
cargo install tono
tono render blip.json -o out/   # → wav + spectrogram + waveform + LUFS stats

# the engine, in a game or tool
cargo add tono-core

New to the codebase? Read the architecture & getting-started guide — the smallest unit (a node) and the ladder up to a full game soundtrack.