Skip to content

Mini-Notation Grammar

Every token that can go inside pattern brackets. The examples below are fragments; a pattern goes to a track like this:

use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.set_instrument(Sampler(Kit("TR-808")));
drums << [bd <sd [sd sd]>, ch*8, <_ oh>];
PLAY;

How elements are grouped and how time is divided.

TokenNameMeaning
[ … ]SequenceElements share the slot, each gets slot / count. Nest to subdivide.
,Parallel groupsSplit a bracket into simultaneous voices, each on its own time grid.
< … >AlternationOne element per cycle, chosen by cycle % count; fills the whole slot.
{ … }PolymetricSteps per cycle = length of the first group (or 1 for a single group).
{ … }%nPolymetric ÷ nForce n steps per cycle regardless of group length.
_RestA silent slot.
let sequence = [C4 D4 E4]; // three slots, 1/3 cycle each
let nested = [[C4 D4] E4]; // C4,D4 in the first half; E4 in the second
let parallel = [C4 D4, E4 F4 G4]; // two voices, 2-against-3
let alt = <C4 D4 E4>; // C4, then D4, then E4 — one per cycle
let poly = {C4 D4 C4 E4}%3; // three steps per cycle, phasing over four
let with_rest = [C4 _ E4 _]; // notes on slots 1 and 3

A pattern nested in a slot plays exactly what it plays on its own, fitted into the slot. A pattern inside < … > advances one cycle each time its turn comes round, so every element of an inner alternation gets played:

let turns = <<C4 D4> E4>; // C4 E4 D4 E4, then repeats

Postfix timing shorthand on a single element. At most one per element.

TokenNameEffectExampleEquivalent
*nFastPlay n times within the slot (speeds up)bd*2[bd bd]
/nSlowStretch the element over n cycles in the slot[C4 D4]/2spans 2 cycles
@nWeightTake an n× share of the cycle (plays once, longer)bd@2 sdbd 2/3, sd 1/3
!nReplicateExpand into n separate slots at normal speedbd!3bd bd bd
let fast = [bd sd*2]; // sd plays twice inside its half
let slow = [<C4 D4>/2 E4]; // the alternation advances every 2 cycles
let weighted = [C4@3 D4]; // long C4, quick D4
let replicate = [bd!4]; // same as [bd bd bd bd]

*n, /n, and @n accept decimals (*1.5, @2.5). *n and /n take 0.0001 to 10000, the range of .fast() and .slow(); @n must be greater than 0 (_ is a rest); !n takes integers only.

Postfixes that shape what an element plays. These combine with each other and with a modifier.

TokenNameMeaning
^vVelocityStrike velocity 0–127, e.g. C4^120.
(k,n)Euclideank pulses spread over n steps.
(k,n,r)Euclidean + rotAs above, rotated left by r steps, modulo n.
Root:QualityChordA chord, e.g. C4:maj7; add ~i for inversion i (C4:maj7~1), ~-i to invert downwards (C4:maj~-1).
^NScale degreeDegree N of the current scale/key (see Write in a Key).
^N:QualityDegree chordA chord built on scale degree N, with an optional ~i.
^N:Diatonic chordThe key’s own triad on degree N; ^N:~i inverts it.
^bN, ^#NAltered degreeDegree N a semitone lower or higher, e.g. ^b3, ^#4, ^b-2. As a chord root it names its quality: ^b6:maj.
.method(…)Sample methodShape one sample hit; chains, e.g. bd.vel(0.8).pan(0.5).
let accented = [C4^120 C4^60 C4^60 C4^60]; // accent on beat 1
let euclid = [bd(3,8) sd(5,8,2)]; // euclidean kick + rotated snare
let chords = [D4:min7 G4:7 C4:maj7~1]; // ii–V–I, last chord inverted
let degrees = [^1 ^3 ^5 ^3]; // arpeggio over the current scale
let diatonic = [^1: ^4: ^5:~1]; // the key's triads, the last inverted
let borrowed = [^1: ^b6:maj ^b7:maj ^1:]; // bVI and bVII, borrowed from the parallel minor
let lower = [c4 e4:min~-1]; // lower case; E minor inverted downwards
let shaped = [bd.gain(1.2) sd.pitch(-5).pan(0.5)];

When several postfixes attach to one element they appear in a fixed order:

element velocity euclid modifier
C4 ^80 (3,8) *2

So C4^80(3,8)*2 is valid; reordering the postfixes is not.

What can sit in a slot:

KindExamplesNotes
NoteC4, F#3, Bb-1, g9Scientific pitch; octaves -1–9 (C4 = MIDI 60). Upper or lower case inside a pattern; upper case only outside one.
Number60, -5, 0.5Raw values for numeric patterns and automation.
Samplebd, sd, hhKit sample names; accept .method(…) postfixes.
ChordC4:maj, a3:min7See the chord qualities. Only inside a pattern; outside one, use chord().
Scale degree^1, ^-3, ^b3, ^5:min, ^2:Resolved against the active scale/key.
Rest_Silence for one slot.

{ … } gives every element one step. %n sets the steps per cycle; without it, a group has as many steps per cycle as its first voice has elements, or 1 for a group with one voice. A voice of L elements over N steps runs at N / L passes per cycle, and wraps when the two don’t divide.

PatternSteps/cycleVoice lengthsPasses/cycle
{C4 D4 E4}131/3
{C4 D4 E4}%3331 — as [C4 D4 E4]
{C4 D4 E4}%6632
{C4 E4 G4, F4 A4}33, 21, 3/2

Voices in { … } share one grid of steps; voices in [ … , … ] each divide the cycle by their own length.

(k,n) spreads k hits over n steps as evenly as possible, inside the element’s slot; the element sounds on the hits and rests on the other steps. (k,n,r) rotates the result left by r steps, modulo n.

Like every modifier and decoration, (k,n) belongs to an element inside brackets: write [<C4 E4>(5,16)], not <C4 E4>(5,16). Outside brackets the same rhythm is the method <C4 E4>.euclid(5,16).

Rotation(3,8,r)Hit steps
0x . . x . . x .0, 3, 6
2. x . . x . x .1, 4, 6
3x . . x . x . .0, 3, 5

Traditional cells written this way:

PatternHitsName
(3,4)x x x .Cumbia
(3,8)x . . x . . x .Tresillo
(5,8)x . x x . x x .Cinquillo
(5,16)x . . x . . x . . x . . x . . .Bossa nova
(7,16)x . . x . x . x . . x . x . x .Samba