Polymetric & Euclidean
This chapter covers two ways to generate rhythm rather than write it out by hand. Polymetric patterns let groups of different lengths cycle at different rates, phasing against each other like Steve Reich loops. Euclidean rhythms distribute hits as evenly as possible across steps, producing many of the world’s classic rhythmic cells from two numbers.
Polymetric Patterns
Section titled “Polymetric Patterns”Curly braces {...} give each element one step. Without a subdivision modifier, one step equals one full cycle:
let slow = {C4 D4 E4}; // One note per cycle — spans 3 cycleslet fast = [C4 D4 E4]; // All three notes in one cycleThe %N Subdivision
Section titled “The %N Subdivision”%N packs N steps into each cycle. The resulting speed of a group is governed by one ratio:
speed_factor = N / L // N = steps per cycle, L = element count| Pattern | N | L | Factor | Effect | Events/cycle |
|---|---|---|---|---|---|
{C4 D4 E4} | 1 | 3 | 1/3 | Slow: spans 3 cycles | 1 |
{C4 D4 E4}%3 | 3 | 3 | 1 | Same as [C4 D4 E4] | 3 |
{C4 D4 E4}%6 | 6 | 3 | 2 | Double speed | 6 |
When N and L don’t divide evenly, the content wraps — and this is where it gets musical. {C4 D4}%3 has factor 3/2: three onsets per cycle at 0, 1/3, 2/3, but only two notes of content. Cycle 0 plays C4 D4 C4; cycle 1 picks up where it left off with D4 C4 D4. The content shifts by one position each cycle, phasing against the meter until it realigns after L cycles.
Multiple Groups: Shared Grid
Section titled “Multiple Groups: Shared Grid”Comma-separated groups inside {...} are the heart of polymetric writing. All groups land on the same onset grid, but each group’s content cycles at its own rate:
let poly = {C4 E4 G4, F4 A4};Without an explicit %N, N defaults to the first group’s length — here 3. Each group is sped up by its own N/L factor so every voice produces exactly N onsets per cycle:
| Time | Voice 1 (L=3, factor 1) | Voice 2 (L=2, factor 3/2) |
|---|---|---|
| 0 | C4 | F4 |
| 1/3 | E4 | A4 |
| 2/3 | G4 | F4 — content wraps |
Voice 1 repeats identically every cycle. Voice 2’s two-note content takes only 2/3 of a cycle per pass, so it drifts one position per cycle and realigns with voice 1 every 2 cycles. That slow churn of two loops sliding past each other is the polymetric sound.
An explicit %N sets the grid density for all groups at once:
let dense = {C4 D4 E4, F4 G4}%6; // 6 onsets/cycle; factors 2 and 3Polymetric {} vs Parallel [,]
Section titled “Polymetric {} vs Parallel [,]”Both layer voices, but they produce fundamentally different structures:
Polymetric {a b c, d e} | Parallel [a b c, d e] | |
|---|---|---|
| Voice 1 onsets | 0, 1/3, 2/3 | 0, 1/3, 2/3 |
| Voice 2 onsets | 0, 1/3, 2/3 | 0, 1/2 |
| Grid | Shared (N-step) | Independent per voice |
| Effect | Content phasing | Onset conflict |
A Polymetric Groove
Section titled “A Polymetric Groove”use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("TR-808")));
// 4-step grid; the 3-hat group phases against the kick-snaredrums << {bd sd bd sd, ch ch oh};
PLAY;Polymetric groups compose with everything else — modifiers and nested structures work inside {}, and a {...}%N group can sit inside a sequence as a single element:
let mixed = [{C4 D4 E4}%3 G4]; // Polymetric fills the first halflet rests = {_ C4 D4}%3; // Rests take steps tooEuclidean Rhythms
Section titled “Euclidean Rhythms”Give the euclidean algorithm a number of hits and a number of steps, and it spaces the hits as evenly as possible. Three hits over eight steps:
x . . x . . x .That’s the Cuban tresillo — the 3+3+2 cell underneath son, reggaeton, EDM, and half of pop music. Many traditional rhythms fall out of this one algorithm:
| Pattern | Hit pattern | Name |
|---|---|---|
(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 |
Inline Syntax
Section titled “Inline Syntax”Attach (hits, steps) to any element. The element sounds on the hit positions and rests on the others, all within its own slot:
let tresillo = [bd(3,8)]; // Tresillo kick filling the cyclelet mixed = [C4(3,8) E4 G4]; // Euclidean C4, plain E4 and G4Rotation
Section titled “Rotation”A third parameter rotates the hit pattern left by that many steps, wrapping around — same spacing, different downbeat:
| Rotation | (3,8) becomes | Onsets |
|---|---|---|
| 0 | x . . x . . x . | 0, 3, 6 |
| 2 | . x . . x . x . | 1, 4, 6 |
| 3 | x . . x . x . . | 0, 3, 5 |
Rotation wraps modulo the step count, so rotation 10 on 8 steps equals rotation 2. Layering rotations of the same cell creates interlocking parts:
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("CR-78")));
// Three tresillo rotations interlockingdrums << [bd(3,8,0), rs(3,8,2), hh(3,8,5)];
PLAY;Three Equivalent Spellings
Section titled “Three Equivalent Spellings”The inline notation has function and method counterparts that work on whole patterns:
let a = [C4(3,8)]; // Inline — single element inside []let b = euclid(3, 8, [C4]); // Function — any pattern as sourcelet c = [C4].euclid(3, 8); // Method — chains with other methodsAll three produce identical output; each takes an optional rotation as its last argument. Use inline inside patterns, the method when chaining transformations, the function for explicitness.
With a multi-note source, the notes are dealt onto the hit positions in order — and wrap if there are more hits than notes:
let dealt = euclid(3, 8, [C4 E4 G4]); // One note per hitlet wrapped = euclid(5, 8, [C4 E4]); // C4 E4 C4 E4 C4Euclidean Drum Patterns
Section titled “Euclidean Drum Patterns”Different hit counts over the same step count give voices that interlock without ever quite lining up:
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("TR-808")));
// Sparse, hypnotic — minimal technodrums << [bd(3,16), ch(7,16), sd(2,16,4)];
PLAY;And nothing says euclidean rhythms are just for drums:
let melody = MidiTrack(1);melody << [C4(3,8) E4(5,8) G4(7,8)];PLAY;Next Steps
Section titled “Next Steps”You can now generate rhythm three ways: by hand, by phasing meters, and by algorithm. Next, transform any of them in code.
- Transforming Patterns —
.fast(),.rotate(),.degrade()and friends - Microtiming — swing, nudge, and humanize
- Mini-Notation Grammar — the complete syntax reference