Skip to content

Signal Methods

FunctionOutput RangeDescription
Sine(n) / Sine2(n)0-1 / -1 to 1Sine wave (starts at midpoint)
Saw(n) / Saw2(n)0-1 / -1 to 1Sawtooth (ramp up, resets at cycle end)
Tri(n) / Tri2(n)0-1 / -1 to 1Triangle (peaks at mid-cycle)
Square(n) / Square2(n)0-1 / -1 to 1Square (50% duty cycle)
Rand(n)0-1Sample-and-hold (deterministic)
Perlin(n)0-1Smooth 1D gradient noise

All accept: no arg (1 cycle/cycle), number (N cycles/cycle), or hz(n) (absolute frequency).

Sine(); // 1 cycle per cycle
Saw(4); // 4 cycles per cycle
Tri(hz(2)); // 2 Hz absolute frequency
Square2(); // Bipolar square wave
Rand(); // Random noise
Perlin(8); // 8 cycles of smooth noise

Define compiled signals using the DSP engine. See Signals & Automation: DSP Signals for full syntax.

dsp signal Name {
param speed: 4.0 range(0.1, 40);
state phase: 0.0;
fn process() -> out {
phase = fract(phase + speed * CPS * INV_SR);
return sin(phase * TWOPI);
}
}
filter.Cutoff << Name().range_exp(200, 4000);

Builtins: TIME, CPS, CYCLE, BPC, SR, INV_SR, CYCLE_PHASE, BEAT_PHASE, CYCLE_EDGE, BEAT_EDGE, plus all DSP builtins. Supports param, state, buffer, local fn helpers, dsp fn, and dsp object.

fn process(...) parameters accept other signals as per-sample inputs:

dsp signal MyRange {
param lo: 0;
param hi: 1;
fn process(source) -> out {
return lo + source * (hi - lo);
}
}
MyRange(Sine(2)); // positional
MyRange(source: Sine(2)); // named
MyRange(0.5); // number auto-wraps as constant signal

Parameters can also be driven by signals at instantiation. Positional args fill upstream inputs first, then params:

MyRange(Sine(2), lo: Sine(0.5)); // named param as signal
MyRange(Sine(2), Sine(0.5), 0.9); // positional: source, lo, hi

Signals support arithmetic operators for combining and scaling:

OperatorExampleDescription
+Sine(1) + Saw(3)Sample-wise addition
-Sine(1) - Tri(2)Sample-wise subtraction
*Sine(1) * Sine(7)Sample-wise multiplication (ring mod)
/Sine(1) / Saw(2)Sample-wise division
- (unary)-Sine(1)Negation

Signals can also combine with numbers:

Sine(4) * 0.5 // Scale amplitude
Sine(2) + 0.3 // DC offset
0.5 - Sine(1) // Inverted offset

Signal algebra composes with all signal methods:

(Sine(1) + Saw(3) * 0.5).range_exp(200, 8000).smooth(5)
MethodDescription
.range(min, max)Linear mapping to [min, max]
.range_exp(min, max)Exponential mapping (for frequencies)
.retrigger(mode)Phase reset: “cycle”, “beat”, “free”
.in_seconds()Convert automation timebase to seconds
.at(time, value)Add breakpoint to automation
.at(time, value, curve)Add breakpoint with curve type
.smooth(time_ms)One-pole lowpass smoothing
let lfo = Sine(4).range(0.2, 0.8);
filter.Cutoff << Sine(1).range_exp(20, 20000);
Sine(4).retrigger("beat");
Cc(74).smooth(50);

Create automation curves with breakpoints using the automation function. Each breakpoint is an array of [time, value] or [time, value, curve]:

let env = automation(#[0, 0], #[2, 1.0, "exp"], #[4, 0]);
CurveDescription
"linear"Straight line between points (default)
"step"Instant jump at breakpoint
"exp"Exponential curve
"smooth"Smooth interpolation
"ease-in"Slow start, fast end
"ease-out"Fast start, slow end
"ease-in-out"Slow start and end
"ease"CSS-style ease curve
"bezier(x1,y1,x2,y2)"Custom cubic bezier

Effect parameters support the << operator for both static values and signal modulation:

let d = Delay(0.25, 0.5);
// Static values
d.Time << 0.1;
d.Feedback << 0.8;
// Signal modulation
d.Time << Sine(2).range(0.1, 0.4);
filter.Cutoff << Sine(1).range_exp(200, 4000);

For .modulate() (breakpoint-based modulation), see the Effects Reference.modulate() is a method on effect parameters, not on signals.

// LFO with range
let lfo = Sine(4).range(0.2, 0.8);
// Exponential mapping for frequency parameters
filter.Cutoff << Sine(1).range_exp(20, 20000);
// Phase reset every beat
Sine(4).retrigger("beat");
// Smooth MIDI CC input
Cc(74).smooth(50);
// Automation envelope
let env = automation(#[0, 0], #[2, 1.0, "exp"], #[4, 0]);