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.

Which means Every setter in Phausto is a modulation input. If a UGen has a 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

ClassStagesCharacter
AREnvAttack, ReleaseThe simplest shape — a swell and a fall
ARFExpEnvAttack, ReleaseAR with exponential segments
ASREnvAttack, Sustain, ReleaseHolds while gated; organ-like
ASRExpEnvAttack, Sustain, ReleaseASR with exponential segments
ADSREnvA, D, S, RThe standard four-stage envelope, linear
ADSRExpEnvA, D, S, RExponential — closer to how acoustic sounds decay
ADSREnvBiasA, D, S, RADSR with an adjustable curve bias per segment
ADSRFEnvBiasA, D, S, RBiased ADSR with a fixed-duration variant
AHDSREnvBiasA, H, D, S, RAdds a Hold stage between attack and decay
AHDSRExpEnvA, H, D, S, RExponential five-stage envelope
AHDSRFEnvBiasA, H, D, S, RBiased five-stage envelope
SmoothEnvA smoothing envelope for taming stepped control values
PhEnvelopeThe abstract superclass; do not instantiate directly
Choosing one Start with 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:

SetterMeaning
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
Sustain is a level Three of the four ADSR controls are durations in seconds; sustain is an amplitude. A sustain of 0 makes the envelope behave as an AD envelope regardless of how long the gate is held.

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

ClassShapeRange
LFOBase classBipolar
LFOTriTriangleBipolar, −1 to 1
LFOTriPosTriangleUnipolar, 0 to 1
LFOSawSawtoothBipolar
LFOSawPosSawtoothUnipolar
LFOSquareSquareBipolar
LFOSquarePosSquareUnipolar
LFORandomPosRandom stepsUnipolar — a new value each cycle
LFOForModulationConfigurableAdds offset and unit clamping
Pos means positive The 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:

ClassUse
PhSmoothGeneral-purpose one-pole smoothing
PhSmoothAndHSmoothing with a hold stage
PhSmoothQSmoothing with an adjustable time constant
PhBSmoothBlock-rate smoothing
PhOnePoleSwitchingDifferent rise and fall times — fast attack, slow release
SmoothEnvEnvelope-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.
Smooth in the graph, not in the loop Smoothing inside the DSP covers every source of change — the UI, your code, an external controller. Sweeping from Pharo with sweepToValue:parameter:in: only covers changes you make yourself.

6. Where to go next

DocumentWhat it covers
FiltersThe obvious destination for an envelope.
Synthesis TechniquesEnvelopes at work in complete patches.
Sequencing & SamplingGenerating the gates that trigger envelopes.
Parameters & ControlTriggering and sweeping from code.

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.