oontz · research

The Song Is the Source

Notes toward an audio programming language in which a whole five-minute track is a few kilobytes of text you can read, grep, diff, fork, review, and commit — and which renders to the same audio, every time, on any machine.

Canonical URL https://oontz.music/language
Repository github.com/charley-forey/oontz · outline in docs/THE-LANGUAGE.md
Reference implementation oontz — two independent engines, one format (oontz-song-1)
Status Living document. Written to be forked, argued with, and superseded.

§Abstract

Software acquired version control, code review, package registries, forks, diffs, issue trackers, and a culture of reading each other's work. Music acquired the WAV file. This asymmetry is not a matter of taste or tooling maturity; it is a direct consequence of the artifact each field chose to exchange. Programmers exchange source. Musicians exchange renders. Every downstream capability follows from that one choice.

This article argues that a specific, narrow, and achievable class of language — a declarative, deterministic, whole-song source format with independent runtimes — closes the gap, and that the design space for such languages has been repeatedly half-explored for sixty-five years without anyone landing squarely in the middle of it. We give the history, the semantics, the architecture, the metaphors, the economics, the failure modes, and a conformance checklist precise enough that a reader can build a rival implementation, or a successor language, without asking us anything.

The reference implementation is oontz: an instrument in which kick x...x...x...x... is four on the floor, one character changes the song, and the entire track — arrangement, notes, automation, sound design, even its visuals — is a text document that two independently written engines are held to render identically. It exists to prove that none of what follows is speculative.

0How to read this

This is long on purpose. It is not a manual, a tutorial, or a marketing page; those exist elsewhere and are shorter. It is the document we wanted when we started and could not find: the complete reasoning behind a category of language, written down while the reasons are still fresh, in the hope that whoever builds the next one starts from here instead of from scratch.

Six parts, each readable alone.

If you have thirty seconds, read the nine laws in §5. If you have ten minutes, read Part II. If you are here to build something, Part V is the payload and everything before it is the justification.

A note on the word "language"

Calling this a programming language invites a fight about whether it is one. It is not Turing-complete, has no user-defined functions, no recursion, and no variables. We use the word anyway, in the sense that HTML, SQL, regular expressions, Makefiles, and chess notation are languages: a formal grammar with a defined meaning, written by humans, executed by machines, and argued about by both. §26 explains why declining Turing-completeness is a feature and not a shortfall — and what it costs.

Part I

The problem

Why the artifact you exchange determines everything you can do, and why music picked the wrong one twice.

1The artifact gap

Consider what you can do with a program you have been given, and what you can do with a song you have been given.

You want toProgramRecording
See how it was madeRead the sourceImpossible
Change one detailEdit a lineRe-record it
Compare two versionsdiffListen twice, guess
Take one partCopy the functionStem separation, badly
Find all examples of XgrepImpossible
Suggest a change to someonePull requestSend an email describing it
Know who wrote which partgit blameLiner notes, if lucky
Have a machine improve itEdit the textRegenerate the whole thing
Store 10,000 of themMegabytesGigabytes, and a bandwidth bill

The right column is not a failure of effort. Producers are not less collaborative than programmers, and DAW vendors are not lazy. The right column is what falls out of exchanging a render instead of a source. A WAV file is the output of a process from which the process itself has been discarded. It is a photograph of a building, offered in place of the plans.

You cannot diff two mixes. You cannot fork someone's bassline. You cannot grep a record for "every track that goes into a breakdown at bar 64." You cannot open a song and see how it was made, because the thing that was shared with you was the cake, not the recipe.

1.1 The project file is not a source format

An obvious objection: DAWs do keep the process. An Ableton .als, a Logic project, a Reaper .rpp — these describe how the track was made. Why is that not source?

Because a source format has properties beyond "contains the information," and project files have almost none of them:

The distinction is old and well understood in software. A source file and a memory dump can encode the same computation; only one of them is source. The test is not "does the information survive" but "can a human read it, a machine execute it, and a third party reproduce it without your computer."

1.2 Why this matters more than it sounds

Consider what version control did to programming — not to the mechanics, but to the culture. Before it was universal, code was something you had; after, it became something you shared, reviewed, blamed, bisected, reverted, and learned from by reading. The tooling did not merely make existing practices convenient. It created practices that had not existed: the pull request, code review as a norm, the public portfolio of commits, the ability to learn a craft by reading thousands of examples of it done well.

None of that is available to musicians, and the reason is not cultural. It is that the artifact they exchange does not support it. Change the artifact and the practices become possible; whether they emerge is then a cultural question, which is a much better problem to have.

The claim, stated precisely

We are not claiming that text is better than audio, that producers should learn to program, or that DAWs are bad. We are claiming something narrower: for a large and growing class of electronic music, a complete song can be represented as a small, readable, deterministic text document, and doing so unlocks an entire category of capability that is otherwise unreachable. The recording still exists. It is now a build artifact.

2Six thousand years of text

Music-as-text is not a new idea; it is the default state of music for most of recorded history, briefly interrupted by the twentieth century. Understanding that interruption explains the shape of the problem.

2.1 Notation as lossy compression with a purpose

The oldest known written music is a Hurrian hymn on a clay tablet from Ugarit, roughly 1400 BCE: cuneiform naming intervals and, apparently, performance instructions. What matters is not its antiquity but its strategy. It does not attempt to record the sound. It records the decisions that produce the sound, in a notation that assumes an informed performer.

Every notation since has made the same trade, tuned differently:

SystemEraRecordsAssumes
Hurrian tabletsc. 1400 BCEIntervals, tuningA living tradition
Neumesc. 9th c.Melodic contour, directionYou know the chant already
Guidonian staffc. 1025Absolute pitch on linesYou can read; rhythm is loose
Mensural notation13th–16th c.Pitch and durationA shared rhythmic vocabulary
Common practice staff17th c.–Pitch, rhythm, dynamics, articulationTrained performers, instrument conventions
Tablature16th c.–Finger positions, not pitchesA specific instrument
Graphic / text scores20th c.Intent, constraints, proseAn interpreting artist

Two lessons transfer directly to language design.

First: notation is compression against an assumed decoder. Neumes are tiny because the singers already knew the melodies; they encode only the delta. Tablature is precise because it targets one instrument and refuses to be general. Every notation buys concision by assuming context, and the notation's reach is exactly the reach of that assumption. A language for techno can be dramatically smaller than a general music language because it may assume a kick drum, a 4/4 grid, and a sixteenth-note resolution. That is not a limitation smuggled in; it is the source of the concision.

Second: notation shapes what gets composed. Mensural notation made rhythmic polyphony thinkable: once durations were writable, composers wrote music that required them. The staff's five lines biased Western music toward pitch-set thinking. Tablature produced idiomatic guitar figures nobody would derive from a staff. This is the musical case of a general principle — the Sapir–Whorf question is contested for natural language and obviously true for notations, because a notation is not a description of thought but a workspace for it.

Consequence for designers

Whatever your notation makes cheap will get made. If probability is one character, people will write probabilistic music. If polymeter requires a declaration, almost nobody will use polymeter; if it falls out of writing a five-character pattern next to a sixteen-character one, it will appear everywhere. You are not designing a way to write music. You are designing which music is easy to think.

2.2 The interruption

In 1877 the phonograph made it possible, for the first time, to exchange the sound rather than the instructions. Within a century that became the default: the artifact of music was a recording, the score demoted to professional infrastructure, and — critically — an entire genre of music grew up that had no score at all. Electronic and sample-based music is composed in the studio, in the act of recording. There is no prior document. The render is the original and the only.

This is why the gap is worst precisely where the tooling is most digital. Classical music kept a portable text format for four hundred years. Techno, born digital, has never had one — the most computational music in history is the least readable.

2.3 The plain-text survivors

Three text formats from the pre-web era are worth studying closely, because they solved preservation problems that any new format will face.

ABC notation (Chris Walshaw, 1991) encodes folk tunes in ASCII: a header of metadata, then melody as letters with modifiers. It was designed to be emailable and typeable, and it has outlived nearly every application that ever read it. There are thousands of tools, hundreds of thousands of tunes, and a spec that has changed slowly and compatibly for three decades. Its lesson is not syntactic — its syntax is wrong for anything but monophonic folk melody — it is institutional: a versioned formal spec, a canonical corpus, and multiple independent implementations produce a format that outlives its authors' careers.

MML (Music Macro Language, from late-1970s Microsoft BASIC and then a generation of Japanese home computers and chiptune trackers) encoded notes as terse command strings: cdefgab for pitches, numbers for lengths, o for octave, t for tempo. It is the direct ancestor of every "pattern as string" system, and it demonstrated that a notation optimized for typing speed develops a different aesthetic from one optimized for reading — a tension we return to in §9.

Tracker formats (Ultimate Soundtracker, 1987, and the MOD/XM/IT lineage after it) are the most underrated ancestor of this work. A tracker module is a complete song in one file: patterns as a grid of rows and channels, an order list sequencing those patterns, instruments, and effects columns — plus the samples. That was a genuinely whole-song format two decades before anyone used the phrase "music as code." Two properties are worth stealing outright: the grid is the interface (a pattern is spatially legible; you see the groove), and an order list separates material from arrangement (write the drop once, play it four times). Two properties are worth refusing: the samples make it big and unportable, and the effect columns are a hex-coded per-vendor mess that only an expert can read.

3The computer-music lineage

Sixty-five years of research languages, each of which solved something real. A designer who has not read this history will re-derive its mistakes. What follows is deliberately opinionated: for each, what it proved and what it costs.

3.1 Music-N and the unit generator (1957)

Max Mathews wrote MUSIC at Bell Labs in 1957 and it played seventeen seconds of sound on an IBM 704. By MUSIC III (1960) he had invented the idea that still organizes the entire field: the unit generator. An oscillator, an envelope, a filter are boxes with inputs and outputs; a sound is a graph of them. And the second idea, equally durable: the split between the orchestra (instrument definitions) and the score (a list of timed events that play them).

Nearly every system since is a variation. Csound (Barry Vercoe, 1986) is Music-N with a bigger opcode library and forty years of momentum. Its orchestra/score split is exactly Mathews'. The unit generator survives in SuperCollider's UGens, in Max/MSP's objects, in Web Audio's nodes, in every modular synthesizer ever built.

What it proved: a signal graph is the right model for synthesis, and separating "how it sounds" from "when it happens" is the right first cut.

What it costs: the score is a list of events, so a song is long. Csound scores are generated, not written. The orchestra is a full programming problem, so the beginner's first sound is far away. The format describes signal flow superbly and song structure not at all.

3.2 MIDI (1983) — the standard that made the wrong thing standard

MIDI is the most successful music interchange format in history and a cautionary tale in equal measure. It standardized performance events: note on, note off, velocity, controller changes, on sixteen channels. It is universal, forty years old, still shipping, and it made the modern studio possible.

But a Standard MIDI File is a tape of gestures, not a document of decisions. It records that a note began at tick 1920 with velocity 96; it does not record that this is the second bar of the drop, that the bassline is the motif transposed, that the filter sweep is a build. It has no notion of sections, of song structure, of why. And crucially it says nothing about timbre: the same file is a piano on one machine and a marimba on another, which is the entire reason General MIDI existed and the entire reason it sounded bad.

What it proved: a small, stable, boring interchange format beats a beautiful one, and it wins for decades. Also: it is worth supporting. oontz emits Standard MIDI Files because a format that cannot leave for a DAW is a trap, however elegant.

What it costs: everything above the event layer. MIDI is the assembly language of music, and forty years of the industry treating it as the interchange layer is a large part of why no higher-level interchange layer exists.

3.3 The live-coding generation

From the mid-1990s, a distinct tradition: languages designed so that editing the program while it runs is the performance.

SuperCollider (James McCartney, 1996) made the decisive architectural move: split the language (sclang, where you write patterns and logic) from the audio server (scsynth, which knows only about synth graphs and messages). They talk over OSC. The consequence is that the language can crash, be replaced, or be driven by something else entirely without the audio stopping. This separation is correct and we adopt it in a different form (§16).

ChucK (Ge Wang and Perry Cook, 2003) contributed strongly-timed programming: time is a first-class type, the program advances it explicitly (1::second => now;), and concurrency is sample-accurate. It is the cleanest treatment of time as a language construct anyone has produced, and it deserves more influence than it has.

TidalCycles (Alex McLean, from 2009) is the most important recent contribution to notation. Its pattern is not a list but a function from a span of time to a set of events — a genuinely functional-reactive model in which a cycle is the unit and patterns compose algebraically. Its "mini-notation" packs rests, subdivision, repetition, alternation, polymeter and probability into a few characters. Tidal is embedded in Haskell, which is both its power (real function composition over patterns) and its ceiling (the audience is people who will learn Haskell).

Sonic Pi (Sam Aaron, 2012) is the philosophical outlier and, by reach, the most successful: it was designed to teach programming to children in classrooms, and it is ruthless about the first ten seconds. Two lines make a sound. It is joyful on purpose. Its lesson is not technical at all — it is that time-to-first-sound is a design parameter with more impact than any feature in your feature list.

Strudel (2022–) ports Tidal's semantics to JavaScript in the browser, with a strict parser → AST → interchangeable outputs pipeline. It proves the browser is a serious runtime for this work, and its architectural discipline — text parses to structure, structure feeds multiple outputs (WebAudio, MIDI, OSC) — is the correct shape.

Others worth knowing: Extempore and Impromptu (Andrew Sorensen) for live-coded systems programming with temporal recursion; Overtone (Clojure over SuperCollider); Gibber (browser, live-coded, notated visually); ORCA (Devine Lu Linvega) — a two-dimensional esolang where operators are letters on a grid and the program is visibly alive, the most radical rethink of the music-notation surface in twenty years; Alda (text-first score language, deliberately unglamorous); Faust (functional DSP that compiles to C++/WASM, the right answer for writing the DSP layer); Nyquist (Roger Dannenberg — functional, behavioural abstraction, sound as a first-class value); bytebeat (Viznut, 2011 — a single C expression over a sample counter produces music, the extreme point of the compression axis and a genuinely useful thought experiment about how little text a song requires).

3.4 The algorave context

Live coding grew a performance culture — TOPLAP (2004) and its manifesto's famous demand to "show us your screens," then the algorave movement from 2012 — in which the projected source code is part of the show. This matters here for a non-obvious reason: it established, in front of real audiences, that an audience will look at code while dancing to it and that the code being legible is part of the aesthetic. That is empirical evidence for a readability-first notation, gathered in the least academic setting imaginable.

4The hole in the middle

Place the prior art on two axes. The first: how much of a song does the artifact contain? — from a single sound, through a loop, to a whole arranged track. The second: who can read it? — from "specialist programmer" to "anyone."

the hole whole song · anyone can read · portable · deterministic readability → anyone can read it scope → the whole song Faust Csound orchestra SuperCollider ChucK TidalCycles Strudel Sonic Pi bytebeat Csound score tracker module MIDI file MML ABC notation staff score DAW project file oontz
The axes are impressionistic, the conclusion is not: the systems that describe a whole song are unreadable, and the systems that are readable describe a fragment or the wrong genre. Positions are arguable; the empty quadrant is not.

Systems cluster in three corners and avoid the fourth.

The unoccupied quadrant has a precise specification:

The thesis

A complete modern song as canonical text: human- and machine-editable, versionable, diffable, searchable, forkable with provenance, small enough to paste anywhere, and rendered identically by independent runtimes.

Every clause is load-bearing. Drop "complete" and you have Tidal. Drop "readable" and you have MIDI. Drop "identical runtimes" and you have a DAW project. Drop "small" and you have stems.

The rest of this document is what it takes to build in that quadrant.

Part II

The theory

The laws, the semantics, the models of time, and the notation theory. This is the part that transfers to a language sharing none of our syntax.

5Nine laws

Every non-trivial decision in the reference implementation traces to one of these. They are stated as laws rather than principles because in practice they function as constraints that veto designs, not as values that inspire them.

Law 1 — The source is the song

The text is not a description of the music, a project file for it, or a recipe you follow to recreate it. It is the music, in the same sense that an HTML file is the web page. Audio is a build artifact, produced on demand, discarded without loss. If your format needs the render to be kept alongside it, the format is incomplete.

Law 2 — Determinism is non-negotiable

The same source produces the same audio: on any machine, in any year, in any conforming runtime. Not "similar," not "musically equivalent" — sample-identical, up to the float behaviour of the host. Determinism is what makes the source authoritative; without it the render creeps back to being the real artifact, and every other property in this list quietly dies with it.

Law 3 — Legibility beats expressiveness

Any notation extension must pass the guessability test: someone who has never programmed, shown one example, can guess what it does. x... *4 passes. x? passes — "that hit… maybe." Nested polymetric alternation with a Euclidean modifier does not, and stays out. This law costs real expressive power and is worth it, because the audience for a music language is not the audience for a programming language.

Law 4 — The whole song or nothing

A loop is not a song. The format must carry arrangement, sections, transitions, automation, sound design and metadata, because the difference between a sketch and a track is exactly the material a loop-shaped format discards. This is the clause that separates this class of language from the entire live-coding tradition.

Law 5 — One source, many runtimes

At least two independent implementations, held to identical musical output by an automated gate. Not for redundancy — as proof that the spec is the spec and not a description of one program's behaviour. A format with one implementation is that implementation's save file wearing a costume.

Law 6 — No hidden state

Everything that affects the sound is in the document. No preferences, no machine-local config, no "you had to have the plugin," no random seed living outside the text. If a knob matters, it is written down; if it is not written down, it does not matter.

Law 7 — Ten seconds to the first sound

From arriving to hearing something you made: ten seconds, no install, no account, no signup wall, no sample pack download. This is not marketing. It is the single highest-leverage design constraint in the entire system, and it kills entire architectures — see §13, where it eliminates server-side rendering outright.

Law 8 — Fail open, never fail silent

A creative tool must not crash, and must not lie. An unknown effect is skipped and reported, not fatal. An unreachable API degrades to the offline page rather than a spinner. A pattern with a typo plays what it can. Losing someone's work is the one unforgivable outcome; a wrong sound is recoverable, a lost session is not.

Law 9 — Text is the API

Every capability — editing, generating, sharing, AI collaboration, testing, export — operates on the same document. There is no privileged internal representation that some features get and others do not. A feature that needs a side channel is a design error, discovered early and cheaply.

5.1 What the laws forbid

Laws are useful mainly for what they exclude. In our case they killed, at various points, all of the following — each of which was proposed, sounded reasonable, and is incompatible with the list above:

ProposalKilled byWhy
Sample library1, 2, 6The song stops being self-contained; the render depends on files
Server-side audio rendering7200 ms round trip; you cannot play an instrument through it
VST/plugin hosting2, 5, 6Non-deterministic, non-portable, unimplementable in a second runtime
Global random seed2, 6Same source, different audio — the one thing that cannot happen
Live-coding evaluation semantics4Optimizes for the session; leaves no finished document
Turing-complete scripting2, 3Halting, unbounded cost in an audio callback, unreadable songs
Binary "compiled song" format1, 9Undiffable, ungreppable — the entire value proposition inverted
Account required to play7Ten seconds becomes ninety and most people never arrive

6A song is a pure function

Here is the whole semantic model, and everything else in the architecture is a consequence of it.

state_at(bar) → the fully resolved state of every track at that absolute bar
render(state)  → the samples for one bar

A song is a function from bar index to state, composed with a function from state to audio. Both are pure. That is the entire model.

6.1 Why purity is the right frame

The obvious way to build a sequencer is as a state machine: a playhead advances, events fire, handlers mutate a global mixer. Every DAW works this way internally, and it is the wrong model for a document, for four reasons that all follow from the same root.

This is denotational semantics applied to music: define what a program means as a mathematical object, and let the implementation be any machinery that computes it. The meaning of a song is a function from time to sound. Everything an engine does is an optimization of that function, and every optimization is checkable against it.

6.2 Sections hold snapshots, not diffs

Given a song made of sections — intro, build, drop, break — there are two ways to represent them. As diffs: "the drop is the build plus a second bass and minus the reverb." Or as full snapshots: each section carries the complete state of every track.

Diffs are tempting. They are smaller, they express the way sections are often made ("copy the build, add stuff"), and they feel more elegant. They are the wrong choice, and the reasoning generalizes far beyond music:

The cost is redundancy: eight sections that share a kick pattern store it eight times. At the scale of a song — kilobytes — that is free. This is a recurring theme: when the artifact is small, prefer the representation that matches how people think, not the one that saves bytes. The compression argument that would have won in 1987 loses now, and designers carrying instincts from the era of scarce storage will make this call wrong.

6.3 Referential transparency in music

One consequence deserves its own name. Because state_at is pure, a section is a value. It can be copied, named, transposed, compared for equality, hashed. Two sections are the same section if their snapshots are equal — which gives you, for free:

7Models of musical time

The deepest design decision in an audio language, and the one most often made by accident, is what kind of thing time is. There are four viable answers and they produce completely different languages.

ModelTime isExemplarsStrengthCost
Event listA sorted list of timestamped eventsMIDI, Csound scoreUniversal, simple, exactNo structure; huge; unreadable
Cycle / pattern functionA function from a time span to the events in itTidalCycles, StrudelComposes algebraically; infinite; elegantCycles are eternal — arrangement is an afterthought
Imperative clockA variable the program advancesChucK, Sonic Pi, ExtemporeIntuitive; sample-accurate; concurrentProgram state is not a document; not a portable artifact
Timeline of snapshotsAn ordered list of sections, each a full stateTrackers, DAWs, oontzArrangement is native; scrub is O(1); readableLess algebraic; sub-bar structure needs its own layer

7.1 Why the timeline wins for whole songs

The cycle model is intellectually the most beautiful. A Tidal pattern is a function from a time span to events; patterns compose with combinators; everything is infinite and everything is algebra. If your goal is live-coded performance, it is the correct model and nothing else comes close.

But a song is not eternal. A song is 5 minutes 12 seconds long, has an intro, drops at 1:04, breaks at 2:30, and ends. The cycle model can express that — with conditionals on the cycle number, or by sequencing patterns — but it expresses it awkwardly, because arrangement is not what the model is about. Ask a Tidal user for the file that is their finished five-minute track and the question does not quite parse; that is not a criticism of Tidal, it is evidence about what its time model is for.

Conversely, the timeline model makes arrangement the primitive and makes sub-bar structure a secondary concern — which is precisely the right trade for a document format, because arrangement is what distinguishes a song from a loop, and the loop is the easy part.

7.2 The hybrid, and where the seam goes

The honest resolution is that you need both, at different scales, and the design question is where the seam goes. In our reference implementation:

macro time  (bars, sections, arrangement)   → timeline of snapshots
meso time   (one bar, the pattern grid)     → positional string, index = time
micro time  (swing, humanize, slides)       → offsets computed at render

Three scales, three representations, each chosen for what that scale needs: the timeline gives you O(1) scrubbing and legible arrangement; the pattern string gives you a groove you can see; the micro layer gives you the difference between a machine and a musician. Getting these boundaries right is the whole game. A language that uses one representation for all three either cannot express arrangement (cycles all the way up) or cannot express groove (snapshots all the way down).

7.3 Bars, not seconds

A subtle corollary: all internal time is measured in bars and steps, never seconds. Seconds are derived at render time from BPM. This means a tempo change is a one-token edit that re-times the entire song correctly and instantly, automation stays musically anchored, and the whole document is tempo-independent. Formats that bake absolute time — MIDI ticks with a tempo map, audio stems — pay for it forever.

8Determinism and the human

Law 2 demands identical output from identical source. Music demands variation, or it sounds like a machine. These look contradictory. Resolving the apparent contradiction is one of the more satisfying results in this design, and it generalizes to any deterministic system that needs to feel alive.

8.1 The trap: a global random seed

The obvious approach is a seeded PRNG: store the seed in the document, and the "random" variation is reproducible. This fails, and the failure is instructive. A PRNG is a stream: its nth value depends on how many times it has been called. So the moment anything upstream changes — a track is added, a section is reordered, one voice consumes one extra sample of noise, the render order changes — every subsequent draw shifts. The document is technically deterministic and practically chaotic: editing the intro changes the hi-hats in the outro. That violates the same principle that killed diff-encoded sections in §6.2, and for the same underlying reason: order-dependence is spooky action.

8.2 The fix: hash the coordinates

Replace the stream with a pure function of position. Each probabilistic decision is keyed by exactly the coordinates that identify it — which track, which bar, which step — and hashed:

maybe(track, bar, step):
    s = "track|bar|step"
    h = 0
    for ch in s: h = (h * 31 + ord(ch)) & 0xFFFFFFFF
    h ^= h >> 15
    return (h % 1000) < 700          # a 70% chance

The properties this buys are worth enumerating, because each solves a specific real problem:

Design rule, generalized

Never use a stream where you can use a function of coordinates. This applies to procedural terrain, to sharded ID generation, to test fixtures, to any generated content that must be stable under edits elsewhere. The seeded-PRNG habit is one of the most common sources of "why did this unrelated thing change" in generative systems, and the fix is always the same: hash the address, do not advance a stream.

8.3 The three layers of "human"

Groove is not one thing. Three mechanisms, deliberately separate:

Keeping them separate matters because they answer different musical questions ("what feel," "how tight," "how varied") and because a single "humanize" knob that mixes them is unusable — the reason so many drum machines have one and nobody turns it up.

8.4 Determinism has limits, and you should state them

Honesty about the boundary is part of the spec. Two engines, one written in Python with NumPy and one in JavaScript over Web Audio, will make identical musical decisions — every hit, every probabilistic step, every automation value — but floating-point scheduling in a browser audio graph may differ in the last bit. So the guarantee is stated in two tiers:

Claiming bit-identity across runtimes would be a lie, and a spec that lies about its guarantees is worse than one with weaker guarantees. Say what you enforce; enforce what you say.

9Notation as interface

The pattern language is four characters and it is the most consequential design decision in the system.

kick X...x...X...x..x
hat  ..x...x...x.x.x.
oh   ......x.......x.
clap ....x.......x...

x is a hit. X is an accented hit. . is a rest. - is a tie. ? is a maybe. That is the entire core notation, and a person who has never seen it can read that block.

9.1 Iconicity: the notation looks like the thing

Peirce distinguished icons — signs that resemble what they denote — from symbols, which are related to their object only by convention. Most programming notation is symbolic: euclid(5, 16) means a five-in-sixteen Euclidean rhythm only if you know the convention. x..x..x..x..x... is iconic: the spacing on the page is the spacing in time. The visual rhythm of the characters is the rhythm.

This has consequences beyond charm.

9.2 The guessability test, applied

Law 3 says an extension must be guessable from one example. In practice this is a hard filter and it has rejected more proposals than it has passed. The scoreboard:

NotationMeansVerdict
x . X -hit, rest, accent, tieIn. Guessable from the shape
x?a hit, most of the timeIn. "That hit… maybe"
x..x *4that pattern, four timesIn. Multiplication is universal
Uneven pattern lengthspolymeter, automaticallyIn. No syntax at all — 5 against 16 just works
a1~ c2!slide into a1, accent c2In. One glance plus one example
[xx][x.]subdivision groupsDeferred. Guessable, but interacts with length rules
<x .>alternate between cyclesOut. Requires knowing "cycle" is a concept
x(3,8,2)Euclidean with rotationOut. Three unlabelled numbers; not guessable
every 4 (fast 2)conditional transformationOut. This is programming, and that is a different product

Note what the rejections have in common: each is more powerful than what was accepted. The test is not "is this good," it is "does this cost a reader more than it gives them." A language that accepts every good idea becomes a language that only its designers can read — a fate that has claimed a remarkable number of otherwise excellent music languages.

9.3 Polymeter for free — the case study in good design

The single most elegant thing in the notation is something nobody designed. Patterns may be any length, and each is divided evenly across the bar. Write a 16-step kick and a 5-step hat, and the hat cycles against the kick with a period of 80 steps — genuine polymeter, the device behind a great deal of the most interesting rhythmic music on earth, and it required zero syntax. It is not a feature; it is the absence of a restriction that a lazier implementation would have imposed by hardcoding sixteen.

Generalize the lesson: the best features are the constraints you declined to add. Before designing syntax for a capability, check whether removing an assumption gives it to you for nothing. This is the design-space equivalent of deleting code, and it has the same superior payoff profile.

9.4 Two representations, one document

The song exists in two forms, exactly as a program exists as source text and as an abstract syntax tree, and both are text.

The command log (.oontz) — the canonical human source. The exact commands that make the instrument produce the song, one per line, comments with #. This is what you type, what a recording session records, and what git diffs beautifully:

# warehouse — driving techno, the default starting point
bpm 132
swing 6
kick X...x...X...x..x
hat  ..x...x...x.x.x.
oh   ......x.......x.
clap ....x.......x...
bass a1! . a1~ . c2 . a1 . g1! . a1~ . c2 . d2 .
filter bass lp 420 res 0.8
sidechain bass 0.7

Ten lines. 232 bytes. A complete driving techno loop.

The compiled timeline (.song, JSON) — the intermediate representation: the whole arrangement as data, which the composer emits and the players consume. Sections, orders, per-track state, automation, metadata, provenance. A full five-minute composed track is 15–40 KB.

Why both? Because they serve different readers and neither can serve both. The log is for humans and for diffs — it is sequential, imperative, and minimal. The IR is for machines and for structure — it is declarative, complete, and addressable. Attempting one representation for both produces either a JSON blob nobody can hand-write or a command log that tools must re-simulate to understand. Keeping the seam explicit is the same discipline as source-versus-AST in a compiler, and it pays the same dividends.

9.5 Naming, and the cost of cleverness

A final notational point that is easy to underrate: the command names are the words a musician already uses. bpm, swing, kick, hat, clap, filter, sidechain, reverb. Not tempo_set, not sc.amount, not track[0].pattern =. The vocabulary of the domain, used directly, with the argument order that reads as English: filter bass lp 420 res 0.8.

This costs generality — kick is a track name and a voice name and a word — and buys the thing that matters more: a person can write the language before they have read the manual, because they are typing words they already know in the order they already say them.

10Totality and failing open

A compiler that rejects a bad program is doing its job. An instrument that refuses to make a sound is broken. This difference is more profound than it first appears and it should change how you write nearly every error path.

10.1 The instrument is not a compiler

When a programmer's build fails, the programmer fixes it — the feedback loop is intact and the error message is the most valuable output. When a musician's instrument goes silent mid-idea, the idea is gone. Musical work is not recoverable state; it lives in a person's short-term memory and evaporates in seconds. A tool that interrupts to complain has destroyed something that a correct error message does not replace.

So the reference implementation is total in the mathematical sense wherever it can be: every input maps to some output, and there are almost no error paths that stop the music.

InputA compiler wouldAn instrument does
Unknown effect nameError, haltSkip that effect, keep the chain
Pattern with a stray characterSyntax errorTreat it as a rest; play the rest of the bar
BPM of 0, NaN, or 109RejectClamp to the legal range at assignment
Note token that is not a noteErrorSilence for that step; everything else plays
A voice that throwsCrashZero samples for that hit; the bar continues
Automation hook raisingStop the clockReuse the previous bar; count a drop
API unreachableSpinner foreverLocal mode, with a line saying so
Unknown field in a documentReject the fileIgnore it — forward compatibility
Unknown format version—Refuse loudly. The one hard error

10.2 Failing open is not failing silent

The critical qualifier in Law 8. "Fail open" means the music continues; it does not mean the problem is concealed. A skipped effect prints a line. A clamped BPM shows the clamped value. Dropped bars are counted and the counter is visible. The distinction:

10.3 Clamp at the assignment, not at the use

One implementation detail worth stealing verbatim. Tempo is assigned from a dozen places: typed commands, keyboard shortcuts, song sections, the composer, automation, a loaded file, a shared URL. One bad value makes a bar zero samples long, which the audio callback then divides by.

The lazy-but-wrong fix is to validate at each of the dozen call sites. The right fix is to make the field a property that clamps on write. One guard, enforced by the type, unbypassable, and any future thirteenth caller inherits it. Push validation to the narrowest point through which every path flows. That point is nearly always an assignment, not a use, and finding it is usually the whole work of the bug fix.

10.4 Forward compatibility as a contract

The document carries format: "oontz-song-1". The rules, stated as obligations on readers rather than as hopes:

This is the discipline that let ABC notation survive thirty years and a hundred applications, and it costs nothing to adopt on day one and is nearly impossible to retrofit on day one thousand.

11Metaphors and analogies

Metaphors are not decoration in system design; they are compression for reasoning. The right one lets you predict how the system should behave in a case you have not considered. The wrong one makes you build the wrong thing confidently. Here are the ones we use, what each explains, and — importantly — where each breaks.

11.1 The primary metaphor: HTML

A web page is not a screenshot of a web page. It is source, rendered by anything that speaks the format, differently on every screen, identical in meaning. This is the closest honest analogy to a song as source, and it is the one to reason from.

The webThis language
HTML documentThe song source
BrowserThe engine / runtime
Rendered pixelsRendered audio
"View source"source — the song prints itself
Multiple browsers, one specTwo engines, one format
The page is kilobytes; images are notThe song is kilobytes; the WAV is not
Anyone can save, edit, re-hostAnyone can fork, edit, republish
CSS cascade, DOM, progressive enhancementSections, tracks, fail-open rendering

Where it breaks: HTML is rendered to a static frame; audio is rendered to a timeline under a hard real-time deadline. The browser can reflow when a font loads. An audio engine that "reflows" produces a click, and a click is unforgivable. Everything about the scheduler in §13 exists because of this asymmetry.

11.2 The recipe and the cake

The most useful metaphor for non-technical audiences, and it survives pressure better than most. A recording is a cake: delicious, finished, un-uningredient-able. The source is the recipe: smaller, teachable, adaptable, scalable, and it makes the cake on demand. You can halve a recipe. You can substitute an ingredient. You can see that the previous baker used too much salt. You can hand it to someone in another country and they will produce the same cake.

Where it breaks: recipes are famously under-specified — "season to taste," "bake until golden" — and depend on a skilled human. Our source is not; it is executable, and the determinism law is precisely the promise a recipe does not make. The metaphor sells the value and understates the rigor.

11.3 The seed and the tree

A seed is small, carries the whole plan, and unfolds into something vastly larger. 232 bytes becomes five minutes of stereo audio — a compression ratio of roughly 200,000:1 against the WAV. Useful for explaining why the economics change (§20) and why the format can ride in a URL, a chat message, or a model's context window.

Where it breaks: a seed's unfolding depends on soil and weather; ours must not depend on anything. Growth is generative and variable — determinism is the opposite. Use for the size argument only.

11.4 Source and build artifact

The precise engineering framing, and the one that generates the correct answer to almost any question about what to store. You do not commit binaries. You do not email a colleague your node_modules. You do not archive a PDF and delete the document it was typeset from. The build artifact is reproducible, therefore disposable, therefore not the thing of record.

Applied here: a WAV is a build artifact. A "recording" is a compiled output, the way a PDF is compiled from a document. Storing audio is unnecessary, and a take is simply the text that reproduces it.

Where it breaks: people have feelings about recordings that they do not have about binaries. A specific render, at a specific moment, on specific speakers, is sometimes the artistic object — a live take with a mistake in it that is better than the correct version. The framing is right about storage and wrong about sentiment, and a mature system should let you keep an audio render when you want to, without pretending that is where the value is.

11.5 Chess notation

The most exact analogy in the entire list, and the most underused. 1. e4 e5 2. Nf3 Nc6 is a complete, unambiguous game in a few dozen bytes. It is human-readable to anyone who plays, machine-readable to every engine, searchable across millions of games, diffable, and it has produced an entire literature of annotation, an industry of databases, and a culture in which studying other people's games is how you learn.

Chess got that culture because it had a portable notation for four hundred years. Music, for electronic genres, has not. The analogy predicts what happens if the notation arrives: not "people make music differently," but people start learning from each other's music the way chess players learn from each other's games — by reading it, move by move, at leisure, with the reasoning visible.

Where it breaks: chess notation records only legal moves in a closed, discrete system with no timbre, no continuous parameters and no aesthetics. Ours must encode continuous values and sound design. The analogy is about the cultural consequences of a portable notation, not its structure.

11.6 Knitting patterns, architectural plans, DNA

Three more, each carrying one specific insight:

11.7 Two metaphors to avoid

Equally important, and rarely written down.

"It's like sheet music." Superficially apt and actively harmful. Sheet music is instructions for a performer and is deliberately under-specified — it does not determine the sound, and its incompleteness is the point, because interpretation is where the art lives. Our source is executable and complete. Reaching for this metaphor leads people to propose expressive-marking features ("play it warmly") that have no meaning in a deterministic system, and to expect a human in the loop who is not there.

"It's a DSL." Technically true, rhetorically fatal. The moment you describe it as a domain-specific language you have told your actual audience — musicians — that this is a programming product, and you have told programmers to evaluate it as a language rather than as an instrument. It is an instrument whose interface is text. The distinction determines who tries it, and therefore whether it works.

Part III

The architecture

How it is actually built, with the numbers. The layer cake, the scheduler, the extension mechanism, and the parity discipline that makes the format real.

12The layer cake

Six layers, each with one job, each replaceable without touching the others. The seams are where the value is; the layers themselves are unremarkable.

1 · SOURCE the command log — what a person types kick x...x...x...x... parse 2 · DOCUMENT (IR) sections · tracks · automation · meta format: "oontz-song-1" state_at(bar) 3 · RESOLVED STATE one bar, every parameter settled pure · random-access · O(1) render 4 · SAMPLES one bar of stereo float, soft-limited voices → fx → sidechain → mix 5 · SCHEDULER — slice the bar, one bar ahead the audio callback does nothing else 6 · OUTPUTS — all fed by the same IR speakers (live) WAV / video (offline render) Standard MIDI File (leaves for a DAW) visuals (band energy per track) analysis · diff · search · AI
The critical property is that outputs hang off the IR, not off the audio path. MIDI export, structural search, diffing and AI collaboration all read layer 2 and never touch a sample.

12.1 Why the IR is the load-bearing layer

New designers reach for the parser or the DSP. Both are the easy parts. The document IR is where the design is decided, because every capability you will ever add reads it:

If the IR is right, adding an output is a day. If it is wrong — if, say, it represents drums as pre-baked audio offsets rather than as patterns — then MIDI export is impossible, structural search is impossible, and diffing is meaningless, and you will not discover this until you try the third feature.

Test for a candidate IR

Before writing a line of engine code, write down five outputs you do not intend to build yet — MIDI, notation rendering, a similarity search, a karaoke-style visualiser, a hardware sequencer driver — and check that each is obviously implementable from the IR alone. If any requires information that only exists inside the renderer, the IR is under-specified, and that is much cheaper to learn now than in eighteen months.

13One bar ahead

The hardest engineering constraint in the system is not synthesis. It is the real-time deadline: an audio callback runs every few milliseconds, must return in less time than the buffer it fills represents, and must never allocate, block, take a lock, or garbage-collect. Miss once, and the listener hears a click — and a click is not a bug report, it is the moment somebody decides your software is cheap.

13.1 The three architectures, and why two are dead

ApproachLatencyCost at scaleVerdict
Render server-side, stream audio200 ms+ round tripCPU per listener per secondDead. You cannot play an instrument through it, and free is impossible
Run the Python engine in WASM (Pyodide)10 MB download; GC pauses in the audio pathFreeDead for live. Fine for offline render
Port the DSP to Web AudioSub-10 ms, nativeFree — it runs on the visitor's machineThis one

Note how Law 7 — ten seconds to first sound — does the killing. Server rendering is not rejected on cost grounds first; it is rejected because a 200 ms round trip is not an instrument. The economics only confirm the verdict. When a law is well chosen, it decides architecture questions before you have finished asking them.

13.2 The bar-ahead scheduler

The design that makes real-time safety almost trivial:

# The audio callback slices a pre-rendered bar and does nothing else.
callback(out, frames):
    out[:] = current_bar[pos : pos+frames]
    pos += frames
    if pos >= len(current_bar):
        bar_done()          # swap in the bar rendered ahead; pos = 0

Everything expensive — synthesis, filtering, effects, automation, the whole arrangement engine — happens on another thread, one bar early, into a buffer. The callback is a memory copy and a pointer increment. It cannot glitch because there is nothing in it to be slow.

The numbers that make this work: a cold render of one bar takes roughly 0.2 s; at 132 BPM a bar lasts about 1.8 s. That is a 9× margin. And if a render ever overruns anyway — a pathological effect chain, a busy machine — the callback reuses the current bar and increments a drop counter. The listener hears a repeated bar instead of a click, which is musically almost invisible, and the drop count is displayed rather than hidden (Law 8 again).

13.3 What a bar-quantized world costs

Being honest about the trade, because it is a real one. Edits take effect at the next bar line, not instantly. Type a new hi-hat pattern and you hear it in up to 1.8 s.

Three reasons this is the right call anyway, and one caveat:

14Voices that ask

How do you add a new sound to a language like this without the core knowing anything about it?

The usual answers are a plugin interface (every voice implements ISynthVoice) or a registry (every voice declares a parameter schema). Both work. Both are ceremony, and both mean the core has an opinion about what a voice is.

The mechanism here is smaller: a voice declares what it wants by naming its parameters, and the core supplies whatever the track has.

def v_bass303(hz, accent, cutoff, res, slide_from): ...
def v_hat(accent, tune, decay): ...
def v_kick(accent): ...

At render time, the core inspects the function's signature and passes the track's values for exactly the names that appear. A voice that asks for hz is by definition pitched, so the pitch machinery engages automatically. A voice that asks for cutoff gets the track's filter frequency. A voice that asks for nothing gets an accent flag and plays.

Consequences:

The general pattern

This is dependency injection by parameter name — the same trick behind pytest fixtures and Angular's original DI. It is worth reaching for whenever you have many small plugins with heterogeneous needs and one caller that holds all the data. The alternative — a uniform interface — forces every plugin to accept a context object and dig through it, which is more code in every plugin so that the core can have less.

Where it stops working: across a language boundary, and in a minified JavaScript bundle where parameter names do not survive. The browser engine therefore uses an explicit small table instead. When a technique does not port, do not port it — port the property (voices declare their needs; the core supplies them) and let each runtime achieve it idiomatically.

15Effects, and the duck

Two details of the audio path that carry design lessons well beyond audio.

15.1 Sidechain is a first-class citizen

In most audio software, sidechain compression — the pumping that makes the bass duck out of the kick's way, the single most characteristic sound in electronic dance music since the 1990s — is assembled from primitives: insert a compressor, route a send, configure a key input, tune four knobs. Perhaps fifteen minutes and some expertise.

Here it is one token: sidechain bass 0.7.

The implementation is a ducking envelope computed once per bar from the kick positions and multiplied into every track that asked for it. It is not a compressor at all — it is the effect a compressor is used to produce, implemented directly, deterministically, and in one line of source.

This is a general principle for domain languages, and possibly the most transferable idea in this document: make the genre's signature move a primitive. A language for techno in which sidechain requires five steps has mis-ranked its vocabulary. A language for the web that made forms hard would be absurd. Look at what practitioners of your domain do every single time, and check that it is one token. If it is three, you have built a general system and called it a domain one.

The corollary is the harder discipline: ranking means demoting things too. Reverb, delay and chorus are ordinary here, expressed the same way as everything else, because they are ordinary in this genre. Generality is the default; primitives are earned by frequency.

15.2 The effect chain that cannot break the song

for name, params in chain:
    fn = FX.get(name)
    if fn is None: continue       # unknown effect: skip, do not crash
    try: x = fn(x, **params)
    except Exception: pass       # a broken effect is skipped, not fatal

Six lines, and they encode Law 8 for the entire effects system. A song using an effect from a newer version of the format plays on an older engine, minus that effect. A malformed parameter costs you one effect, not the track. The alternative — validate the chain up front and refuse — is more "correct" and strictly worse: it converts a partially working song into no song at all, in a context where partial is enormously more useful than nothing.

15.3 Analysis rides along

One more small thing with outsized consequences: while rendering each track, the engine records that track's RMS level and its energy in a handful of frequency bands. It is nearly free — the buffer is already in cache — and it means the visualiser does not need its own FFT of the mixed output. It gets per-track data the mix cannot provide, so a visual can respond to the bass and the hats separately rather than to a single lump of loudness.

The lesson: the renderer knows things nobody else can recover. Analysis performed downstream of the mix is strictly less informative than analysis performed during it. If a later stage will want a measurement, take it where the information still exists.

16Two runtimes, one theory

Law 5 requires at least two independent implementations. This is the most expensive law and the one that most directly determines whether you have built a format or a program.

16.1 What actually ports, and what gets rewritten

The codebase splits cleanly, which is not luck — it is what falls out of keeping the seams pure, and the split is a good diagnostic for whether your own architecture is sound:

LayerPorts?Why
Song model, state_at, automationMechanicallyPure logic, no I/O, no numerics library
Music theory: scales, chords, motifsMechanicallyTables and arithmetic; derived from one shared file
Arrangement grammar, energy curvesMechanicallyPure functions over the IR
Layout, key tables, string-building UIMechanicallyPure
Oscillators and envelopesRewrittenFormulas, not libraries — straightforward, just not shared
Filters, delay, reverbRewrittenWeb Audio has BiquadFilter, DelayNode, ConvolverNode natively
The bar rendererRewrittenBecomes a worklet that renders a bar into a buffer

The proportion is the point: most of a music language is not DSP. The parts that are hard to port are the parts that are also small, formula-shaped, and well-defined. If you find that porting your engine means porting everything, your logic and your numerics are entangled, and the format you think you have is actually an implementation.

16.2 The parity gate

Two implementations that agree in spirit are two implementations. Two implementations held to identical output by an automated test are a specification. The gate:

Plus golden renders within the Python engine: hash the output of a fixed corpus and assert byte-identity across changes. That catches "a refactor changed the sound by 0.001%," which no listening test would ever find and which is exactly how determinism dies — not in one dramatic break but in a slow drift nobody notices until two versions no longer agree.

A format with one implementation is a save file. A format with two implementations that agree by accident is a coincidence. A format with two implementations held identical by a gate is a specification.

16.3 One source of truth for the theory

Both engines derive their music theory — scales, chord tables, Camelot wheel adjacencies, motif transformations — from one file. Not "kept in sync," not "documented in both": generated from one artifact, with a check that fails the moment a copy drifts. The same discipline covers the shared engine file served by two different sites: a byte-comparison test fails if the copies differ.

Duplication you cannot avoid must be duplication you cannot forget. If two copies of something must exist for deployment reasons, the check that they are identical is not optional hygiene; it is the only thing standing between you and a bug that appears on one site and not the other, six months later, with no obvious cause.

17Generation over the IR

The composer — the thing that writes a five-minute arranged track from a genre name and a seed — is not a separate system. It is a pure function that emits the same IR a human edits.

compose(style, minutes, seed) → document

That single design choice has consequences worth spelling out, because the alternative (a generator that plays notes, or that drives the engine directly) is the more obvious build and forecloses all of them:

17.1 Arrangement as grammar

Song structure is remarkably regular within a genre, and that regularity is expressible as a grammar over section roles:

song    → intro build drop break drop2 outro
role    → energy target ∈ [0,1]
section → role × bars × the track state that reaches that energy

Each role carries a nominal energy — intro 0.25, build 0.60, drop 1.00, break 0.30, outro 0.20 — and generation is a walk along a curve through those targets, choosing tracks, densities, filter positions and effects that land near each one. Curves themselves are named and swappable: linear, exponential, logarithmic, eased, stepped.

This is the same insight as the arrangement grammar in generative-music research and the same insight as a tracker's order list: separate what the material is from where it goes. It also makes a song critiqueable — you can score an arrangement against its own declared curve and say "the build does not build," which is a genuinely useful thing to tell a beginner and a completely mechanical computation.

17.2 Where a language model fits

Because the document is text with a small vocabulary, a language model is unusually well suited to editing it — see §22 for why. The architectural point here is narrower: the model's output is commands, not audio. It writes lines you can read, that apply to your song, that you can undo, and that appear in the diff like any other edit.

This is the difference between a collaborator and an oracle. An oracle returns a finished render and you either accept it or ask again — you learn nothing, you cannot take half of it, and your taste never enters the loop. A collaborator hands you source. The posture is a design constraint, not a politeness: the model may only produce artifacts the human can read, partially accept, and edit.

18The proof obligations

A format that claims determinism must prove it continuously, or the claim decays into folklore. Four gates run before anything ships, and their shape is more interesting than their contents.

GateCoversAnswers the question
Engine self-testEvery module, in-processDoes each part still do what it says?
Cross-engine parity + golden renders360 arrangements, byte-hashed outputDo both runtimes still agree, and did the sound change?
Browser gateThe real page, driven in a real headless browserDoes it work where people actually use it?
Site gateThe real server, every asset, share routes, one-tap audioDoes the deployed thing serve what it claims?

18.1 Why "the real thing" is the only useful gate

Two of these four exist because of specific, humbling failures, and the pattern is worth internalising.

A relative script path — src="copy.js" — shipped to production. On the home page it worked. On a share page served at /t/<id> it resolved to /t/copy.js and 404'd, so every shared link anyone opened loaded a page with no words on it. Forty-three green browser tests never saw it, because they tested the app directory statically and the share route lived in a server nothing exercised.

The fix was not a fix for that bug. It was a gate that boots the real server and asserts that every same-origin response is 200, plus a check that no asset path in the page is relative. Both assertions are about the class, not the instance.

The rule this teaches

When a bug escapes to production, the question is never "how do I fix this bug." It is "what assertion, had it existed, would have made this class of bug impossible" — and then, is that assertion cheap enough to run every time. A test that catches one instance is worth little. A test that catches the category is worth the whole incident.

18.2 Golden renders as a cultural device

Byte-hashing the audio output of a fixed corpus is technically a regression test and culturally something more useful: it makes every change to the DSP an explicit, reviewed decision. You cannot casually "improve" the kick. You must change it, see the gate fail, and consciously bless the new hashes with a note about why.

That friction is the point. It converts the sound of the instrument from an emergent property of whoever touched it last into a versioned decision with a paper trail — which is exactly the property Law 2 promises and would otherwise quietly lose, one well-meaning refactor at a time.

Part IV

The consequences

What the design actually buys. Every item here is a capability that is unreachable without a source format and nearly free with one.

19Version control for music

The headline consequence, and the one whose implications are most underestimated, because people evaluate it as a feature rather than as an infrastructure change.

19.1 The diff

Two versions of a song produce a diff that means something:

--- warehouse.oontz
+++ warehouse.oontz
 bpm 132
-swing 6
+swing 12
-kick X...x...X...x...
+kick X...x...X...x..x
 hat  ..x...x...x.x.x.
-filter bass lp 420 res 0.8
+filter bass lp 280 res 0.94

You can read that. The swing doubled, the kick gained a pickup on the last sixteenth, the bass filter closed and got more resonant — it got darker and more acid. That is a legible account of a musical decision, produced by diff, a program from 1974 that knows nothing about music.

Then, at the structural level, a diff of two IRs is a diff of meaning: "the break grew from 8 to 16 bars," "drop2 lost the open hat," "the filter automation now starts 4 bars earlier." No audio comparison can produce those sentences, and no listener can produce them reliably either.

19.2 The practices that follow

Git provides the mechanics; what matters is which human practices become possible. Each of these is standard in software, unavailable in music, and becomes available the moment the artifact is text:

19.3 The hard part: merge

Honesty demands the limitation. Text merge works on a song when two people edit different lines — different tracks, different sections — which is the common case and merges cleanly with no special tooling.

It fails where it fails everywhere: two people editing the same pattern. Line-based merge will produce a conflict, and resolving it by picking one side is musically crude — the two edits may be combinable in a way no text tool can see. Semantic merge for music is an open problem, and a genuinely interesting one: a hit at step 3 and a hit at step 11 added by two people are trivially unifiable, but a pattern rewritten in a different length by both is not. See §29, where this is the first item on the research agenda.

20The economics of kilobytes

The least romantic section and possibly the most consequential, because economics decides who gets to publish.

20.1 The numbers

ArtifactSizeRatio
A loop as source~232 bytes1×
A five-minute arranged track as source15–40 KB~100×
The same track as a 320 kbps MP3~12 MB~50,000×
The same track as 44.1/16 stereo WAV~52 MB~220,000×
The same track as a DAW project with samples200 MB – 2 GB~106×

A five-order-of-magnitude difference is not an optimization. It is a change in what kind of thing the object is, and things change category at that scale.

20.2 What becomes possible below a megabyte

20.3 Why the economics are a moral argument

Under an audio-hosting model, each additional listener costs money, so someone must eventually pay: ads, subscriptions, an upload cap, a rights regime, or a shutdown. Every free music-hosting service in history has faced this and resolved it the same way. Under a source-hosting model, the marginal cost of a listener is the listener's own CPU, because rendering happens on their machine. The service serves kilobytes of text.

That is why the free tier is credible rather than promotional — and why the architectural decision in §13.1 (client-side rendering) and the access decision are the same decision. Sustainable free is an architecture, not a pricing page.

21Searching the music itself

Music search today is search over metadata: title, artist, genre tag, and whatever an audio-fingerprinting model inferred. Search over structure is essentially unavailable outside research corpora, because the structure was thrown away when the recording was made.

With a source corpus, these are ordinary database queries:

21.1 Why this is a research instrument

Musicology of electronic music is bottlenecked on data. Studying how, say, hi-hat density relates to perceived energy across a genre currently means either hand-annotating recordings or trusting a signal-processing pipeline that infers structure with unknown error. Both are expensive, and both introduce a measurement layer between the researcher and the object.

A corpus of source documents removes the inference step entirely. The hi-hat density is not estimated; it is read. Section boundaries are not detected; they are declared. The provenance of a remix is not inferred from similarity; it is recorded.

This makes a class of study cheap that is currently rare: large-N, exact-measurement, longitudinal studies of how a genre's structural conventions actually change, with a ground truth that does not depend on a model. If such a corpus reaches meaningful scale, it is a more valuable research artifact than the instrument that produced it.

21.2 The corpus as a teaching object

The same property makes the corpus pedagogically potent. "Show me twenty builds that work" is a query. So is "show me how this producer's kick patterns changed over two years." Learning from examples requires examples you can read, and this is the first form in which electronic music has them at scale.

22Why machines read this well

Large language models are extraordinarily well suited to this format, and the reasons are structural rather than lucky. Understanding them tells you how to design a format that machines can collaborate on — which is now a first-class design goal rather than a nice-to-have.

22.1 Five structural reasons

22.2 The ladder of collaboration

Four postures, increasing in autonomy, all producing source:

ModeThe modelYou
askExplains what is there, in musical termsLearn something
jamProposes small edits to what you haveAccept, reject, tweak
produceRestructures — arrangement, transitions, mixReview a diff
dreamWrites a whole track from a descriptionTake it apart and make it yours

Every rung returns editable source you watch apply, never a black-box render. That constraint is what keeps the human's taste in the loop: you are always looking at the decisions, so you are always able to disagree with one of them specifically rather than rejecting the whole output.

22.3 The general lesson for AI-era formats

Design for the reader you did not expect

A format that is small, textual, structured, domain-named and verifiable is a format a machine can collaborate on. Every one of those properties was chosen here for a human reason — readability, diffability, portability, determinism — and each turns out to be exactly what a model needs. This is not a coincidence. The properties that make an artifact legible to people are the properties that make it tractable to machines. Optimizing for either gets you most of the other; optimizing for neither gets you a WAV file.

23Teaching and reading

How does anyone learn to produce electronic music today? Watch videos of someone else's screen, in real time, in a tool you must own, and try to replicate mouse movements. It is apprenticeship by shoulder-surfing — the least efficient knowledge transfer humans have.

Compare how programmers learn: by reading enormous quantities of other people's source, at their own pace, with the ability to change a line and see what happens. The difference in throughput is not marginal.

23.1 What a readable song format changes

23.2 The ten-second rule, defended

Law 7 deserves a defence, because it looks like a marketing constraint smuggled into an engineering document.

The reason it is load-bearing: the first sound is the only moment at which a new person decides whether this is for them, and that decision is nearly irreversible. Every second before it is spent on faith, and most people have very little faith available for software. An install step, an account wall, a sample pack download, a "choose your plan" screen — each one loses a large fraction of arrivals, and the fractions multiply.

Sonic Pi's real contribution to the field is demonstrating this in classrooms at scale: children make a sound in the first minute, and that is why it works where more powerful systems did not. It is the most reliably ignored finding in music-language design, because it is not a technical result and therefore does not feel like one.

24Preservation

A question worth asking of anything you build: will this be readable in fifty years?

24.1 The rot rates

ArtifactFails whenRealistic lifespan
DAW projectAny plugin, sample, licence, or app version is missing5–10 years
Proprietary audio formatThe decoder is abandoned10–20 years
WAV fileMedia rots; the format itself is fineMedia-bound
MIDI filePlays, but sounds like a different songIndefinite, lossy
ABC notationNothing; it is text with a spec30+ years, demonstrated
A source songOnly if no conforming engine existsAs long as the spec is implementable

The last row has a condition attached, and the condition is the whole discipline. Text plus a versioned spec plus multiple independent implementations is the configuration that has actually survived — demonstrated by ABC, by TeX, by PostScript, by HTML itself. Text alone is not enough: an undocumented text format with one implementation rots exactly as fast as a binary one, just more legibly.

24.2 What a preservation-grade format requires

The cost of all six is close to zero at the start and effectively infinite later. This is the single cheapest form of insurance in software design and almost nobody buys it.

25Access

A text-first instrument has accessibility properties that graphical music software mostly does not, and they are consequences of the architecture rather than features bolted on.

Worth stating plainly: a text interface is also a barrier for people who think spatially, who cannot type comfortably, or who find a blinking cursor intimidating. The honest claim is not that text is universally more accessible; it is that text is accessible along axes where graphical music software is catastrophically bad, and that those axes have been under-served for decades. The right long-term answer is both — a grid you can paint on and a text form that is the source of truth, which is exactly the tracker's arrangement and remains the correct one.

Part V

Build your own

The payload. Twelve decisions with their tradeoffs, a conformance checklist, the anti-patterns, and the problems we have not solved.

26Twelve decisions

Every audio language makes these choices. Most make several by accident. For each we give the options, our answer, and — more usefully — when the other answer is right, because these are genuine trade-offs and not a list of correct opinions.

26.1 — Scope: fragment, loop, or song?

Options: a sound · a loop · a whole arranged track.
Ours: the whole track. It is the entire thesis.
Choose otherwise if: you are building a performance instrument, where the session is the artifact and arrangement is improvised. Loop scope is correct for live coding and much simpler.
Consequence: whole-song scope forces you to design sections, automation, and transitions on day one. Retrofitting arrangement onto a loop language is the single hardest migration in this space, because the time model has to change underneath everything.

26.2 — Time model

Options: event list · cycle function · imperative clock · timeline of snapshots. (§7)
Ours: timeline of snapshots, with a positional pattern grid inside the bar.
Choose otherwise if: composability of patterns matters more to you than arrangement — take the cycle model, and take Tidal's semantics seriously rather than approximating them.
Consequence: this decision is effectively irreversible. Decide it first, deliberately, in writing.

26.3 — Turing-complete, or not?

Ours: not. No user functions, no recursion, no variables.
Why: three reasons, each sufficient. A song must render in bounded time — an audio callback cannot wait for a fixed point. A readable document cannot contain arbitrary computation, because reading it then requires executing it in your head. And every conforming runtime must implement the whole language, so each construct you add multiplies across implementations forever.
Choose otherwise if: your users are programmers and generation is the point. Extempore and SuperCollider are right to be full languages.
The cost, honestly: some things become verbose. A 64-bar evolving pattern that a loop would express in three lines is written out. We pay it, and mitigate with generation (§17) — a program writes the document; the document stays declarative. That split is the recommendation: keep the computation outside the artifact.

26.4 — Where does randomness live?

Options: global seed · per-object streams · hash of coordinates.
Ours: hash of coordinates. (§8.2)
Choose otherwise: essentially never, for anything that must be stable under unrelated edits. This is the closest thing to a universal recommendation in this document.

26.5 — Samples, or synthesis?

Ours: synthesis only. Not a single sample; the kick is math.
Why: self-containment. A sample-based format needs a sample library, and a song that references files is not portable, not small, not deterministic across machines, and not legally simple.
Choose otherwise if: your genre is sample-defined — hip-hop, breakcore, plunderphonics — where refusing samples refuses the music. Then design the reference mechanism carefully: content-addressed hashes, an embedded tiny-sample option, and a documented resolution order.
Consequence: synthesis-only bounds your timbral range. We accept it because techno is a synthesis genre; that is exactly the "notation assumes a decoder" trade from §2.1.

26.6 — One representation, or source plus IR?

Ours: both. A command log for humans, a JSON document for machines. (§9.4)
Choose otherwise if: your language is small enough that the source is the structure. A pure pattern language may not need an IR at all.
Warning: if you have two, you must decide which is canonical and never blur it. Ours is the log; the IR is derived. A system where both are authoritative will drift, and the bug will be "the song sounds different after a round trip."

26.7 — Text-only, or a GUI too?

Ours: text is the source of truth; visual surfaces edit the text.
The rule: any GUI must be a view over the document, producing edits to it. The moment a control can change something the text cannot express, the format has stopped being the source of truth and every downstream property dies quietly.
Choose otherwise if: never, if you want the properties in Part IV.

26.8 — What is the extension mechanism?

Options: plugin interface · registry with schemas · parameter-name injection · no extension at all.
Ours: parameter-name injection. (§14)
Choose otherwise if: extensions must be sandboxed, or written in another language, or loaded at runtime by untrusted users — then you need a real interface and a real ABI, and you should expect it to cost you determinism.
Consider: no extension mechanism at all is a legitimate and underrated answer for v1. Every voice in the reference implementation is written by the same people who wrote the core; the mechanism exists to keep the core ignorant, not to support third parties who do not yet exist.

26.9 — How immediate are edits?

Options: instant · quantized to a bar · quantized to a phrase.
Ours: quantized to the bar for document edits; instant for performance gestures. (§13.3)
Choose otherwise if: your users are sound designers rather than composers — twiddling a filter and hearing it now is the whole activity, and then you need parameter smoothing and a fundamentally different scheduler.

26.10 — How many runtimes?

Ours: two, gated for parity. (§16)
Cost: real. Every DSP change happens twice, and the gate must be written and maintained.
Why pay it: it is the difference between a format and a program, and — less obviously — the second implementation is where you discover what your spec actually says. Ambiguities that survive one implementation indefinitely surface within days of a second.
Choose otherwise if: you are prototyping. But write the spec as though a second implementation is coming, or you will find that your "spec" is a description of your code.

26.11 — What is the unit of sharing?

Options: a file · a link · a database row · a URL fragment containing the whole song.
Ours: all four, deliberately. A file for git, a short link for chat, a row for the gallery, and the whole song packed into a URL fragment for sharing with no account and no server.
The insight: the fragment form is only possible because the artifact is kilobytes. Small size is not an efficiency property; it is a distribution property, and it unlocks channels that are otherwise closed.

26.12 — Who is this for?

Ours: anyone who can type. Not programmers. Not live-coders.
Consequence: this is the decision that generated Law 3 and the guessability test, and therefore most of the notation. It is the decision that most reliably gets made implicitly — by the designers' own comfort — and it determines everything about the surface. Write it down before you write syntax.

27A conformance checklist

If you are building a language in this class, here is the checklist. It is ordered: each item depends on the ones above it. Anything you skip, you will retrofit at ten times the cost.

The format

The semantics

The notation

The engine

The proof

The product

28Anti-patterns

Failure modes we hit, watched others hit, or came close enough to hitting to have opinions about.

28.1 The expressiveness spiral

Every extension is individually justified; each adds a little power for a little syntax. Twenty extensions later, only the designers can read the language, and the readability that was the original selling point is gone — lost in increments, none of which was the wrong call in isolation. The defence is a written test that a proposal must pass, applied by someone who did not propose it. A rejection log makes the accumulated cost visible.

28.2 Building the DSP first

Synthesis is the fun part and the least important. A beautiful engine with a badly designed document format is a dead end, because the format is what everything else reads. Design the IR, write five songs by hand in it, then build the engine. If hand-writing five songs is miserable, you have learned something enormously valuable for the price of an afternoon.

28.3 The one true representation

Trying to make one text form serve humans, machines, diffs and the renderer. You get a JSON blob nobody can write or a command log tools must simulate to understand. Two forms with an explicit, one-directional relationship is correct.

28.4 Seeded chaos

A global PRNG "for reproducibility." (§8.1) It is reproducible only if nothing upstream ever changes, which is a guarantee no living project can make. Symptom: users report that editing one thing changed another, and you cannot reproduce it.

28.5 The account wall

"Sign in to try it." Every step before the first sound loses a large fraction of arrivals, and the fractions multiply. If storage requires an account, let people work without storage — local state until they want it kept.

28.6 Plugin hosting

The most seductive one, because it seems to buy unlimited timbre for free. It costs determinism, portability, the second runtime, self-containment and preservation — five of the nine laws — in exchange for something a well-chosen synthesis set mostly provides. Refusing plugins is the highest-leverage "no" in the design.

28.7 Optimizing bytes at the expense of clarity

Delta-encoded sections, packed binary fields, clever shared references. At kilobyte scale you are optimizing something free and paying in readability, diffability and mental model — all of which are the product. Instincts formed when storage was expensive systematically mis-rank this.

28.8 Testing the mock

A comprehensive suite over a static copy of the app, while the real server — where the routing, the injection and the share pages live — is exercised by nothing. Forty-three green tests and a blank page in production. Test the thing you ship, in the shape you ship it.

28.9 Treating the AI as a separate product

Bolting a generator onto the side, with its own output format and its own mode. The result is a two-class system where generated songs are not quite editable and edited songs are not quite regenerable. Generation must emit the same document a human edits, or it is a different product wearing your logo.

28.10 Silence as an error message

The specific worst outcome: something is wrong, and the tool responds by making no sound and saying nothing. The user concludes the software is broken — or worse, that they are. Every silence must be explained.

29Open problems

What we have not solved, stated precisely enough to be worked on. This is the research agenda, and contributions to any of it are more valuable than contributions to the instrument.

29.1 Semantic merge

Two people edit the same pattern. Text merge conflicts; musical merge should often succeed. A hit added at step 3 and a hit added at step 11 are trivially unifiable. A pattern rewritten at a different length by both is not. What is the correct merge algebra for patterns, notes, and automation curves? This is the highest-value unsolved problem in the space, because collaboration at scale depends on it, and it is genuinely tractable — the objects are small, discrete and well-typed. Adjacent prior art: operational transformation, CRDTs, and structured-document merge (3DM, GumTree).

29.2 Structural diff that reads like a review

We can diff text and we can diff resolved states. Neither produces the sentence a person would write: "the build is now eight bars longer and the bass enters earlier." What is the right edit-distance metric over song structure, and how do you render it in musical English? Tree edit distance over the section graph is the obvious start; the hard part is ranking which of many valid edit scripts is the one a musician would describe.

29.3 Perceptual equality testing

Golden renders assert byte-identity, which is too strict: a legitimate refactor that changes the last bit fails, and blessing it by hand erodes the gate's authority. Audio similarity metrics are too loose and are not stable under the changes we care about. What is the right equivalence relation for "this is the same song" that is strict enough to catch drift and loose enough to permit refactoring?

29.4 Sub-bar structure without losing guessability

Subdivision groups — [xx][x.] — are the most requested extension and pass the guessability test on their own. They interact badly with the "any pattern length divides the bar" rule that gives us free polymeter. Is there a formulation that keeps both? A wrong answer here costs the most elegant property in the notation.

29.5 Microtiming as data

Swing is one number; real groove is a per-step timing profile that varies by genre, by drummer, by machine. Can a groove be a small, readable, transferable object — a "feel" you apply to a pattern, extractable from a performance and legible as text? MPC-style swing templates and MIDI groove quantize are the industrial prior art; none of it is readable.

29.6 Structural similarity search at scale

Given a corpus of source documents, find structurally similar tracks — not by audio embedding, but over the actual structure. What is the right feature representation and index? This is a well-shaped machine-learning problem with unusually clean ground truth, and nobody has had the corpus to attempt it.

29.7 Notation for timbre

Patterns are beautifully readable. Sound design is a list of parameters, and a list of parameters is not notation — you cannot look at it and hear it. Is there an iconic notation for timbre with the property that x...x... has for rhythm? This may be impossible; the negative result would itself be interesting, and would tell us where the readable boundary of the format actually lies.

29.8 A package registry for music

If a pattern, a groove, or a sound design is a value, it should be distributable, versioned, and depended upon. What does npm for musical material look like, and what are the semantics of a dependency you can hear? The version-resolution question is genuinely novel: a "patch release" of a bassline that sounds slightly different is a breaking change to every song that uses it.

29.9 Formal semantics

The model in §6 is stated in prose and code. A formal denotational semantics for the language would make conformance provable rather than testable, and would let a third implementation be verified rather than compared. Nyquist's behavioural abstraction and Tidal's pattern algebra are the closest existing work.

29.10 Cross-language notation

The pattern characters are language-neutral; the command words are English. Can the command vocabulary be localized without fragmenting the corpus? Compare the failure of localized spreadsheet formulas and the success of localized keyboard layouts — the difference appears to be whether the artifact crosses borders, and songs do.

Part VI

Appendices

Grammar, schema, the hash, glossary, bibliography, and the terms on which all of this may be reused.

AGrammar

The command log, as EBNF. This is the human-facing surface in full; it is deliberately small enough to fit on this screen.

document    = { line } ;
line        = comment | command | blank ;
comment     = "#" , { any } ;
command     = word , { WS , arg } ;

(* patterns *)
pattern     = step , { step } , [ WS , "*" , integer ] ;
step        = "x"        (* hit *)
            | "X"        (* accented hit *)
            | "."        (* rest *)
            | "-"        (* tie: hold the previous hit *)
            | "?"        (* maybe: 70%, hashed on track|bar|step *) ;

(* pitched tracks *)
notes       = note , { WS , note } ;
note        = ( pitch , [ accidental ] , octave | "." ) , { modifier } ;
pitch       = "a".."g" ;
accidental  = "#" | "b" ;
octave      = digit ;
modifier    = "~"        (* slide into this note from the previous *)
            | "!"        (* accent *) ;

(* the commands that matter *)
command     = "bpm"       , number
            | "swing"     , number                        (* percent of a step *)
            | track       , pattern
            | track       , notes
            | "filter"    , track , mode , number , [ "res" , number ]
            | "sidechain" , track , number                (* 0..1 *)
            | "gain"      , track , number
            | "pan"       , track , number                (* -1..1 *)
            | "fx"        , track , name , { param , number }
            | "section"   , name , integer
            | "order"     , { name }
            | ... ;

track       = "kick" | "hat" | "oh" | "clap" | "snare" | "perc"
            | "bass" | "stab" ;
mode        = "lp" | "hp" | "bp" ;

Semantics not captured by the grammar

BThe document schema

{
  "format": "oontz-song-1",
  "name": "warehouse", "bpm": 138, "swing": 8,
  "key": "a", "scale": "minor",
  "order": ["intro", "build", "drop", "break", "drop2", "outro"],
  "sections": {
    "drop": {
      "bars": 32, "role": "drop", "energy": 1.0,
      "order": ["kick", "hat", "bass"],
      "tracks": {
        "bass": { "voice": "reese", "pat": "x.x.x.x.x.x.x.x.",
                  "notes": ["a1", ".", "a1", "c2"], "gain": 1.0,
                  "filt": "lp", "fc": 340, "res": 0.94,
                  "sc": 0.7, "pan": 0, "tune": 0, "fx": [] }
      },
      "automation": [], "master_fx": []
    }
  },
  "meta": { "style": "hardtechno", "curve": "classic" },
  "viz":  { "theme": "acid", "mode": "auto" },
  "remix_of": "a1b2c3d4e5f6"
}
FieldMeaningNote
formatSchema identifierUnknown value: refuse loudly
order (song)Section names in playback orderMaterial and arrangement stay separate
sectionsName → full snapshotSnapshots, not deltas (§6.2)
role, energyWhat this section is for, 0–1What generation walks along a curve
order (section)Track render orderExplicit; render order affects nothing musical but must be stable
pat / notesThe pattern and its pitchesAny length; index is time
scSidechain amount, 0–1The genre's signature move, as one field (§15.1)
automationParameter ramps within the sectionInterpolated inside state_at
vizThe song's own lookA custom palette embeds whole — a track brings its colours with it
remix_ofParent song idProvenance travels in the source

CThe determinism hash

Reproduced in both languages, because a spec that describes an algorithm in prose is a spec with two behaviours. Any conforming runtime must produce identical results from this function.

# Python
def maybe(name, bar, i):
    s = "%s|%d|%d" % (name, bar, i)
    h = 0
    for ch in s:
        h = (h * 31 + ord(ch)) & 0xFFFFFFFF
    h ^= h >> 15
    return (h % 1000) < 700
// JavaScript
function maybe(name, bar, i) {
  var s = name + "|" + bar + "|" + i, h = 0;
  for (var k = 0; k < s.length; k++)
    h = (h * 31 + s.charCodeAt(k)) >>> 0;
  h ^= h >>> 15;
  return (h % 1000) < 700;
}

Design notes, each deliberate: 32-bit unsigned integer arithmetic only, so no float behaviour can differ between platforms; character codes rather than string hashing, so no locale or Unicode normalization is involved; the multiply-add is the classic Java/Bernstein-style construction, chosen for being the one every programmer can reimplement from memory; the xor-shift decorrelates the low bits, which matters because the decision reads them; and the threshold is expressed in parts per thousand rather than as a float comparison.

Do not improve this function. Its only virtue is that two independent implementations agree, and every improvement is a compatibility break for every song ever written.

DGlossary

TermMeaning
BarOne musical measure; the atomic unit of rendering and of edit quantization
StepOne character of a pattern; one bar divided by the pattern's length
PatternA string of steps; index is time, character is what happens
TrackOne voice plus its pattern, notes, and parameters
VoiceA synthesis function that renders one hit
SectionA named span of bars holding a full snapshot of every track
RoleWhat a section is for — intro, build, drop, break — carrying a nominal energy
Energy curveThe intended arc of intensity across a song; what generation walks
AutomationA parameter ramp within a section, interpolated inside state_at
SidechainDucking a track out of the kick's way; the pump. One token here
SwingA systematic delay on odd steps, as a percentage of a step
HumanizePer-track timing jitter in milliseconds
Maybe step? — a hit that happens 70% of the time, decided by coordinate hash
PolymeterPatterns of different lengths cycling against each other
IRIntermediate representation — the compiled timeline document
Command logThe canonical human source: the commands that make the song
Golden renderA byte-hashed reference output that must not change without a deliberate blessing
Parity gateAn automated test that two runtimes make identical musical decisions
Guessability testCan a non-programmer, shown one example, guess what it does?
Fail openKeep playing, say what went wrong; never stop, never conceal

EBibliography

Systems

Ideas

This project

FReuse and citation

This document exists to be used. Fork it, argue with it, take the parts that are right and publish a correction to the parts that are not. The most useful possible outcome is a better language that cites this one as the thing it improved on.

If you build something from this, we would like to know — an issue or a pull request on the repository is enough. If you find an error, the same. If you disagree with a design decision, the rejection log in §26 is where the argument should happen, because that is where the reasoning is written down and therefore where it can be shown wrong.

The Song Is the Source: Notes Toward an Audio Programming Language.
oontz, 2026. https://oontz.music/language

Written alongside the implementation, which is the only reason any of it is specific. Everything claimed here is running at oontz.sh; where something is unsolved, it is in §29 rather than described as though it works.