Two ways out of the UGen layer when it does not reach far enough: write FAUST source directly, or build FAUST boxes yourself through the API the UGens are themselves built on.

1. Three layers

Everything in Phausto compiles down to the same thing. Knowing which layer you are on tells you what is available and what it costs:

Unit Generators — objects with fluid setters. Readable, safe, and what the rest of this manual documents.
Boxes — the FAUST box representation. Every UGen answers asBox; operators like => and , are box operations underneath.
FAUST source — text compiled by the embedded FAUST compiler. The whole language and the whole standard library, with none of the Pharo conveniences.
You can mix them A UGen chain and a raw FAUST string both become a DSP, and both are driven by the same DSP API. Dropping to a lower layer for one part of a patch does not commit you to it everywhere.

2. Writing FAUST source

2.1 Creating a DSP from a string

class method DSP create: aStringWithFaustCode
content := 'import("stdfaust.lib");
tempo = hslider("tempo", 10000, 300, 20000, 100);
freq  = hslider("freq",  300,   200, 900,   100);
process = ba.pulsen(1, tempo) : pm.djembe(freq, 0.3, 0.4, 1) <: dm.freeverb_demo;'.

x1 := DSP create: content.
x1 init.
x1 start.
x1 stop.

The resulting object is an ordinary DSP: displayUI, setValue:parameter:, traceAllParams and the exporters all work exactly as they do for a UGen-built patch. DSP create:withName: names it.

2.2 The standard libraries

import("stdfaust.lib") brings in the whole FAUST standard library under short prefixes. This is the real reason to drop to source: Phausto wraps a large part of it, but not all of it.

PrefixLibrary
os.Oscillators
no.Noises
fi.Filters
en.Envelopes
ef.Misc effects
re.Reverbs
co.Compressors
pm.Physical modelling
ba.Basics
ma.Maths
si.Signals
an.Analysis
dm.Demos
sf.Synth files
Composition operators FAUST's five composition operators appear throughout: : sequential, , parallel, <: split, :> merge, and ~ recursive. Phausto's =>, ,, splitTo:, mergeWith: and ~ map onto them one for one — see Connecting Unit Generators.

2.3 Reaching the controls

Controls declared in FAUST source behave like any other parameter. The label in the source becomes the parameter name:

s1 := x1 sliderFor: 'tempo'.  s1 openInWindow.
s2 := x1 sliderFor: 'freq'.   s2 openInWindow.

"Nested group paths for controls inside library modules"
s3 := x1 sliderFor: 'Freeverb/0x00/RoomSize'.  s3 openInWindow.

x1 traceAllParams.   "the authoritative list"

2.4 Stored FAUST programs

DSPCode is a small convenience class holding complete FAUST programs as strings, reachable from the class side:

MessageReturns
DSPCode basicKickWithADSRA kick drum with an ADSR envelope
DSPCode basicHiHatFMAn FM hi-hat
DSPCode drumMachine7A seven-voice drum machine
DSPCode drumMachine8An eight-voice drum machine
dsp := DSP create: DSPCode drumMachine8.
dsp init.
dsp start.
dsp displayUI.

These are also worth reading as examples of complete, working FAUST programs.

3. The box layer

3.1 PhBox

A box is FAUST's internal representation of a signal expression. Phausto objects are always converted to a box before being assembled into a DSP — PhBox is the Pharo-side container, and every UGen ultimately produces one.

MessageEffect
asBoxThe box for any UGen, number or widget
asFaustCodeThe FAUST expression this box represents
fromString:Build a box from a FAUST expression
asDsp / asDspWithName:Compile the box into a DSP
asDspFileWrite the box out as a FAUST file
inputs / outputsChannel counts
errorBufferThe compiler's error output for this box
extractUIPrimitivesFromPrintRecover the widgets a box declares

PhBox also carries the whole operator set — =>, ,, arithmetic, comparison, ~, smoo, db2linear and the rest — which is why those operators work on anything that can become a box.

3.2 The concrete boxes

ClassRole
WireA pass-through connection
CutTerminate a signal — discard a channel
Select2Two-way selector
PhSelect4Four-way selector
PhMultiplierMultiplication box
PhIncrementerIncrementing box
SoundFileA sound file as a signal source
SamplePlayerSample playback box
Wire and Cut are not trivial In FAUST, routing is explicit: a parallel block with more outputs than the next stage has inputs needs the surplus terminated with Cut, and channels that must pass through untouched need Wire. Most channel-count errors are solved with one or the other.

3.3 The library context

The FAUST compiler needs a library context to build boxes in. Phausto manages this for you at start-up, but if you are constructing boxes by hand the messages are:

MessageEffect
BoxAPI new createLibContextCreate a compilation context
BoxAPI new destroyLibContextDestroy it
PhBox libContext / libContext:Whether a context is currently held
PhBox startUp:Context handling at image start-up
Boxes do not survive an image restart A box is a pointer into the FAUST compiler's memory. Saving an image with live boxes and reopening it leaves dangling references — rebuild your patches after a restart rather than expecting them to resume.

4. The Box API

BoxAPI is the FFI binding to the C functions of FAUST's box API, compiled into libfaust. This is the floor of the system: every operator in Phausto eventually becomes a call here.

4.1 Composition primitives

MessageFAUST operator
boxSeqFrom:to:: sequential composition
boxPar:and:, parallel composition
boxSplit:with:<: split
boxMerge:with::> merge
boxRecursive:with:~ recursive composition

4.2 Values, wires and widgets

MessageProduces
boxInt: / boxReal:Integer and floating-point constants
boxWire / boxCutA wire, and a terminated channel
boxButton: / boxCheckbox:Discrete widgets
boxHslider:init:min:max:step:A horizontal slider
boxVslider:init:min:max:step:A vertical slider
boxNumEntry:init:min:max:step:A numeric entry
boxHBarGraphAux:min:max:input:A horizontal meter
boxVBarGraphAux:min:max:input:A vertical meter
boxSoundFile:numChannels:A sound file source
boxReadOnlyTable:init:index:A read-only wavetable
boxSelect2Aux:input0:input1:A two-way selector
boxFromString:inputs:outputs:buffer:Compile a FAUST expression into a box
boxPrint:Print a box for inspection

4.3 Arithmetic and maths

GroupMessages
ArithmeticboxAdd:with:, boxSubtract:from:, boxMultiply:with:, boxDivide:by:, boxPower:exponent:, boxRem:with:, boxFModBetween:and:
ComparisonboxGt:than:, boxGE:than:, boxLT:than:, boxLE:than:, boxEQ:than:, boxNE:than:
RangesboxMinBetween:and:, boxMaxBetween:and:
RoundingboxFloor, boxCeil, boxRound, boxRint, boxAbs
TranscendentalboxSin, boxCos, boxTan, boxAsin, boxAcos, boxAtan, boxExp, boxLog, boxLog10, boxSqrt
You rarely want this layer The Box API exists so the UGen layer can be built on it. Calling it directly means managing contexts, checking for null boxes and tracking channel counts by hand. Prefer a raw FAUST string — §2 — which gets you the same expressive power with the compiler checking your work.

5. Inspecting what Phausto generated

The most useful thing about the lower layers, for most people, is reading rather than writing them. Any DSP will show you the FAUST it compiled:

synth := PulseOsc new => ADSREnv new => MoogVcf new.
dsp := synth stereo asDsp.
dsp init.

dsp generatedCode.        "the FAUST source Phausto built"
synth asBox asFaustCode.  "the expression for one box"
The fastest way to learn the operators Build a small chain, read generatedCode, change one operator, read it again. The difference between , and +, or between applying stereo before and after an effect, becomes obvious immediately in the generated source — and is often hard to hear.

6. Where to go next

DocumentWhat it covers
Architecture & InternalsThe engine beneath the Box API.
Connecting UGensThe operators these primitives implement.
DSP & Parameter APIDriving a DSP however it was built.
ExportingTaking generated FAUST out of Pharo.

7. Troubleshooting

My FAUST string fails to compile and the error is unhelpful

Ask the engine directly: PhaustoDynamicEngine new getLastError returns the FAUST compiler's own message, which names the line. See Architecture & Internals.

A null box exception

A box expression produced nothing — nearly always a channel-count mismatch. Check inputs and outputs on each part, and terminate surplus channels with Cut — §3.2.

My FAUST code works in the online editor but not here

Check that process is defined and that every library you use is imported. Phausto compiles exactly the string you give it, with no implicit preamble.

Controls declared in my FAUST source do not appear

A FAUST widget only exists if it is actually used in process. An unreferenced slider is optimised away. §2.3.

Boxes stop working after saving and reopening the image

They hold pointers into the compiler's memory. Rebuild after a restart — §3.3.

I want a FAUST function Phausto has no UGen for

That is exactly what §2 is for — write the string and wrap it in a DSP.