What you can change while the sound is running, how it gets a name, and every way to change it — by hand, from code, or on a schedule.
1. Three kinds of argument
Almost every Phausto setter is declared as taking
aNumberOrABoxOrASymbol, and that signature is the single most important thing
on this page. The kind of argument you pass decides whether the value is frozen,
modulated, or exposed as a control.
1.1 A number is a constant
osc := SineOsc new freq: 440.
440 is compiled into the DSP as a literal. It is efficient and it is permanent: no
parameter appears in the UI, and setValue:parameter: has nothing to address.
Use numbers for values that genuinely never change.
1.2 A UGen is modulation
"Vibrato: ±20 Hz at 6 Hz around a 440 Hz centre"
osc := SineOsc new freq: (LFOTri new freq: 6) * 20 asBox + 440 asBox.
The value now comes from another part of the signal graph and changes every sample. This is how envelopes, LFOs and audio-rate modulation are wired — see Envelopes & Modulation.
1.3 A symbol is a control
osc := SineOsc new freq: #myFreq.
Passing a symbol creates a named, runtime-controllable parameter. It
appears in displayUI, it shows up in traceAllParams, and
setValue:parameter: can reach it. This is the mechanism you need for anything
you intend to perform with.
Symbols also convert directly into widgets when you want to specify a range:
| Expression | Result |
|---|---|
| #gate asPhButton | A momentary button named gate |
| #cutoff asPhHSlider | A horizontal slider named cutoff |
| 'Level' asPhFader | A fader from a string label |
| #freq <- 440 | Set a symbol-named parameter's value |
2. How parameters get their names
A parameter's name is its UGen's label followed by the parameter's own
label. A PulseOsc whose label is the default class name therefore contributes
PulseOscFreq and PulseOscDuty.
Relabel the UGen and every one of its parameters is renamed with it:
"Two oscillators that would otherwise share parameter names"
left := SineOsc new label: 'Left'.
right := SineOsc new label: 'Right'.
"now LeftFreq and RightFreq, individually addressable"
dsp setValue: 440 parameter: 'LeftFreq'.
dsp setValue: 443 parameter: 'RightFreq'.
The same technique makes an arbitrary instrument work with
playNote:prefix:dur:, which looks for a frequency and a gate under a prefix you
choose:
synth := ElecGuitar new
freq: #ElecGuitarFreq;
trigger: #ElecGuitarTrigger.
asDsp has no
effect on the running DSP — rebuild it.
3. Discovering what exists
You should almost never guess a parameter name. After init, the DSP can list
everything it exposes:
| Message | Returns |
|---|---|
| traceAllParams | Prints every parameter and its current value to the Transcript |
| allParameters | The parameters as objects |
| getParamCount | How many there are |
| getParamAddress: | The name at a given index |
| getParamIndex: | The index of a given name |
| getParamValue: | The current value of a named parameter |
| includesParameter: | Whether a name exists — useful before setting it |
| getUIButtons | Just the buttons |
| getUIKnobs | Just the continuous controls |
| getUIItems | Every UI item |
| getJSON | The full FAUST UI description as JSON |
dsp traceAllParams.
dsp getParamValue: 'PulseOscDuty'.
(dsp includesParameter: 'PulseOscFreq') ifTrue: [ "safe to set" ].
traceAllParams is the authoritative answer
and costs one line.
4. Setting values
dsp setValue: 0.2 parameter: 'PulseOscDuty'.
dsp setValue: 120 parameter: 'PulseOscFreq'.
Values are in the parameter's own units — hertz, seconds, decibels, or a normalised 0–1 range, depending on the control. Out-of-range values are clamped to the declared minimum and maximum rather than raising.
The index form, setValue:parameterIndex:, avoids the name lookup and is
marginally faster; it is worth using inside a tight control loop, but the name form is
clearer everywhere else.
traceAllParams before assuming the value is wrong.
5. Triggering
Envelopes, drums and plucked models do nothing until gated. A button parameter is a signal
that is 1 while pressed and 0 otherwise, and trig: presses it from code.
| Message | Effect |
|---|---|
| trig: aString | Fire the named trigger |
| trig: aString for: seconds | Hold the gate open for a duration, then release |
| playNote: n prefix: aString dur: seconds | Set the frequency from a MIDI note number and gate it for a duration |
| syncTrigReset | Reset synchronised triggers to a common origin |
"Strike a drum"
dsp trig: 'DjembeTrigger'.
"Hold a note for a quarter of a second"
dsp trig: 'ADSREnvGate' for: 0.25.
"Play middle C for a quarter of a second"
dsp playNote: 60 prefix: 'ElecGuitar' dur: 0.25.
The difference between trig: and trig:for: matters for sustaining
instruments. A percussion model only needs an instant; an ADSR held open by
trig: alone will sit in its sustain stage indefinitely.
6. Sweeps and ramps
A parameter can be moved gradually rather than jumped, which is the difference between a filter that clicks and one that sweeps:
"Open the filter over two seconds"
dsp sweepToValue: 8000 parameter: 'MoogVcfFreq' in: 2.
sweepToMfValue:parameter:in: is the variant for parameters expressed as
multiplication factors rather than absolute values.
smoo to the widget, or use one of the PhSmoo family. That way
every change is smoothed, including ones made by hand in the UI. See
Envelopes & Modulation.
7. Setting many at once
Phausto extends Array so a collection of values can be applied to a DSP in one
message — convenient when recalling a preset or stepping a sequence:
| Message | Effect |
|---|---|
| anArray setValue: aFloat parameter: aString forDsp: aDsp | Apply a value across a DSP from an array context |
| anArray trig: aString for: seconds forDsp: aDsp | Fire a trigger for a duration from an array context |
For structured state — saving, recalling and interpolating whole parameter sets — Phausto
has DSPParameter and DSPParameterStore, described in
DSP & Parameter API.
8. Individual widgets
displayUI opens everything at once. When you want one control on screen —
during a performance, or to keep a specific knob to hand — open it alone:
| Message | Effect |
|---|---|
| displayUI | The whole generated interface |
| sliderFor: | A slider presenter for one named parameter |
| buttonFor: | A button presenter for one named trigger |
| openSliderFor: | Build and open a slider in one step |
| openButtonFor: | Build and open a button in one step |
| keyBoardFor: | A piano keyboard bound to a named instrument |
s1 := dsp sliderFor: 'tempo'. s1 openInWindow.
s2 := dsp sliderFor: 'freq'. s2 openInWindow.
Nested FAUST groups produce path-like names, so a parameter inside a demo module may be
addressed as something like 'Freeverb/0x00/RoomSize'. Copy the exact string from
traceAllParams.
10. Troubleshooting
setValue:parameter: silently does nothing
Either the name is wrong, or the value was fixed as a number at construction time and is now
a compiled constant. Check with traceAllParams — §3 — and see §1.1.
The parameter I want is not in traceAllParams at all
It was never exposed. Rebuild the UGen passing a symbol or a UI primitive instead of a number — §1.3.
Two UGens respond to the same parameter name
They share a label. Give one its own label: — §2.
Changing a value produces an audible click or zipper noise
The jump is instantaneous. Sweep it, or smooth it inside the graph — §6.
My envelope triggers but never releases
trig: opens the gate and leaves it open. Use trig:for: with a
duration, or playNote:prefix:dur: — §5.
A parameter name has slashes and hex digits in it
That is a nested FAUST group path, normal for demo modules and complex instruments. Copy it verbatim — §8.