Skip to content

Routing

Buses are declared once, summed automatically, and cleared every block.

bus space: stereo
instr pluck(freq: hz) {
out = osc(saw, freq).lpf(cutoff: 900hz)
space += out.gain(-14db)
}
track room {
out = space.reverb(room: 0.8, model: plate)
}
  • bus += x sends a copy; original routing is unchanged.
  • .to(bus) routes output to a bus instead of master.
  • A track’s out goes to master unless routed with .to(bus).

The compiler builds a dependency graph from bus reads and writes and sorts it: all writers to a bus run before readers in the same block. File order is irrelevant; redefinition re-sorts the graph.

Feedback between buses has no valid order — the compiler rejects it and names the loop. Break it with prev, which costs one block (32 samples by default):

track room {
out = space.reverb(room: 0.85)
echo += prev(out).gain(-20db)
}

Inside a single voice or opcode, prev(x) is one sample.

  • Opcode: sig.delay(time: 3/16 beat, feedback: 0.4) — beat times follow tempo.
  • Delay lines as values (write with +=, read with taps):
line = delay_line(max: 2sec)
tap1 = line.tap(3/16 beat)
tap2 = line.tap(5/16 beat, interp: cubic)
line += sig + tap1.lpf(cutoff: 3khz).gain(-6db)
out = sig + [tap1, tap2]

Buffer size is known up front (max: when time is modulated). Short feedback loops (flangers, Karplus–Strong) run per sample automatically. When modulating read position, set interp: none, linear, cubic, or allpass.

Opcodes with lookahead declare latency; parallel paths are delayed to stay aligned. Automatic unless with(compensate: false).

out = drums.split(dry: it, wet: it.limit(ceiling: -1db, lookahead: 5ms)).sum

Signals carry a layout in their type: mono, stereo, quad, surround(5.1), surround(7.1.4), ambi(order: 3), ch[N].

  • split must cover every channel or provide rest:.
  • .each(...) processes every channel of any layout.
  • Prefer pan(azimuth:, spread:) over hard-coded channel names so the same code works on stereo, 5.1, or headphones.
  • Master layout: config { channels: surround(5.1) }.
  • Ambisonics: config { mix: ambi(order: 3) } — buses carry the sound field; decoded at master.

Mismatch overrides: config { upmix: ... } or .to_layout(...).