All books

The three writes, and what an amount means

~3 min read · updated 2026-08-29 · markdown

A parameter that is modulated has three values that look like one knob, and FaustWave gives each its own verb. Getting this wrong is the single most common way to "set a value that does not stick".

WriteActionWhat it changesSurvives
livedsp.param.set { instance_id, path, value }The number in the running worklet, right now — what dsp.param.get reads back, post-modulationuntil the next modulation tick overwrites it, or the next compile
basemodulation.base.set { sink_id, path, value }The centre the modulation swings around: clamp(base + sum amount x source)the project (paramBases for .dsp, the .builder file for Builder nodes, the mixer slice for slots)
slotmaster.fx.slot.param.set { slot_id, param_name, value } / mixer.tracks.fx.set { params }What an FX slot stores and re-applies when it next compilesthe project

The rule of thumb: a modulated parameter is set through its base. Writing it live is overwritten on the next tick; writing an unmodulated .dsp parameter live is fine and also lands in its base. For a slot, write the slot.

actions:
  - action_id: modulation.base.set
    input: { sink_id: "<module_id>", path: "/MyDsp/cutoff", value: 2400 }
    label: "▶ Set the base a modulator swings around (edit the ids first)"

Amount is a fraction of the range

An edge's amount is not in the parameter's units. It is a fraction of the sink parameter's declared range, multiplied by the source's output:

live = clamp( base + amount x source x (max - min), min, max )

So a macro at 0.6 on weight_dB (0..12) with amount 0.2 adds 0.6 x 0.2 x 12 = 1.4 dB; an LFO at -1..1 on a 400..8000 Hz cutoff with amount 0.12 breathes +/-912 Hz. Two helpers for thinking in min/max instead: set base = (min + max) / 2 and amount = (max - min) / 2 / range.

actions:
  - action_id: routing.connect
    input: { from_source: "<source_id>", from_port: "/LFO/out", to_sink: "<module_id>", to_port: "/MyDsp/cutoff", kind: modulation, amount: 0.12 }
    label: "▶ Wire an LFO into a cutoff at 12 % of its range (edit the ids first)"
  - action_id: routing.list
    input: {}
    label: "▶ See the edge (sinks appear only while the instrument runs)"

Source ports are the [modout] addresses from modulation.source.list (/LFO/out); sink ports are the parameter paths from dsp.params.list. Re-connecting the same pair replaces the amount; routing.disconnect removes the edge and the base is what remains — modulation is non-destructive by construction.

The demo's three edges

Around the World wires exactly three, and they show the three kinds of use:

  • Breath — Mod LFO Breath (0.135 Hz ~ four bars) → Hook Lead cutoff, amount 0.12. A slow drift nobody notices until it is gone.
  • Step — Mod SH Bell (sample-and-hold, sync 1/8) → Bell Hook width, amount 0.18. The bell is somewhere else on every eighth.
  • Macro — Mod Macro Erdbeben → 808 weight_dB 0.2, boom 0.3, dirt_level 0.25. One knob, three targets, no motion of its own — the next chapter puts a controller on it.
Try it yourself — the IDE runs in your browser. Open the IDE → Get the desktop app

Text licensed under CC BY 4.0 — Mani Weber / FaustWave. For language models: llms.txt · llms-full.txt

AUDIO · 48k · 48.0ms FAUST · 3 KB · 1171 docs CPU · 8.4% BPM · 120.0 UTF-8 BETA· v0.90.0