Envelopes, LFOs, and modulation routing
Learning objectives
- learner can shape a parameter over time with ADSR/AR envelopes and choose curve, trigger modes, and time scaling for the musical goal
- learner can add movement and dynamics to a voice by routing an LFO to a synthesis parameter and mapping note velocity to amplitude
- learner can articulate a subtractive voice by routing an envelope to filter cutoff and amplitude (VCA)
Capstone — one whole task that evidences the objectives
Build a single synth voice whose brightness and loudness evolve expressively: route one envelope to filter cutoff, another to a VCA, add an LFO for movement and a velocity-to-amp mapping — then play a phrase that demonstrates all four modulations.
Prerequisite modules
A static patch is a demo; a patch that moves is an instrument. In a live-coded or synth-driven set — a techno bassline that bites harder on downbeats, a pad that breathes under a trance kick — everything the audience hears as “expression” is modulation: control signals reshaping pitch, amplitude, and brightness note by note. This module builds toward one whole task: a single subtractive voice (in Surge XT or any softsynth/modular rig) where a filter envelope, an amp envelope, an LFO, and velocity all audibly do their jobs in a played phrase.
The arc starts fully supported. First, hear what an envelope even is — a control curve, not audio — and drill the four ADSR stages by ear on amplitude alone. “A voltage-controlled amplifier driven by an envelope generator shapes a sound’s loudness over time” is your first JIT pointer; “Routing an envelope to filter cutoff is the core articulation move of subtractive synthesis” is the second, turning the same gesture toward timbre. From there, scaffolding is progressively removed: you choose segment curves yourself (guided by why exponential segments sound perceptually linear), pick trigger modes for drum-style one-shots, add cyclical motion with an LFO and decide sync-per-note versus free-running, map keystroke velocity to amplitude so the phrase responds to touch, and finally patch the capstone voice with no recipe — just the phrase that proves all four routings.
The required atoms gate the capstone: without envelope stages, VCA and cutoff routing, trigger behavior, LFO placement, and the velocity-to-amplitude mapping, the voice cannot be built or debugged. Supporting atoms widen the craft — ADBDR piano shapes, envelope followers as audio-derived modulation sources, sidechain ducking as trance’s signature pump, humanisation, and Surge XT’s DAHDSR-per-LFO, MSEG, and modulator-of-modulators — showing where the same routing logic goes next.
Walkthrough
An envelope is a control curve, not a sound — it shapes how a parameter moves over each note. You’ll route envelopes and an LFO into one sawtooth voice until it plays expressively. At strudel.cc, Ctrl-Enter plays, Ctrl-. stops. Each step is a complete program. The same note, radically different, depending on how it’s shaped.
1 — the amplitude envelope (attack + release). attack is how fast a note fades in; release how it fades out. A tiny attack and short release give a percussive pluck; long ones give a swell. Two knobs already change the whole character ([[envelope-synthesis-definition]], [[envelope-generator]]).
setcpm(120/4)
note("c3 e3 g3 c4").sound("sawtooth").attack(0.005).release(0.15)
2 — the full ADSR. Four stages: Attack (in), Decay (to a level), Sustain (held level), Release (out). A slow attack with a high sustain is a pad that blooms and holds; this is the vocabulary every synth shares ([[adsr-envelope]], [[adsr-vs-ar-envelope]], [[vca-envelope-shaping]]).
setcpm(120/4)
note("c3 ~ e3 ~").sound("sawtooth").attack(0.4).decay(0.2).sustain(0.6).release(0.5)
3 — an envelope on the filter. Route a second envelope to the cutoff (lpenv = amount, lpattack/lpdecay/lpsustain = its shape). Now each note starts bright and darkens as it decays — the “wow” of a plucked synth, and the core articulation move of subtractive synthesis ([[cutoff-envelope]], [[filter-envelope-modulation]], [[exponential-envelope-segments]]).
setcpm(120/4)
note("c2 c2 c2 c2").sound("sawtooth").lpf(400).lpenv(4).lpattack(0.01).lpdecay(0.2).lpsustain(0.2)
4 — an LFO for continuous movement. An envelope fires once per note; an LFO cycles continuously. sine.range(0.3, 0.9).fast(2) on gain gives a tremolo that keeps pulsing regardless of note events — motion the envelopes can’t provide ([[lfo-modulation]]).
setcpm(120/4)
note("c3 e3 g3 e3").sound("sawtooth").lpf(1200).gain(sine.range(0.3, 0.9).fast(2))
5 — velocity maps touch to loudness. velocity scales each note’s amplitude, so a pattern of velocities gives accents — the phrase responds to “how hard” each note is struck, the difference between a machine and a performance ([[synth-control-note-velocity-to-freq-amp]]).
setcpm(120/4)
note("c3 e3 g3 e3").sound("sawtooth").velocity("1 0.5 0.8 0.4").lpf(1000)
6 — one expressive voice (the capstone). All four modulations on one sawtooth: an amp ADSR shapes each note, a filter envelope adds the pluck, a slow gain LFO breathes underneath, and velocity accents the phrase. Every parameter is moving with intent ([[envelope-trigger-mode]]):
setcpm(120/4)
note("<c3 e3 g3 b3> ~ e3 g3")
.sound("sawtooth")
.attack(0.02).decay(0.15).sustain(0.5).release(0.2)
.lpf(500).lpenv(3).lpattack(0.01).lpdecay(0.25)
.gain(sine.range(0.5, 0.85).slow(2))
.velocity("1 0.6 0.8 0.5")
What good sounds like. An expressive voice evolves within each note and across the phrase: you hear the attack shape (pluck vs swell), the filter opening and closing, and dynamics from the velocities — not a flat, identical blip repeated. The beginner failure is stacking modulations that fight (a slow amp attack under a fast filter pluck reads as mushy); pick a character — percussive or sustained — and make all four serve it. A tiny bit of LFO goes a long way. (Skill map: live-coder Domain B5 — sound design: shape a synth so it evolves.)
Now make it yours. Make it a pad: long attack, long release, low lpenv. Make it a stab: near-zero attack, short decay, high lpenv. Pattern the attack: .attack("0.01 0.3"). Move the LFO to the cutoff (.lpf(sine.range(400,2000).slow(4))) for a wah. Add .room(0.3) and let the release tails wash.
Runnable examples
Generated from the context/ instrument corpus by concept (redistributable idioms only). Do not edit — regenerate with gen-module-examples.mjs.
amplitude-lfo
osc 440 * lftri 1 >> audio
punctual-0003 · CC0-1.0
s("bd*4").gain(sine.range(0.5,1).fast(4))
strudel-0040 · CC0
adsr-envelope
note("c3").s("sawtooth").attack(0.01).decay(0.1).sustain(0.6).release(0.3)
strudel-0205 · CC0
{ Saw.ar(220) * EnvGen.kr(Env.perc(0.001, 0.2), Impulse.kr(2)) * 0.3 }.play
supercollider-0013 · CC0
vibrato
saw (midicps $ 24 +- 0.03 $ osc 6) >> audio
punctual-0005 · CC0-1.0
{ SinOsc.ar(SinOsc.kr(6).range(430, 450), 0, 0.2) }.play
supercollider-0006 · CC0
sidechain-pump
note("c2").s("sawtooth").duckorbit(1).duck("bd*4")
strudel-0017 · CC0
~duck: imp 4 >> envperc 0.001 0.15 >> mul -1.0 >> add 1.0
out: saw 110 >> lpf 600 1.0 >> mul ~duck >> mul 0.3
glicol-0029 · MIT
Atoms in this module
Required — these gate the capstone
Supporting — enrichment, not gating
Part of curricula
- Dawless Performer — hardware jam to recorded live take — Signals, voices, and the DAWless mindset required
- Electronic Music Producer — from raw sound to a released track — Design your palette — synthesis and groove required
- Live Coder — zero to performing live-coded music — Patterns, Grooves & Voices recommended
- Synthesist / Sound Designer — deep DSP to a performed live synth rig — Hearing sound as spectrum, shaping a first voice required
Unlocks — modules that require this one
- Additive synthesis and resynthesis: building timbre from partials
- Drum synthesis: kicks, snares, hats, claps, and toms from scratch
- FM synthesis: carriers, modulators, ratios, and index
- Granular synthesis: grains, clouds, and time-frequency textures
- Leads, pads, and performance voices: arps, gates, and modulation motion
- Subtractive synthesis: from raw wave to shaped voice