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.

The one exception to audio rate Everything in Phausto runs at audio rate except UI elements, which update at the slower rate a human or a host moves them. This is why stepped controller movement is audible and why 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:

method label: aString init: init min: min max: max step: step
index := PhNumEntry new
  label: 'Wave' init: 0 min: 0 max: 3 step: 1.
method label: aString values: anArray
freq := PhHSlider new
  label: 'Freq' values: #(100 20 4000 0.1).
Array positionMeaning
1stInitial value
2ndMinimum
3rdMaximum
4thStep size
Init comes first, not the minimum #(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

ClassFAUST primitiveUse
PhHSliderhsliderHorizontal slider — the default choice for a continuous value
PhVSlidervsliderVertical slider; identical behaviour, different orientation hint
PhNumEntrynentryNumeric entry — best for discrete choices such as a selector index
PhSliderAbstract superclass of the three
Entry for integers, slider for continuous values A 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

ClassFAUST primitiveSignal
PhButtonbutton1 while held, 0 otherwise — momentary
PhCheckboxcheckbox1 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.

An implementation detail you may notice FAUST buttons and checkboxes share the same underlying box constructor, so Phausto encodes the widget type in the label, separated by a tilde. If a label appears in 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.

ClassUse
PhHBarGraphHorizontal meter
PhVBarGraphVertical 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:

ExpressionProduces
#gate asPhButtonA button named gate
#cutoff asPhHSliderA horizontal slider named cutoff
'Level' asPhFaderA fader from a string label
'Cutoff' asDSPParameterA DSPParameter from a label
#freq <- 440Assign 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:

MessageBinds to
midiCtrl: aNumberA MIDI continuous controller, any channel
midiCtrl: aNumber channel: aChannelA controller on a specific channel
midiKeyon: aPitchNote-on for a given pitch
midiPitchwheelThe pitch bend wheel
belaPin: aBelaPinAn analogue pin on a Bela board
declare: aKey value: aValueAny other FAUST metadata declaration
metadataRead back what has been declared
cutoff := PhHSlider new
  label: 'Cutoff' values: #(800 40 12000 1);
  midiCtrl: 1.        "the modulation wheel"
Declare once, works everywhere The same declaration is honoured by the FAUST runtime in Pharo, by an exported JUCE plugin, and by a Bela binary. Declaring control bindings on the widget rather than in your own code is what makes a patch portable. See Exporting.

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.

AccessorMeaning
name / name:Parameter name
label / label:Display label
description / description:Human-readable description
initialValue / initialValue:Default value
min: / max:Bounds
rangeThe 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.

9. Where to go next

DocumentWhat it covers
Parameters & ControlDriving these widgets from code.
MIDI & Playing NotesMapping hardware controllers to them.
DSP & Parameter APIOpening individual widgets and reading the UI description.
ExportingWhat these declarations become in a plugin.

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.