DSL overview
The sndlab DSL is a small set of Rhai functions for describing audio
signals. Every primitive — source, transform, or combinator — builds
a node in a single Signal graph. The graph is lazy: nothing is
computed until the engine decides what to do with it.
What the engine does depends on the patch’s role:
- One-shot patches render the graph into a finite buffer at
patch-registration time, driven by whatever bounded duration the
graph supplies (a
take(...), achirp(...), or a sound primitive called with a duration argument). The buffer plays through Kira’s low-latencyStaticSoundDatapath. - Ambient patches keep the graph as a lazy description. At play time a fresh runner is spawned and ticks the graph at audio rate for as long as the ambient stays enabled. There is no looping — ambients are generated, not played back.
The single-graph design means there’s no distinction between
“buffer DSL” and “stream DSL.” sine(440) is the same primitive
whether it ends up in a one-shot or an ambient — only the duration
context differs.
Status
| Primitive | Status | Purpose |
|---|---|---|
patch | shipped | Register a named patch. |
sine | shipped | A sine oscillator. sine(freq) is unbounded; sine(freq, dur) wraps in take. |
chirp | shipped | Linear-FM sweep, bounded by its duration argument. |
noise | shipped | noise(kind) is unbounded; noise(kind, dur) wraps in take. |
env | shipped | Attack + exponential decay applied to a signal. |
take | shipped | Truncate a signal to duration_s. Sources support this implicitly via their two-arg form. |
fade_out | shipped | Cosine-squared fade over the buffer’s last duration_s. Requires a bounded source. |
fade_in | shipped | sin² fade-up at the start. Complementary to fade_out — together they sum to constant power. |
delay | shipped | Prepend silence before the source. Stagger entries in a mix(…). |
tremolo | shipped | Sine LFO amplitude modulation. |
gain | shipped | Linear amplitude scaling. |
bandpass | shipped | Biquad bandpass. |
lowpass | shipped | Biquad lowpass. |
highpass | shipped | Biquad highpass. |
mix | shipped | Sum multiple signals. |
tap | shipped | A delay tap, used by with_taps. (Per-tap exponential decay is honoured in one-shots only; ambient streams use fixed-gain delay copies.) |
grains | shipped | Stochastic damped-sine grain generator — bubbles, drips, rain. |
sample | shipped | Load an audio file (MP3/WAV/Ogg/FLAC) as a Signal. sample(path) plays once; sample_loop(path) wraps. |
Conventions
- Frequencies in Hz. Integers and floats both accepted.
- Durations in seconds.
- Amplitudes linear, 0..1.
Fluent style
sine(330.0).env(0.008, 1.4).gain(0.32).take(3.5)
Equivalent to nesting calls — the engine’s Rhai layer just registers
each function as both a free fn and a method on Signal.
Bounding rules
One-shot patches need a finite duration somewhere in the graph. The
engine walks the tree and uses the longest take / chirp /
bounded fade_out it finds; if nothing’s bounded it caps at a 10 s
safety default and logs a warning. Ambient patches ignore bounded
sub-trees and simply run forever.