Turning a DSP into an instrument you can play: note numbers instead of frequencies, MIDI-enabled DSPs, on-screen keyboards, and mapping hardware controllers to parameters.

1. Notes, not frequencies

A DSP thinks in hertz; music is usually written in notes. MIDI note numbers bridge the two: an integer from 0 to 127, where 60 is middle C and each step is a semitone. Phausto converts between the two representations in several places so you rarely have to.

1.1 Converting by hand

ExpressionConverts
60 midiNNToFreqMIDI note number to hertz, in Pharo
aSignal midikey2hzMIDI note number to hertz, inside the signal graph
PhMidiKey2HzThe same conversion as a UGen
PhHz2MidiKeyHertz back to a MIDI note number
PhPianoKey2HzPiano key number to hertz
PhHz2PianoKeyHertz to piano key number
PhSemi2RatioSemitones to a frequency ratio — for transposition
PhCent2RatioCents to a frequency ratio — for fine tuning

The distinction matters: midiNNToFreq is a Pharo message that computes a number before the DSP is built, while midikey2hz and PhMidiKey2Hz operate on a signal at audio rate. Use the first for a fixed note, the second when the note number is itself modulated.

"A fixed note, converted once at build time"
osc := SineOsc new freq: 69 midiNNToFreq.   "A4, 440 Hz"

"A note number that changes — converted in the graph"
osc := SineOsc new freq: (noteSignal midikey2hz).

2. Playing a note

method playNote: aMidiNN prefix: aString dur: aDuration

This one message does everything a note-on/note-off pair does: it converts the note number to a frequency, writes it to the instrument's frequency parameter, opens the gate, waits, and closes the gate again.

dsp playNote: 60 prefix: 'ElecGuitar' dur: 0.25.

2.1 Preparing an instrument

The prefix: is how the method finds the two parameters it needs. The instrument must expose a frequency and a gate whose names begin with that prefix, which you arrange by passing symbols to the setters:

"Symbols name the parameters rather than fixing their values"
synth := ElecGuitar new
  freq:    #ElecGuitarFreq;
  trigger: #ElecGuitarTrigger.

dsp := synth asDsp.
dsp init.
dsp start.
Any UGen can become playable There is nothing guitar-specific here. Give any UGen with a frequency and a gate a matching pair of symbol labels and playNote:prefix:dur: will play it — including a TpSampler, which is how sample-based melodic playback works. See Sequencing §4.3.

2.2 Patterns

With that in place, a melody is an ordinary Pharo loop. Fork it so the image stays responsive:

"A random line, 128 notes, 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.

Because it is just Pharo, a scale is a collection, a chord is three sends, and a probabilistic sequence is an ifTrue:. This is the point at which Phausto stops being a synthesiser and starts being a composition environment.

"A D minor pentatonic scale, ascending"
scale := #(62 65 67 69 72).
[ scale do: [ :n |
    dsp playNote: n prefix: 'ElecGuitar' dur: 0.2.
    220 milliSeconds wait ] ] fork.

3. MIDI-enabled DSPs

A DSP can be compiled with MIDI support built in, so that the FAUST runtime interprets MIDI messages itself rather than requiring you to translate them:

MessageEffect
asDspMIDICompile the UGen chain as a MIDI-enabled DSP
asDspMIDIWithName:The same, with a name you choose
isMIDIWhether a DSP was built with MIDI support
isMIDI:Set the MIDI flag
synth := SawOsc new => ADSREnv new => MoogVcf new.
dsp := synth asDspMIDI.
dsp init.
dsp start.
Two different things called MIDI playNote:prefix:dur: uses MIDI note numbers but is not MIDI — it is Pharo writing to parameters. asDspMIDI builds a DSP that understands actual MIDI messages. You can use either, or both.

4. On-screen keyboards

For trying an instrument out, Phausto can open a piano keyboard bound to it:

MessageEffect
keyBoardFor:A keyboard presenter bound to a named instrument
requirePianoKeyboardEnsure the keyboard component is available
kb := dsp keyBoardFor: 'ElecGuitar'.
kb openInWindow.

The keyboard sends the same note events playNote:prefix:dur: does, so an instrument prepared as in §2.1 works with it immediately.

5. Mapping controllers

FAUST supports metadata declarations that bind a UI element to a MIDI control, and Phausto exposes them directly on UIPrimitive. The binding is declared on the widget when you build the patch, and the runtime does the rest.

MessageBinds to
midiCtrl: aNumberA MIDI continuous controller number, any channel
midiCtrl: aNumber channel: aChannelA controller on a specific channel
midiKeyon: aPitchNote-on for a given pitch
midiPitchwheelThe pitch bend wheel
declare: aKey value: aValueAny FAUST metadata declaration
belaPin: aBelaPinAn analogue pin on a Bela board
"Bind the filter cutoff to the modulation wheel (CC 1)"
cutoff := PhHSlider new
  label: 'Cutoff' values: #(800 40 12000 1);
  midiCtrl: 1.

voice := SawOsc new => (MoogVcf new cutoff: cutoff smoo).
dsp := voice stereo asDspMIDI.
Smooth mapped controls MIDI controllers send coarse 7-bit values, so a mapped parameter steps in 128 increments and will audibly zipper. Append smoo — see Envelopes §5.

The same belaPin: declaration is what lets a patch exported to a Bela board read its analogue inputs — see Exporting.

6. The MIDI instrument classes

Several physical models ship in a MIDI-ready variant, already wired so that note number and gate arrive where they should. When you want to play an instrument rather than design one, start with these:

ClassInstrument
DjembeMIDIGoblet drum
MarimbaMIDITuned bars
ElecGuitarMIDIElectric guitar
GuitarMIDIAcoustic guitar
NylonGuitarMIDINylon-string guitar
ViolinMIDIBowed violin
KarplusStrongMIDIPlucked string
ClarinetMIDIClarinet
FluteMIDIFlute
BrassMIDIBrass

See Physical Modelling for what each one models.

7. External MIDI hardware

Phausto generates sound; it does not itself open MIDI ports. For sending and receiving MIDI to and from external hardware inside Pharo, the companion package is Pharo-Sound, which wraps PortMidi over uFFI. Coypu builds on both and adds live-coding sequencing, including MIDI output to hardware synthesisers.

PackageRole
PhaustoSynthesis and DSP; consumes note numbers and controller values
Pharo-SoundMIDI send and receive via PortMidi
CoypuLive-coding sequencer; drives Phausto, MIDI, SuperDirt, Kyma and Pd
A patch built with symbols is already controllable Whatever ends up driving your DSP — a forked loop, a MIDI keyboard, Coypu, an OSC message — it all arrives through the same named parameters. Designing with symbols rather than constants is what keeps every one of those routes open.

8. Where to go next

DocumentWhat it covers
Sequencing & SamplingGenerating the patterns that call playNote:.
UI PrimitivesThe widgets that carry the MIDI metadata.
TurboPhaustoA performance rack driven from Coypu.
ExportingTaking a MIDI patch out to a plugin or a Bela board.

9. Troubleshooting

playNote:prefix:dur: produces no sound

The instrument's frequency and gate are not labelled with the prefix. Set them with symbols and confirm the resulting names with traceAllParams — §2.1.

Notes sound but always at the same pitch

The frequency was fixed as a number at construction time, so the note number has nowhere to go. Pass a symbol instead — §2.1.

Notes never release, and the sound piles up

The gate parameter is not being found, so the note-off half of the cycle does nothing. Check the trigger label matches the prefix — §2.1.

My MIDI controller does nothing

Check three things in order: the DSP was built with asDspMIDI rather than asDsp (§3); the widget carries a midiCtrl: declaration (§5); and the controller number and channel match what the hardware sends.

A mapped control moves in audible steps

MIDI is 7-bit. Add smoo — §5.

I want to send MIDI out to a hardware synth

That is Pharo-Sound or Coypu, not Phausto — §7.