Coypu's terseness comes from extending Pharo's own classes. An integer answers rhythms, a string answers patterns, a symbol routes to an instrument — this page catalogues what each base class gained.
1. Why it reads the way it does
16 downbeats to: #kick contains no Coypu class name. That is deliberate: the
vocabulary is grafted onto the types you already have, so a pattern reads as a sentence
rather than as object construction.
| Class | Gains |
|---|---|
| Integer | Every named rhythm, random generators, note helpers |
| ByteString | Six pattern notations, note parsing, OSC helpers |
| ByteSymbol | Routing and live control of a part already playing |
| Array | Arithmetic, scales, Euclidean rhythms, conversion |
| Number | Tempo, MIDI conversion, OSC sending |
| SequenceableCollection | wrap: — the indexing rule the whole system runs on |
wrap: is the one to understand
aCollection wrap: n indexes modulo the size, one-based, so it never goes out of
bounds. Notes, durations, gate times and every effect parameter are read this way, which is
why lists of different lengths rotate against each other instead of failing.
2. Integer
The receiver is almost always a step count. All 31 named rhythms are Integer methods — see the Rhythm Library — alongside these:
| Message | Answers |
|---|---|
| bpm | The step duration for that tempo — p freq: 132 bpm |
| bars | A number of steps for that many bars |
| randomTrigs | A random gate pattern |
| randomTrigsWithProbability: n | The same at a chosen density |
| randomRhythm | A randomly chosen named rhythm |
| randomNotesFrom: array | Random notes from a collection |
| randomNotesFrom:octaves: | The same, octave-displaced |
| randomNotesIn: #( lo hi ) | Uniform between two MIDI notes |
| randomWalksOn:octaves:root: | A scale-coherent melodic walk |
| melodyFrom: scale | A melody with resolved cadence points |
| randomSamplesFromFolder: | A pattern of random samples from a SuperDirt folder |
| copiesOf: n | An array of self copies |
| copiesOfEach: array | Each element repeated self times |
| spreadOver: n | Floats from 0 to self in n steps |
| modulo: n | One-based modulo, for indexing |
| asRisingArray | 1 to self |
| midiNoteToFreq | MIDI note number to hertz |
| semitonesToSpeed | Semitones to a playback-rate multiplier |
| dirtNoteToSpeed | The same, for SuperDirt |
3. String
3.1 The six notations
A string can be read six different ways. Which message you send decides what the tokens mean:
| Message | Reads the string as |
|---|---|
| hexBeat | Hex digits, four steps each |
| asDirtNotes | Comma-separated pitches with rests and durations |
| asDirtIndex | The same, but sample indices |
| asDirtSounds | Sound names for SuperDirt or Phausto |
| asDirtLevel | The same, but level values |
| asMondoNotes / asMondoSounds / asMondoIndex | Mondo mini-notation — cycle-based, with grouping and alternation |
'F000' hexBeat to: #kick.
'36 , 38 , -/4 , 41' asDirtNotes to: #bass.
'bd [sd sd] bd <sd cp>' asMondoSounds to: #drums.
The asDirt… family is step-based and the Mondo family is cycle-based — the
difference is explained in Rhythms: Advanced §4.
Supporting pieces used by those parsers, occasionally useful alone:
| Message | Answers |
|---|---|
| asSeqGates | Gates from a space-separated string, ~ being a rest |
| asDirtPureNotes | Just the parsed note numbers, as an array |
| splitTopLevelSlots | Split on spaces at bracket depth zero |
| parseMondoLeaves | Expand one Mondo slot into leaves |
| chordsToArrays | Parse 'c-maj d-min' into interval arrays |
| parseChord | One chord to an interval array |
| multiplyStringsInString | Expand x*3 |
| withNRests | Expand x/4 |
3.2 Note names
asMidiNote is the parser the string notations use. It accepts a bare number,
or a note letter with an optional accidental and octave:
'c4' asMidiNote. "60"
'f#3' asMidiNote. "sharp"
'bb2' asMidiNote. "flat"
'cs5' asMidiNote. "TidalCycles-style sharp"
'c' asMidiNote. "octave defaults to 4"
Accidentals accept both conventions: # or s for sharp,
b or f for flat, and ##, x,
ss, bb, ff for the doubles. The result is clamped to
0–127.
4. Symbol
Symbols are instrument keys, and their extensions act on whatever is playing at that key — the live-performance vocabulary:
| Message | Effect |
|---|---|
| asRhythm | The named rhythm, always at 16 steps |
| to: aKey | Route the named rhythm to an instrument |
| to:index: | Route it and set sample indices |
| mute / unmute | Silence or restore |
| solo / unsolo | Isolate or release |
| flip | Invert the gates of the part playing there |
| rhythm: aName | Replace its gates with a named rhythm |
| gates: aRhythm | Replace its gates directly |
| notes: / index: / level: | Change its notes, sample indices or level |
| transpose: n | Shift its notes |
| swapWith: aKey | Exchange two parts |
| injectInto: aKey | Copy this part's gates, notes and durations to another key |
| x: / bw: / number: | Set synth parameters on a running part |
#kick flip.
#bass transpose: -12.
#kick swapWith: #snare.
#hh level: '0.4 0.8'.
5. Array
| Message | Answers |
|---|---|
| asSeq | A Sequencer from gates, with defaults filled in |
| asRhythm | A Rhythm |
| asNotes | A Sequencer where 0 means a rest and other values are notes |
| euclidean | A Euclidean rhythm from #( onsets steps ) |
| fullScale | A scale expanded across the MIDI range |
| intoScale: aSymbol | Map degrees onto a named scale |
| into: anArray | Index into another array, 0 staying a rest |
| of: anArray | Plain indexing |
| times: n | Repeat |
| offset: n | Rotate, wrapping |
| trigs / numberOfGates | Count the triggers |
| minDurationBetweenGates | The closest spacing — how asSeq picks a duration |
| randomOctaves: n | Displace each note randomly |
| arp: intervals | Arpeggiate over intervals |
| asSeries | #( 1 8 ) asSeries → 1 to 8 |
| root:octaves: | Expand a scale from a root over octaves |
| and: / and:and: | Build a Sequencer from gates, notes and durations |
6. Number and Collection
| Message | Answers |
|---|---|
| bpm | Step duration for a tempo |
| bars: n | Wait that many bars |
| midiNoteToFreq | MIDI note to hertz |
| asDirtArray | Wrap a scalar as a one-element array |
| toLocal: / toKyma: | Send the value as OSC to a named address |
| wait | Delay for that many seconds |
| randomsFromArray: #( lo hi ) | Random integers in a range |
| secondsInStepAt: | Convert seconds to steps |
On SequenceableCollection: wrap: as described in §1, and
asOSCMessageForSuperDirt to send a collection straight to SuperDirt.
BlockClosure gains loopFor:, which forks a block repeated a number
of times — handy for hand-rolled automation.
7. Binary operators
| Operator | On | Meaning |
|---|---|---|
, | Sequencer | Concatenate gates, notes and durations |
* | Sequencer | Repeat n times |
* | String, Character | Repeat, space-separated |
* + - | Array | Element-wise arithmetic with a number |
+ - | SequencerMono | Transpose. + answers a copy, - mutates |
< | Sequencer | Set notes — a binary form of notes: |
> | Sequencer | Route to a key — a binary form of to: |
>> | Symbol, SequencerMono | Copy gates into another key |
<< | String, Symbol | Send a value to that OSC parameter |
/ | String | Append n−1 rests |
@ | Array | Expand a scale by #( root octaves ) |
+ and - are not symmetrical
On SequencerMono, + deep-copies and answers a new Sequencer, while
- changes the receiver in place. Only one of them is safe to use on a part that
is already playing.
8. Traps
asMidiNote and asMidiNN disagree
'c4' asMidiNote is 60; 'c4' asMidiNN is 72. The string notations
use asMidiNote, so c4 means middle C throughout this manual. If a
melody is an octave out, this is usually why.
Sequencer>>size is the trigger count
Not the pattern length. gatesSize gives the length.
asRhythm is always 16 steps
#trueAksak asRhythm truncates a 13-step pattern at 16. Send the rhythm to an
integer instead — 13 trueAksak.
Array>>> writes to the Transcript rather than doing anything musical,
and a few OSC helpers hard-code a Kyma hostname. Nothing here depends on them.
10. Troubleshooting
A melody came out an octave high
asMidiNN rather than asMidiNote — §8.
doesNotUnderstand on a message this page lists
Check the receiver's class. Many messages exist on ByteString but not
Symbol, or on SequencerMono but not Sequencer — send
asString or asRhythm first.
Transposing with - changed a part that was playing
It mutates in place; + copies — §7.
My parameter list is not lining up with the notes
Each is read with wrap: independently, so different lengths rotate against each
other. Match the lengths if you want them locked — §1.
#( 3 8 ) euclidean gave an unexpected rotation
Coypu uses a Bresenham variant rather than Bjorklund. See Rhythms: Advanced §1.1 for which named rhythms it reproduces exactly.
Where do I see all of these in the image?
Browse the *Coypu extension protocols on Integer,
ByteString, ByteSymbol, Array and
Number.