Two ways to make a patch play itself: inside the signal graph with pulses and counters, or outside it with forked Pharo processes — plus the TpSampler multisample player.
1. Two places time can live
Rhythm in Phausto can be generated in either of two places, and knowing which you are using explains most of the surprises.
Pulse or counter is part of the signal graph. It is sample-accurate, runs on the audio thread, and keeps perfect time regardless of what the image is doing.trig: or playNote:prefix:dur: messages. It is far more flexible, can use the whole language, but is only as accurate as Pharo's scheduler.Use the first for steady rhythmic engines, the second for anything that needs decisions, randomness or live interaction. Most real patches use both.
2. Pulses, counters and time tools
Eighteen UGens are dedicated to generating and dividing time. The essentials:
| Class | What it does |
|---|---|
| Pulse | A repeating pulse; set the interval with period: |
| Pulsen | A pulse with an explicit length as well as a period |
| Spulse | A single, non-repeating pulse |
| PhImpulsify | Converts a gate into a one-sample impulse |
| PhTempo | Tempo as a signal, in BPM |
| PhBeat | Beat clock derived from a tempo |
| PhSubBeat | Subdivisions of the beat |
| PhCountUp / PhCountDown | Counters, with looping variants |
| PhCycle | Cycles through a range |
| PhRamp / PhSweep | Linear ramps over time |
| PhTime | Elapsed time as a signal |
| PhSequencer | Step sequencer with a trigger: input |
A pulse becomes a rhythm the moment you feed it to something that responds to a trigger — an envelope, a drum model, a sampler:
"A djembe struck every 300 ms, entirely inside the DSP"
drum := Djembe new trigger: (Pulse new period: 0.3).
dsp := drum stereo asDsp.
dsp init.
dsp start.
dsp stop.
2.1 A modulated pulse
Because period: accepts a UGen, the tempo itself can be modulated — giving
accelerating, decelerating or drifting rhythms that no external sequencer could produce
as cleanly:
"Two pulse generators — the first has its period driven by an LFO"
pulse1 := Pulsen new period: (LFOTriPos new freq: 0.2; offset: 0.05; amount: 4).
pulse2 := Pulsen new period: 0.35.
"Two physical models, one triggered by each pulse"
djembe := Djembe new trigger: pulse1.
marimba := Marimba new
trigger: pulse2;
freq: (LFORandomPos new offset: 20; amount: 600; freq: (1 / 0.35)).
"Mix, chuck into reverb, make it stereo"
dsp := (djembe + marimba => GreyHole new) stereo asDsp.
dsp init.
dsp start.
dsp stop.
Note LFORandomPos driving the marimba's pitch at exactly the pulse rate
(1 / 0.35): a new random pitch per strike, with no scheduling code at all.
3. Sequencing from Pharo
The other approach keeps the DSP simple and drives it with messages. This is where Phausto starts to feel like a live coding environment.
3.1 Labelling with symbols
playNote:prefix:dur: finds an instrument's frequency and gate by name, built
from a prefix you supply. For it to work, those two parameters must be labelled to match.
Passing a symbol to a setter does exactly that:
"Symbols set the parameter labels rather than fixing values"
synth := ElecGuitar new
freq: #ElecGuitarFreq;
trigger: #ElecGuitarTrigger.
dsp := synth asDsp.
dsp init.
dsp start.
3.2 A melodic pattern
"128 random MIDI notes between 28 and 76, one every 125 ms"
pattern := [
dsp playNote: (Random new nextIntegerBetween: 28 and: 76)
prefix: 'ElecGuitar'
dur: 0.11.
(Delay forMilliseconds: 125) wait
].
[128 timesRepeat: pattern] fork.
dsp stop.
aMidiNN is a MIDI note number (middle C is 60), aString the
label prefix, and aDuration the note length in seconds. The method converts
the note number to hertz and performs the gate-on, wait, gate-off cycle for you.
fork the loop blocks the UI process and the image freezes until it
finishes. Forked blocks also compose: several running at once give you polyrhythm for
free.
4. TpSampler
TpSampler is the multisample player from
TurboPhausto. Point it at a folder of audio files and it
exposes an index to choose between them and a trigger to fire them.
.wav or .aiff files
— no subfolders, no stray files — and every file must have the same channel count. Files are
indexed in sorted filename order. Sample folders such as TurboSamples and
MoofLodSamples are in the Phausto repository.
4.1 Loading a folder
"Drag a folder into the Playground and Phausto writes the path string for you"
sp := TpSampler new pathToFolder: '/Users/you/Documents/TurboSamples/conga'.
"TpSampler is mono even when the files are stereo — send stereo to widen it"
dsp := sp stereo asDsp.
dsp init.
dsp start.
"Play it from the UI: tpSamplerTrigger fires, tpSamplerIndex selects"
dsp displayUI.
4.2 Algorithmic triggering
"Random samples at random intervals"
[128 timesRepeat: [
dsp trig: 'tpSamplerTrigger'.
dsp setValue: (Random new nextIntegerBetween: 1 and: 9)
parameter: 'tpSamplerIndex'.
(Random new nextIntegerBetween: 80 and: 310) milliSeconds wait
]] fork.
4.3 Melodic playback
A sampler is also an instrument: fix the index and play the same file chromatically. MIDI note 60 plays at the file's original speed, and other notes resample around it.
"Choose one sample, then play it as a pitched instrument"
dsp setValue: 8 parameter: 'tpSamplerIndex'.
[128 timesRepeat: [
dsp playNote: (Random new nextIntegerBetween: 35 and: 78)
prefix: 'tpSampler'
dur: 0.1.
110 milliSeconds wait
]] fork.
dsp stop.
dsp destroy.
| Message | Effect |
|---|---|
| pathToFolder: | Load a folder of samples |
| pathToFile: | Load a single file instead |
| numberOfSamples | How many files were found |
| sampleNamesSorted | The filenames, in index order |
| dsp trig: 'tpSamplerTrigger' | Fire the current sample |
| dsp setValue: n parameter: 'tpSamplerIndex' | Choose a sample by index |
| dsp playNote: n prefix: 'tpSampler' dur: s | Play it pitched to a MIDI note |
sp sampleNamesSorted tells you exactly which file each index refers to. An
index beyond the end of the folder plays the last available sample rather than failing.
6. Troubleshooting
My forked loop froze the image
It was probably not forked. A bare 128 timesRepeat: [...] runs on the UI
process. Wrap it: [128 timesRepeat: pattern] fork — §3.2.
A forked loop keeps playing after I stop the DSP
The process is still alive and still sending messages. Stop it from the Process Browser, or guard the loop with a flag you can flip. Destroying the DSP under a running loop can raise errors on every iteration.
playNote:prefix:dur: does nothing
The instrument's frequency and gate are not labelled to match the prefix. Set them with
symbols first — §3.1 — and confirm the resulting names with dsp traceAllParams.
TpSampler is silent, or loads nothing
Check the folder holds only audio files with a consistent channel count, and that the path
is absolute. sp numberOfSamples returning zero means the folder was not read.
See §4.
The sampler plays but only ever the same sound
tpSamplerIndex is not being set, or is being set outside the valid range —
indices past the end fall back to the last file. Confirm with
sp sampleNamesSorted.
My in-DSP pulse rhythm drifts against the forked one
They are driven by different clocks — the audio thread and the Pharo scheduler — and will never lock. Pick one source of time per rhythmic layer. See §1.