Be a modulation source
Turn your device into an LFO that wiggles other devices.A device can output movement: a signal that drives other devices' controls, like an LFO. Give it a modulation output and write a value each sample.
m.addPort(modulationOut("Mod"));A slow sine LFO. Keep a phase and a sample rate on the device, advance the phase each sample:
class Node extends Device {
private phase: f32 = 0;
private sr: f32 = 48000;
describe(): Manifest {
const m = new Manifest("LFO");
m.addParam(new ParamDef("rate", "Rate", "Rate", 0.1, 20.0, 2.0, false));
m.addPort(modulationOut("Mod"));
return m;
}
prepare(sampleRate: f64, maxBlock: i32): void {
this.sr = <f32>sampleRate;
}
process(ctx: Ctx): void {
const inc = ctx.param(0) / this.sr; // Rate, in Hz
const tau = <f32>(2.0 * Math.PI);
for (let i = 0; i < ctx.n; i++) {
ctx.modOut(i, Mathf.sin(this.phase * tau));
this.phase += inc;
if (this.phase >= <f32>1.0) this.phase -= <f32>1.0;
}
}
}How deep it goes and which controls it hits are set where the modulation output is
plugged in. Don't want to hand-roll the shape? The building
blocks include RandomLfo and friends.
Several outputs from one device
A device can declare up to 8 modulation outputs: call modulationOut(...) once per
output. The first port keeps the bare modulation-out handle and is written with
ctx.modOut(i, value); every further port gets an indexed handle
(modulation-out-1, modulation-out-2, ...) and is written with
ctx.modOutAt(out, i, value), where out is the port's declaration order (0 is
the first port). Each output shows as its own handle on the tile, labeled when
there is more than one, so a random sequencer can drive pitch, gate, and velocity
targets from independent streams:
describe(): Manifest {
const m = new Manifest("TripleMod");
m.addPort(modulationOut("Pitch"));
m.addPort(modulationOut("Gate"));
m.addPort(modulationOut("Velocity"));
return m;
}
process(ctx: Ctx): void {
for (let i = 0; i < ctx.n; i++) {
ctx.modOut(i, this.pitch); // output 0 (same as modOutAt(0, ...))
ctx.modOutAt(1, i, this.gate);
ctx.modOutAt(2, i, this.velocity);
}
}