Unit Generators are the atoms of synthesis in Phausto. There are over five hundred of them and they all behave the same way — this page is about what they have in common.

1. What a Unit Generator is

A Unit Generator — UGen — is an object that describes a signal. Oscillators, noise sources, envelopes, filters, effects, physical models and even arithmetic operators are all UGens. They are all subclasses of UnitGenerator, and there are 506 of them in the current package.

A UGen is a description, not a sound. Sending it messages builds a bigger description; sending it asDsp hands that description to the FAUST engine, which compiles it to native code. Nothing is heard until then. This is why you can freely build, inspect and recombine UGens without any audio running.

"White noise is the simplest signal source there is"
noise := Noise new.
dsp := noise stereo asDsp.
dsp init.
dsp start.
dsp displayUI.   "one knob: uLevel"
dsp stop.

1.1 Where the idea comes from

The Unit Generator was introduced by Max Mathews at Bell Labs in the 1950s, in the MUSIC family of languages. Nearly every audio environment since — Csound, SuperCollider, Max, Pd, ChucK, FAUST — has kept the concept and mostly kept the name. If you have used any of them, Phausto's UGens will feel familiar; what is different is that here they are ordinary Smalltalk objects, inspectable and debuggable in a live image.

2. What every UGen has

2.1 uLevel, the universal control

Every UGen carries a uLevel — a linear gain applied to its output. It is the one parameter you can count on being present, whatever the UGen is:

sine := SineOsc new uLevel: 0.3.
Linear, not perceptual uLevel is a straight multiplication. Human loudness perception is closer to logarithmic, so a change from 0.1 to 0.2 sounds far larger than one from 0.8 to 0.9. When you want decibels, convert with PhDb2Linear or the db2linear message — see Math & Conversion Tools.

Because uLevel: accepts a number, a UGen or a UI primitive, it doubles as an amplitude modulation input:

"Tremolo: amplitude driven by a slow oscillator"
sine := SineOsc new uLevel: (LFOTri new freq: 5).

2.2 Labels and parameter names

Each UGen has a label, which defaults to its class name. The label is what prefixes every parameter name the UGen contributes to the finished DSP — which is why a PulseOsc gives you PulseOscFreq and PulseOscDuty.

Change the label and you change the parameter names:

"Two oscillators that would otherwise collide"
a := SineOsc new label: 'Left'.
b := SineOsc new label: 'Right'.

"now addressable as LeftFreq and RightFreq"
Why you would do this Two instances of the same class in one DSP would otherwise expose the same parameter names. Relabelling also lets playNote:prefix:dur: find the frequency and gate of an arbitrary instrument — see MIDI & Playing Notes.

2.3 Inputs and outputs

Every UGen knows its channel count, through numberOfInputs and numberOfOutputs. This is what makes connection errors catchable: a UGen with two outputs cannot be fed into one expecting one input without an explicit conversion. stereo and mono are the two conversions you will use constantly.

MessageMeaning
uLevel:Linear output gain — accepts a number, UGen or UI primitive
label:Rename the UGen, and with it all its parameter names
stereoDuplicate the signal to two channels
monoCollapse to a single channel
numberOfInputsHow many channels this UGen consumes
numberOfOutputsHow many channels it produces
asBoxThe underlying FAUST box — see Raw FAUST & the Box API
asDspCompile into a playable DSP

3. The families of UGen

UGens are organised into families by package tag. The counts below are the current contents of the package — use them to gauge where the depth is.

FamilySizeExamplesGuide
Filters60MoogLadder, PhSvfLp, LowpassFilters
Effects47GreyHole, AutoWah, PhEchoEffects
Math46PhLog2, PhSignum, PhSampleRateMath
Oscillators42SineOsc, SawOsc, CZpulseSynthesis
Physical models87Djembe, ElecGuitar, ClarinetModelPhysical Modelling
Compressors30PhCompressorStereo, PhLimiter1176MonoDynamics
Toolkit23PhSequencer, PhSelectN, PhLooperSequencing
Counters & time18Pulse, PhTempo, PhBeatSequencing
Conversion tools17PhMidiKey2Hz, PhDb2LinearConversions
TurboPhausto17TpSampler, Acid, TpKick99TurboPhausto
Basics16PhLatch, PhBitCrusher, PhLineUGen Library
Antialiased14AASine, ArcTan2, Cosine1UGen Library
Envelopes13ADSREnv, AREnv, AHDSREnvBiasEnvelopes
Synths12Kick, Clap, Fm4OpSynthesis
Signals11PhSmooth, PhBus, PhRevUGen Library
Operations10PhAdder, PhMultiplicatorConnecting
UI primitives9PhHSlider, PhButton, PhNumEntryUI Primitives
Dx75Dx7Op, Dx7Algo, Dx7EnvFM Synthesis
Noises4Noise, PinkNoise, SparseNoiseUGen Library

The full catalogue, class by class, is in the UGen Library reference.

4. Where the setters come from

Browse SineOsc in the System Browser and you will find exactly one method: initialize. Yet SineOsc new freq: 200; uLevel: 0.5 works. This surprises people, and it is worth understanding early.

The fluid setter API is supplied by traits. freq: comes from PhFrequencySetter, period: from PhPeriodSetter, trigger: and gate: from PhTriggerSetter, and a broad catch-all of thirty-five parameter setters from PhParamsSetter. Twenty-two such traits are composed into UGens across the hierarchy.

The practical consequence Reading one class will not tell you its API. Instead, instantiate it, call asDsp, init and traceAllParams, and read the answer off the Transcript. The complete list of traits and their selectors is in Setter Traits.

Every setter accepts the same three kinds of argument, which is what makes modulation so easy to write:

"a number — fixed at compile time, not changeable at runtime"
osc := SineOsc new freq: 440.

"a UGen — modulation"
osc := SineOsc new freq: (LFOTri new freq: 3) * 20 + 440.

"a symbol — creates a named, runtime-controllable parameter"
osc := SineOsc new freq: #myFreq.

5. UGens, numbers and boxes

Underneath, every UGen becomes a FAUST box. Phausto extends Number, String, Symbol and Array so that ordinary Pharo values can enter a signal graph wherever a UGen is expected:

ExpressionResult
200 asBoxA constant signal, usable in arithmetic with UGens
60 midiNNToFreqMIDI note number converted to hertz
#gate asPhButtonA named button UI primitive
#cutoff asPhHSliderA named horizontal slider
anArray asSumOfUGenAll elements summed into one signal
anArray asChainOfUGenAll elements chained in series

Which is what lets a pitch envelope be written as plain arithmetic:

"An ADSR scaled to 200 Hz of sweep, offset from a 100 Hz base"
pitchEnv := 200 asBox * ADSREnv new.
osc := TriOsc new freq: (100 asBox + pitchEnv).

The operators themselves are covered in Connecting Unit Generators; the box layer beneath them in Raw FAUST & the Box API.

6. Where to go next

DocumentWhat it covers
Connecting UGensChaining, stacking, arithmetic, recursion and splitting.
Parameters & ControlNaming, triggering and automating what you have built.
Setter TraitsAll 22 traits and every selector they provide.
UGen LibraryThe complete catalogue, family by family.

7. Troubleshooting

The System Browser shows almost no methods on the UGen I want to use

That is expected — the setters arrive by trait. See §4, and Setter Traits.

Two copies of the same UGen fight over the same knob

They share a label, so they share parameter names. Give at least one of them its own label: — §2.2.

doesNotUnderstand on a setter I am sure exists

The trait providing it is not composed into that particular class. Check the selector against Setter Traits; several near-synonyms exist — freq:, frequency:, fr:, cutoff: — and which one applies depends on the family.

Setting uLevel: to 2 distorts instead of getting louder

uLevel is a raw multiplier with no limiting. Values above 1 will clip. Add a limiter from Dynamics, or scale down elsewhere in the chain.