DSP Blocks
A dsp block is compiled into the audio graph and runs once per sample. The code its functions may
contain is in DSP Code; the functions and constants it can call
are in the DSP builtins reference.
| Declaration | Makes | Entry point | Instantiated with |
|---|---|---|---|
dsp effect Name { … } | an effect | fn process(…) -> … | Name("slot"), placed with track.set_effects(#[…]) |
dsp instrument Name { … } | an instrument | fn render(note, velocity, gate) -> (l, r) | Name(), placed with track.set_instrument(…) |
dsp signal Name { … } | a signal | fn process(…) -> out | Name(…), bound with << |
dsp fn name(…) -> out { … } | a pure function | — | called from dsp code |
dsp object Name { … } | a stateful component | — | let x = Name(); inside dsp code |
Members
Section titled “Members”| Member | effect | instrument | signal | object |
|---|---|---|---|---|
param name: default range(min, max) smooth ms; | ✓ | ✓ | ✓ | — |
state name: initial; | ✓ | ✓ | ✓ | ✓ |
voice state name: initial; | — | ✓ | — | — |
buffer name(size); | ✓ | ✓ | ✓ | ✓ |
input name: stereo; / input name: mono; | ✓ | — | — | — |
output: stereo; / output: mono; | ✓ | — | — | — |
latency: samples; | ✓ | ✓ | — | — |
range: min..max | — | — | ✓ | — |
fn name(…) -> out { … } | ✓ | ✓ | ✓ | ✓ |
param— a control, read by name inside the block and set from outside with.parameter(name),.set_parameterand<<.range(min, max)is optional; it scales normalized values and bounds modulation.smooth msis optional: a value that is set glides to its new value overmsmilliseconds instead of stepping. A bound signal is never smoothed. Withoutsmooth, a set value applies at once. In an instrument, one value is shared by all voices.state— a variable that keeps its value from one sample to the next.voice state— astateof which every voice has its own copy, set back to its initial value on each note-on. In an instrument, a plainstatecurrently behaves the same way.buffer name(size)—sizenumbers, all0at the start. An index is truncated to a whole number and wraps modulosize, sobuf[size]isbuf[0]; a negative index reads and writesbuf[0]. In an instrument, every voice has its own buffers, cleared on each note-on.latency: samples— the delay the block adds, in samples, on top of what the engine computes for its graph. Default0. See Declare Latency.range: min..max— the span of a signal’s output. Default-1..1. It takes no;.
Transport and MIDI
Section titled “Transport and MIDI”The clock constants CPS, BPC, CYCLE, TIME, CYCLES, POSITION, CYCLE_PHASE,
BEAT_PHASE, CYCLE_EDGE and BEAT_EDGE, and the MIDI functions cc, pitchbend and
aftertouch, follow the session only in a dsp signal — and in the dsp fns and object methods it
calls. In an effect or an instrument, TIME, CYCLES, POSITION and the MIDI functions are
unknown names, CPS, BPC and CYCLE
are the fixed values 1, 4 and 0, and the phase and edge constants are 0. SR, INV_SR,
PI and TWOPI work everywhere.
TIME and CYCLES are how far the signal has run since it started, in seconds and in cycles.
A tempo change bends CYCLES and never jumps it, and the phase and edge constants are built on it
(CYCLE_PHASE is fract(CYCLES)). Use CYCLES for anything that should stay on the beat, and
TIME for anything that should keep its speed whatever the tempo.
POSITION is the same distance counted in the signal’s timebase: cycles unless .set_timebase()
sets another unit. Use it for any length a user should be able to give in their
own unit — the stdlib Ramp measures its duration with it, so
signal_ramp(0, 1, 4).set_timebase(seconds(1)) is a four-second ramp.
dsp effect
Section titled “dsp effect”Without input and output declarations, an effect is stereo in, stereo out:
fn process(left, right) -> (out_l, out_r)With declarations, process takes one argument per input channel, in declaration order — two for a
stereo input, one for a mono one — and returns one value per output channel:
| Declarations | Signature |
|---|---|
input main: stereo; input sidechain: mono; output: stereo; | fn process(main_l, main_r, sc) -> (out_l, out_r) |
input main: mono; output: mono; | fn process(input) -> output |
Every input after the first is fed with effect.connect_input(name, track).
dsp instrument
Section titled “dsp instrument”fn render(note, velocity, gate) -> (out_l, out_r)| Argument | Value |
|---|---|
note | MIDI note number; fractional for pitches between semitones |
velocity | 0.0–1.0 |
gate | 1.0 while the note is held, 0.0 after its note-off |
render runs once per sample for every sounding voice; the voices are summed. An instrument has
16 voices. A note takes the first free voice; when none is free, the quietest voice is taken. After
note-off a voice keeps running until its output stays below −120 dBFS (1e-6) for 64 samples, then
it is free.
dsp signal
Section titled “dsp signal”fn process(input_1, input_2, …) -> outprocess returns one value per sample. Its arguments, if any, are inputs fed by other signals.
The constructor takes the inputs first, then the params in declaration order. Any argument can be given by name instead. A number where a signal is expected is a constant signal; a signal given for a param modulates it per sample.
Remap(Wobble()) // input `source` = Wobble()Remap(source: Wobble(), lo: 0.2) // by nameWobble(8.0) // no inputs: first param, speed = 8dsp fn
Section titled “dsp fn”dsp fn name(a, b) -> out { … }A pure function: no param, state or buffer, and one return value. Every dsp block of the
file can call it, wherever the dsp fn is written.
dsp object
Section titled “dsp object”dsp object Name { state …; buffer …; fn method(…) -> out { … }}Methods may have any name; there is no entry point and no param. Each let x = Name(); inside a
block is a separate instance with its own state.
Helper functions
Section titled “Helper functions”Any fn in a block other than its entry point is a helper:
- It is visible only in its block, and shadows a
dsp fnof the same name. - It can read and write the block’s
param,state,voice stateandbuffernames, but sees only its own arguments — not the entry point’s arguments or locals. - A block declares each helper once, and has one entry point; a second
fn processorfn renderis an error.
Every helper, dsp fn and dsp object method is checked when it is compiled, called or not.
Imports
Section titled “Imports”dsp fn and dsp object are exported from a module like any other definition, unless marked
private, and imported with a selective use. Only a module’s dsp blocks can call imported
DSP code; the blocks of the file being run, or of an executed selection, can call only what that
file defines itself.
Doc comments
Section titled “Doc comments”/// above a dsp declaration, a param or a helper documents it for the editor: hovering an
effect lists its documented params, and hovering a param or helper shows its own comment. A
signal’s params are its constructor’s arguments, and are listed as such.
/// A gain stage with a soft ceiling.dsp effect SoftGain { /// Linear gain before the ceiling. param level: 1.0 range(0, 4);
/// Bends `x` smoothly towards ±1. fn soften(x) -> y { return __native("tanh", x); }
fn process(left, right) -> (out_l, out_r) { return (soften(left * level), soften(right * level)); }}Related
Section titled “Related”- DSP Builtins — every
__nativefunction and constant - Effect — the methods of a placed effect
- The Audio-Thread Contract — why a block is shaped like this