Skip to content

Pattern Syntax

AlgoBooth uses a compact pattern language called mini-notation — a small domain-specific language for describing rhythm, pitch, and structure in very little text. This page covers the full syntax with examples.

The Cycle

Everything in AlgoBooth runs in cycles. By default, one cycle is 2 seconds. All patterns loop continuously, repeating every cycle. When you add more steps to a sequence, they are compressed to fit — the cycle duration stays constant.

// 2 steps — each step is 1 second
s("bd sd")
// 4 steps — each step is 0.5 seconds (120 BPM equivalent)
s("bd hh sd hh")
// 8 steps — each step is 0.25 seconds
s("bd hh bd sd bd hh bd sd")

Core Functions

s() / sound() — Play Samples

s() plays a named sample. The argument is a mini-notation string.

s("bd sd hh cp")

note() — Play Pitched Notes

note() plays a pitched sound. Accepts note names or MIDI numbers.

note("c3 e3 g3 b3")
note("48 52 55 59")

n() — Select Sample Index

n() selects which variant of a sample to play (zero-indexed).

s("hh*4").n("0 1 2 3")

stack() — Play Patterns Simultaneously

stack() combines multiple patterns into one, all running in the same cycle.

stack(
s("bd*4"),
s("~ sd ~ sd"),
note("c2 g2 f2 g2").s("sawtooth")
)

cat() — Concatenate Patterns

cat() plays patterns one after another, each taking one full cycle.

cat(
s("bd sd bd sd"),
s("cp hh cp hh")
)

seq() — Sequence of Patterns

seq() is similar to cat() but divides the cycle among all patterns evenly.

seq(s("bd sd"), s("hh hh"), s("cp ~"))

Mini-Notation Syntax

Sequence — Space

Separate events with spaces to play them in sequence. All events are compressed to fit one cycle.

s("bd sd")
s("bd hh sd hh")
s("bd hh hh sd hh bd sd hh")

Rest — ~

Use ~ to insert silence at a step position.

s("bd ~ sd ~")
note("c3 ~ e3 ~")
note("c3 ~ ~ g3")

Subdivision — [ ]

Square brackets group events into a sub-sequence that occupies one step.

// [hh hh] takes the time of one step, playing two hi-hats
s("bd [hh hh] sd hh")
// Nest arbitrarily deep
s("bd [[hh hh] sd] bd cp")
// Multiple subdivisions in one pattern
s("bd [hh hh] sd [hh bd]")

Speed Up — *

Multiply an event or group to repeat it faster within its slot.

s("bd hh*2 sd hh") // hh plays twice in one step
s("bd hh*4 sd hh") // hh plays four times
s("[bd sd]*2") // the whole group plays twice per cycle
note("c3 e3*2 g3 b3")

Slow Down — /

Divide to spread a group across multiple cycles.

note("[c3 e3 g3 b3]/4") // plays over 4 cycles (each note is 2 seconds)
note("[c3 e3]/2") // plays over 2 cycles
s("[bd sd hh cp]/2")

Alternation — < >

Angle brackets cycle through their contents one item per cycle. The tempo does not change as you add or remove items.

s("<bd sd cp hh>") // plays one sound per cycle, rotating
note("c3 <e3 f3> g3") // middle note alternates each cycle
s("bd*4, [~ <sd cp>]*2") // snare or clap, alternating

Parallel — ,

Comma plays multiple things simultaneously in the same step. This is how you write chords.

note("c3,e3,g3") // C major chord
note("[c3,e3,g3] [f3,a3,c4]") // chord sequence
s("bd*4, hh*8, ~ sd ~ sd") // full beat with comma-separated layers

Elongate — @

@ sets the relative duration weight of an event. Default weight is 1.

note("c3@3 e3") // c3 is 3x longer than e3
note("c3@2 e3 g3") // c3 takes half the cycle, e3 and g3 split the other half
note("[c3@2 e3] g3 b3") // elongate inside a sub-sequence

Replicate — !

! repeats an event without speeding it up (unlike *).

note("c3!3 e3") // three c3 notes at the same speed as one, then e3
s("bd!2 sd hh")

Random Drop — ?

? gives an event a 50% chance of being silenced each cycle. Add a number for custom probability.

s("hh?") // 50% chance each cycle
s("hh?0.2") // 20% chance of silence
note("c3 e3? g3 b3?0.3")

Random Choice — |

| picks one of several alternatives at random each cycle.

s("bd | sd | cp")
note("c3 | e3 | g3")
s("bd hh | bd sd | bd cp")

Sample Index — :

: selects a specific sample variant by index (zero-based).

s("hh:0 hh:1 hh:2 hh:3")
s("bd:0 bd:2 bd:4")

Euclidean Rhythms — (beats, steps)

Round brackets distribute beats evenly across steps using the Euclidean algorithm. This produces many common world music rhythms automatically.

s("bd(3,8)") // 3 beats across 8 steps (clave rhythm)
s("bd(5,8)") // 5 over 8 (bossa nova clave)
s("hh(7,8)") // dense hi-hat pattern
s("bd(3,8,2)") // third argument shifts the rotation offset
// Layer Euclidean patterns
stack(
s("bd(3,8)"),
s("sd(2,8,2)"),
s("hh(7,8)")
)

Chaining Effects

All patterns support method chaining for effects and transformations:

s("bd hh sd hh")
.gain(0.8)
.room(0.2)
note("c3 e3 g3")
.s("sawtooth")
.lpf(800)
.delay(0.25)
.pan("0 0.5 1 0.5")

Common Effect Methods

MethodDescriptionExample
.gain(n)Volume (0–1).gain(0.8)
.room(n)Reverb amount (0–1+).room(0.5)
.delay(n)Echo send amount (0–1).delay(0.3)
.pan(n)Stereo position (0=left, 1=right).pan("0 1")
.lpf(hz)Low-pass filter cutoff in Hz.lpf(1200)
.hpf(hz)High-pass filter cutoff in Hz.hpf(200)
.speed(n)Sample playback speed.speed(2)
.slow(n)Slow pattern by factor.slow(2)
.fast(n)Speed up pattern by factor.fast(2)
.rev()Reverse pattern direction.rev()
.bank(name)Select drum machine preset.bank("RolandTR909")
.scale(name)Map n() to a musical scale.scale("C:minor")

Scales

The .scale() method maps numeric indices to musical scale degrees:

n("0 2 4 6 0 4 2").scale("C:minor").s("piano")
n("0 1 2 3 4 3 2 1").scale("D:major").s("gm_marimba")
n("<0 2 4>*4").scale("A:minor:pentatonic").s("sine")

Cycle through scales:

n("0 2 4 6").scale("<C:major D:mixolydian>/4").s("sine")

Pattern Examples

Classic house beat

s("bd*4, [~ cp]*2, [~ hh]*4").bank("RolandTR909")

Melody with bass

stack(
note("<c2 f2 g2 bb2>*4").s("sawtooth").lpf(600),
note("<c4 eb4 g4> <f4 a4 c5>").s("sine").room(0.3)
)

Euclidean groove

stack(
s("bd(3,8)"),
s("sd(2,8,3)"),
s("hh(5,8)").gain(0.6),
note("c2(3,8)").s("sawtooth").lpf(400)
)

Alternating chords

note("<[c3,e3,g3] [f3,a3,c4] [g3,b3,d4] [f3,a3,c4]>")
.s("gm_electric_piano_1")
.room(0.4)
.gain(0.7)