Music is change over time. Envelopes and LFOs are the UGens that produce that change — and in Phausto they are ordinary signals, so they can be routed anywhere.
1. There is no control rate
Many audio environments separate audio-rate signals from slower control-rate ones, and will not let you connect the two without a conversion. Phausto, following FAUST, makes no such distinction: every Unit Generator produces a signal at audio rate. The only slower things in the system are UI primitives, which update when a human moves them.
The consequence is liberating. An LFO and an oscillator are the same kind of object, so anything that accepts one accepts the other. Raise an LFO's frequency into the audible range and it becomes an audio oscillator; lower an oscillator's frequency to 3 Hz and it becomes a modulator. There is no boundary to cross.
cutoff:, you can
drive it with an envelope. If it has a gain:, you can drive it with an LFO. No
special "modulation matrix" is needed, because the graph is the matrix.
2. Envelope generators
An envelope produces a non-periodic control signal: a shape, triggered by a gate. The envelope generator in this form was developed by Robert Moog in the 1960s with Herbert Deutsch, and its vocabulary — attack, decay, sustain, release — has been standard ever since.
An envelope is defined by times and levels: what value is reached, and how long it takes to get there. Each time/level pair is a stage, and the envelopes differ mainly in how many stages they have.
2.1 The thirteen envelopes
| Class | Stages | Character |
|---|---|---|
| AREnv | Attack, Release | The simplest shape — a swell and a fall |
| ARFExpEnv | Attack, Release | AR with exponential segments |
| ASREnv | Attack, Sustain, Release | Holds while gated; organ-like |
| ASRExpEnv | Attack, Sustain, Release | ASR with exponential segments |
| ADSREnv | A, D, S, R | The standard four-stage envelope, linear |
| ADSRExpEnv | A, D, S, R | Exponential — closer to how acoustic sounds decay |
| ADSREnvBias | A, D, S, R | ADSR with an adjustable curve bias per segment |
| ADSRFEnvBias | A, D, S, R | Biased ADSR with a fixed-duration variant |
| AHDSREnvBias | A, H, D, S, R | Adds a Hold stage between attack and decay |
| AHDSRExpEnv | A, H, D, S, R | Exponential five-stage envelope |
| AHDSRFEnvBias | A, H, D, S, R | Biased five-stage envelope |
| SmoothEnv | — | A smoothing envelope for taming stepped control values |
| PhEnvelope | — | The abstract superclass; do not instantiate directly |
ADSREnv. Move to the Exp variants when linear decays
sound artificial — which is most of the time for plucked and struck sounds. Reach for the
Bias variants when you need to shape the curvature of individual segments,
and the AHDSR family when a sound needs to sit at full level briefly before
decaying.
2.2 Stages and their setters
The stage setters come from the PhADSRSetter trait, so they are consistent
across the whole family:
| Setter | Meaning |
|---|---|
| attack: | Time to reach maximum level after the gate opens |
| decay: | Time to fall from the peak to the sustain level |
| sustain: | The level held while the gate stays open — not a time |
| release: | Time to fall to zero after the gate closes |
| ar: | Attack and release together, for the two-stage envelopes |
| level1: … level4: | Per-stage target levels on the multi-segment envelopes |
| release1: … release4: | Per-stage release times |
| biasAttack:, biasDecay:, biasRelease: | Curvature of each segment, on the Bias variants |
2.3 Gating an envelope
An envelope outputs zero until gated. The gate can come from the UI, from code, or from inside the graph:
"From the interface — press the button"
dsp displayUI.
"From code, held for a duration"
dsp trig: 'ADSREnvGate' for: 0.25.
"From the graph — a pulse every 300 ms, no scheduling code at all"
env := ADSREnv new gate: (Pulse new period: 0.3).
The third form is worth dwelling on: because the gate is just another signal, a rhythm generator wired to it turns the envelope into a self-playing part. See Sequencing & Sampling.
3. Low-frequency oscillators
An LFO produces a periodic control signal, normally below 20 Hz — under the threshold of hearing, so it is felt as movement rather than heard as pitch.
3.1 The LFO family
| Class | Shape | Range |
|---|---|---|
| LFO | Base class | Bipolar |
| LFOTri | Triangle | Bipolar, −1 to 1 |
| LFOTriPos | Triangle | Unipolar, 0 to 1 |
| LFOSaw | Sawtooth | Bipolar |
| LFOSawPos | Sawtooth | Unipolar |
| LFOSquare | Square | Bipolar |
| LFOSquarePos | Square | Unipolar |
| LFORandomPos | Random steps | Unipolar — a new value each cycle |
| LFOForModulation | Configurable | Adds offset and unit clamping |
Pos suffix marks the unipolar variants, which stay between 0 and 1.
Choose bipolar when modulating around a centre value, unipolar when modulating a quantity
that must never go negative — an amplitude, a delay time, a filter frequency.
3.2 Offset, amount and polarity
The two setters you will use constantly are amount:, which scales the LFO's
excursion, and offset:, which shifts its centre:
"A random pitch between 20 and 620 Hz, new value roughly three times a second"
pitch := LFORandomPos new offset: 20; amount: 600; freq: 3.
Read that as: start at offset, and add up to amount. The same
shaping can of course be written as arithmetic — lfo * 600 asBox + 20 asBox —
and the two are equivalent; the setters simply read better.
4. Routing a modulator
Envelopes are not only for amplitude, and LFOs are not only for vibrato. The three classical destinations, with the terms for each:
4.1 To amplitude
Periodic modulation of amplitude is tremolo; a one-shot shape is an envelope.
"Tremolo — 5 Hz amplitude wobble"
trem := SineOsc new uLevel: (LFOTriPos new freq: 5).
"Envelope shaping — the chuck operator multiplies the two"
plucked := SawOsc new => ADSREnv new.
4.2 To pitch
Periodic modulation of pitch is vibrato; a one-shot pitch shape is a pitch envelope.
"Vibrato — ±10 Hz at 6 Hz"
vib := SineOsc new freq: ((LFOTri new freq: 6) * 10 asBox + 440 asBox).
"Pitch envelope — the drop that makes a kick drum a kick drum"
pitchEnv := 200 asBox * ADSREnv new.
kick := TriOsc new freq: (50 asBox + pitchEnv).
4.3 To timbre
Modulating a filter's cutoff is the single most characteristic gesture in subtractive synthesis — the "wah" and the classic filter sweep are both this:
"Filter envelope — brightness follows the same shape as the note"
cutoff := 200 asBox + (4000 asBox * ADSREnv new).
voice := SawOsc new => (MoogVcf new cutoff: cutoff).
Note that this envelope is a second, independent one — a filter envelope is usually shorter than the amplitude envelope, which is what gives a sound its initial brightness and subsequent mellowing. See Filters.
5. Smoothing
A control value that jumps produces a click. The PhSmoo family interpolates
between values so changes are heard as movement rather than as steps:
| Class | Use |
|---|---|
| PhSmooth | General-purpose one-pole smoothing |
| PhSmoothAndH | Smoothing with a hold stage |
| PhSmoothQ | Smoothing with an adjustable time constant |
| PhBSmooth | Block-rate smoothing |
| PhOnePoleSwitching | Different rise and fall times — fast attack, slow release |
| SmoothEnv | Envelope-shaped smoothing |
The shorthand smoo applies the standard smoother to any signal, and is the
usual way to tame a slider:
cutoff := (PhHSlider new label: 'Cutoff' values: #(800 40 12000 1)) smoo.
sweepToValue:parameter:in: only covers changes you make yourself.
7. Troubleshooting
My envelope produces no sound
It has not been gated. See §2.3.
The envelope triggers but the sound never stops
The gate is still open — trig: holds it. Use trig:for:, or check
that sustain: is not doing what you think release: should. §2.2.
My vibrato makes the pitch drop to zero and buzz
A bipolar LFO went below the base frequency. Either raise the offset, or use the unipolar
Pos variant — §3.1.
The filter sweep sounds stepped rather than smooth
The control is jumping between discrete values. Add smoo, or increase the
slider's resolution by lowering its step — §5.
Everything clicks at the start of each note
The attack is at or near zero, so amplitude jumps from silence instantly. A few milliseconds of attack removes the click without softening the transient audibly.
An LFO in a patch sounds like a buzz, not a wobble
Its frequency is above about 20 Hz and it has entered the audible range. That is legitimate — it is now doing amplitude or frequency modulation — but if you wanted movement, lower it. §1.