The widgets that make a value controllable. They describe an interface abstractly — no toolkit, no layout — and Phausto, a plugin host or a Bela board each render them their own way.
1. Widgets are signal generators
A FAUST widget is not a control that sends events. It is a signal: a button outputs 1 while pressed and 0 otherwise; a slider outputs its current position, continuously. That is why a widget can be used anywhere a UGen can, and why arithmetic on widgets works.
The description is also abstract. Nothing in a PhHSlider says how wide it is or
where it sits — it declares a name, a range and a default, and the host decides the rest.
The same declaration becomes a Pharo window under displayUI, a plugin parameter
when exported to JUCE, and an analogue input on a Bela board.
smoo exists — see Envelopes §5.
UIPrimitive is the abstract superclass. Do not instantiate it directly; it
exists to group the real widgets and give them a common protocol.
2. Sliders and numeric entries
2.1 The two constructors
PhSlider supplies both constructors to all its subclasses. They express the
same thing; pick whichever reads better:
index := PhNumEntry new
label: 'Wave' init: 0 min: 0 max: 3 step: 1.
freq := PhHSlider new
label: 'Freq' values: #(100 20 4000 0.1).
| Array position | Meaning |
|---|---|
| 1st | Initial value |
| 2nd | Minimum |
| 3rd | Maximum |
| 4th | Step size |
#(100 20 4000 0.1) means "start at 100, range 20–4000". Reading it as
min-max-init-step is the commonest cause of a slider that will not move.
Individual setters exist too: label:, init:, min:, max:, step:.
2.2 PhHSlider, PhVSlider, PhNumEntry
| Class | FAUST primitive | Use |
|---|---|---|
| PhHSlider | hslider | Horizontal slider — the default choice for a continuous value |
| PhVSlider | vslider | Vertical slider; identical behaviour, different orientation hint |
| PhNumEntry | nentry | Numeric entry — best for discrete choices such as a selector index |
| PhSlider | — | Abstract superclass of the three |
PhNumEntry with step: 1 is the natural control for something
like a waveform index, where intermediate values are meaningless. See
Synthesis §1.
3. Buttons and checkboxes
| Class | FAUST primitive | Signal |
|---|---|---|
| PhButton | button | 1 while held, 0 otherwise — momentary |
| PhCheckbox | checkbox | 1 or 0 — latching |
The difference matters for envelopes: a button is a gate you hold, a checkbox is a switch you leave. Triggering percussion wants the former; enabling an effect wants the latter.
traceAllParams with a ~ in it, that is why — use the name exactly
as printed.
Trigger a button from code with dsp trig:; see Parameters §5.
4. Bar graphs
Bar graphs run the other way: instead of producing a signal, they display one. They are meters.
| Class | Use |
|---|---|
| PhHBarGraph | Horizontal meter |
| PhVBarGraph | Vertical meter |
Both take label:, min:, max: and, crucially,
input: — the signal to display. They pass that signal through unchanged, so a
meter can be inserted mid-chain without altering the sound.
"Watch the level going into the reverb"
meter := PhVBarGraph new
label: 'Level'; min: 0; max: 1; input: voice.
5. Shortcuts from symbols and strings
For the common case — a named control with default range — Phausto extends
Symbol and String:
| Expression | Produces |
|---|---|
| #gate asPhButton | A button named gate |
| #cutoff asPhHSlider | A horizontal slider named cutoff |
| 'Level' asPhFader | A fader from a string label |
| 'Cutoff' asDSPParameter | A DSPParameter from a label |
| #freq <- 440 | Assign a value to a symbol-named parameter |
Passing a bare symbol to any setter does the same job implicitly — see Setter Traits §1.1. Use the explicit forms when you need to control the widget type or range.
6. Metadata and external control
FAUST lets a widget carry metadata declarations, and those are what bind it to the outside world. Phausto exposes them as ordinary messages:
| Message | Binds to |
|---|---|
| midiCtrl: aNumber | A MIDI continuous controller, any channel |
| midiCtrl: aNumber channel: aChannel | A controller on a specific channel |
| midiKeyon: aPitch | Note-on for a given pitch |
| midiPitchwheel | The pitch bend wheel |
| belaPin: aBelaPin | An analogue pin on a Bela board |
| declare: aKey value: aValue | Any other FAUST metadata declaration |
| metadata | Read back what has been declared |
cutoff := PhHSlider new
label: 'Cutoff' values: #(800 40 12000 1);
midiCtrl: 1. "the modulation wheel"
7. PhControlParameter
A PhControlParameter describes a UGen parameter that can be made
controllable — the metadata layer between a UGen and the widget that might drive it. It is
what lets Phausto report a UGen's controllable parameters before any widget has been
attached.
| Accessor | Meaning |
|---|---|
| name / name: | Parameter name |
| label / label: | Display label |
| description / description: | Human-readable description |
| initialValue / initialValue: | Default value |
| min: / max: | Bounds |
| range | The span between them |
| step / step: | Increment |
| value / value: | Current value |
| widgetType / widgetType: | Which widget should represent it |
Reach it through aUGen controlParameters and aUGen uiParameters.
A widget can be converted into one with asControlParameter, or
asControlParameterOfWidgetType:description: when you want to specify both.
The related DSPParameter and DSPParameterStore describe parameters
of a running DSP rather than of a UGen — see
DSP & Parameter API §8.
8. Widgets in expressions
Because a widget is a signal, it takes part in arithmetic directly. This is how one control drives several destinations, or how two controls combine:
"One frequency control, one ratio control, two oscillators"
freqKnob := PhHSlider new label: 'Freq' values: #(100 20 4000 0.1).
ratioKnob := PhHSlider new label: 'Ratio' values: #(1 0.1 32 0.1).
modulator := SineOsc new freq: freqKnob * ratioKnob.
carrier := Dx7Op new phaseMod: modulator; freq: freqKnob.
Widgets understand +, *, ,, => and
smoo, and can be sent asDsp directly if you want to hear one on its
own. See Connecting Unit Generators.
10. Troubleshooting
My slider will not move, or does nothing
The values: array is in the wrong order, or the step is larger than the range.
Initial value comes first — §2.1.
The widget does not appear in the UI at all
It was never connected to anything. A widget only reaches the DSP if it is used as a setter argument or is part of the signal expression — §8.
A parameter name has a tilde in it
That is the button/checkbox type marker. Use the name exactly as printed — §3.
Two widgets end up with the same name
Labels must be unique within a DSP. Give them distinct label: values, or
relabel the owning UGen — see Unit Generators §2.2.
Moving a control produces zipper noise
Widgets update below audio rate. Append smoo — §1.
My bar graph changes the sound
It should not — bar graphs pass their input through unchanged. If something changed, the
signal is probably being routed into the meter instead of through it. Check
input: — §4.