You have the full toolkit. Euclidean rhythms, filter sweeps, stereo splits, stutters, sine-driven modulation, chunked variation, stacked layers. This lesson uses all of it. Three notes in eight slots become a living texture. One line of code becomes seven transforms deep. Then that line joins the full band.
s(), note(), n(), stack(), cat(), setcpm(35),
mini-notation (~ * [] <> / @ (k,n)),
.gain(), .pan(),
.lpf(), .lpq(), .attack(), .decay(),
.sustain(), .release(),
.room(), .size(),
.delay(), .delaytime(), .delayfeedback(),
.distort(), .scale(), voice-led chord voicings,
.every(), .sometimes(),
.jux(), .juxBy(), .off(), .add(note()),
.rev(), .fast(), .slow(), .ply(),
.speed(), sine.range(),
chord progressions with <>, and the full EDM palette from 0–9b.
Sixteen hats, steady. One quarter doubles speed—and it rotates. First beat, then second, then third, then fourth:
One quarter goes double-time. Next cycle, the next quarter. A scanning variation that moves across the pattern like a spotlight. Four cycles, the whole thing has been hit once.
Now on a melodic line instead of drums:
Same melody, but one quarter at a time gets doubled. The rest plays normally. Every four cycles it comes back around. Variation without randomness—the scanning is deterministic.
.chunk(N, fn) divides the pattern into N equal chunks. Each cycle, it applies the transform to one chunk, rotating which chunk gets hit. Cycle 1: chunk 1 transforms. Cycle 2: chunk 2. And so on. Creates a sweeping variation that moves across the pattern.
Try .chunk(8, rev) for finer rotation—eight slices, each one reversed in turn. Or .chunk(4, x => x.speed(2).gain(0.3)) for pitched-up ghost echoes scanning across each chunk.
The original melody, plus a copy a fifth above. Two voices from one line:
Both play at the same time. No delay, no stereo split. The copy is just transposed and quieter. Compare that to .off(), which shifts the copy in time, or .jux(), which splits it across stereo. .superimpose() stacks them directly on top of each other.
Now a copy that runs double-time and pans right:
.superimpose(fn) plays the original pattern plus a transformed copy simultaneously. Unlike .off() (time-delayed copy) or .jux() (stereo-split copy), superimpose stacks both in the same time and space. The transform function creates all the difference between the two layers.
Try .superimpose(rev) for original plus reversed simultaneously. Or .superimpose(x => x.add(note(12)).fast(2).gain(0.15)) for an octave-up double-time ghost.
Chain multiple transforms into a single function. Inside a chunk, one arrow function does two things at once:
Inside the chunk, the function does two things: doubles speed AND adds a fifth. The chunked section plays twice as fast and a fifth higher. The rest of the pattern stays normal.
Building complex transforms from simple ones. x => x.fast(2).add(note(7)).gain(0.2) reads: take the pattern, speed it up, transpose it, quiet it. Each method chains onto the last. One arrow function, three operations. This is how you build monsters—by composing small transforms into one.
One line. Start simple. Add one transform at a time until it becomes something no single tool could produce.
The seed. A euclidean melody in C minor—three notes distributed across eight slots:
Three notes in eight slots. That’s the seed. Everything grows from here.
Add speed alternation. Even cycles at normal pitch, odd cycles an octave up:
Every other cycle jumps an octave. Two-bar phrase from one character of code.
Add ply and chunk. One quarter of the pattern stutters eight times. The rest stays clean:
Chunk rotates which quarter gets ply’d. That quarter stutters eight times. The rest plays normally. Scanning texture.
Add speed modulation with sine inside the chunk. Pitch bending within the stutters:
Inside the chunked section, speed sweeps from half to double via sine. Pitch bending within the stutters. The texture becomes alive.
Add juxBy for stereo width. Left channel: original. Right channel: reversed:
The pattern splits across the stereo field. Width. Headphones make this obvious.
Add a sweeping filter, resonance, release, and reverb. The monster:
Filter sweeps slowly across eight cycles. Resonance adds bite at the cutoff. Stereo split. Chunked ply with sine-driven pitch. Alternating octaves. Reverb tail. All from three notes in eight slots.
That’s seven transforms on a single pattern. Each one is a tool you earned. Together they create something no single tool could. The euclidean seed is still there—n("0(3,8)")—but it’s been processed into a living texture.
The monster in full context. Drums, bass, pad, and the monster voice together. Kicks with variation. Claps sometimes drenched in reverb. Hats chunked and stereo-split. Cowbell with delay. 808 bass walking the progression. Pad with an offset octave. And on top of it all, the monster—euclidean seed, seven transforms deep, its melody evolving across four bars.
Count the tools: stack, every, fast, sometimes, chunk, rev, juxBy, off, add(note), ply, speed with sine modulation, voice-led chord voicings, euclidean rhythms, <> alternation, scale degrees, explicit note arrays, reverb, delay, distortion, filter sweep, pan. Nearly every tool from the entire course in one piece.
"0(3,8)" to "0(5,8)" or "0(7,16)". The euclidean pattern changes everything downstream. More hits, denser texture. Fewer hits, more space..degradeBy(0.3) to the monster voice. 30% of notes randomly drop out. The texture thins and breathes unpredictably..chunk(4, ...) with .chunk(8, ...) for finer scanning. Eight slices instead of four. The spotlight moves faster.| tool | does | looks like |
|---|---|---|
| .chunk(N, fn) | apply transform to 1/Nth of pattern, rotating each cycle | .chunk(4, fast(2)) |
| .superimpose(fn) | play original + transformed copy simultaneously | .superimpose(x => x.add(note(7)).gain(0.2)) |
| function composition | chain multiple transforms in one arrow function | x => x.fast(2).add(note(7)).gain(0.2) |
| .degrade() | randomly drop 50% of events | .degrade() |
| .degradeBy(n) | randomly drop n% of events | .degradeBy(0.3) |
| building from a seed | start minimal, add transforms one at a time | n("0(3,8)") + 7 transforms |
Next: The Set. Everything you’ve built, arranged into a performance.
Tracks that demonstrate this lesson’s concepts.
| artist | track | why |
|---|---|---|
| Mick Gordon | DOOM 2016: BFG Division (2016) | (VGM) extreme layered production, ~500M Spotify streams |
| Aphex Twin | Vordhosbn (2001) | (IDM) inhuman layered complexity |
| Venetian Snares | Hajnal (2005) | (breakcore) Bartók + amen = breakcore |
| Squarepusher | Ultravisitor (2004) | (glitch) noise + ambient + glitch + wild breaks |
| Brian Eno | Music for Airports 1/1 (1978) | (IDM) generative systems: tape loops of coprime lengths producing non-repeating music |
Building music from rules instead of note-by-note composition has a lineage running from medieval canons to Brian Eno to your strudel editor.
A canon is the simplest generative structure: a melody plays, then a copy of itself starts later. The composer writes ONE line; the system generates the second (and third, and fourth). Bach’s Musical Offering (1747) includes canons where the second voice plays the original backward (retrograde), upside down (inversion), or at half speed (augmentation). .off(), .rev(), and .slow() are these operations in code.
Eno’s Discreet Music (1975) used two melodic loops of different lengths playing through a delay system. Because the loops were different lengths, they never exactly repeated the same alignment. Music for Airports (1978) extended this with tape loops of different durations playing simultaneously. Eno called it “generative music” — music that is “ever-different and changing.” The composer sets up a system; the system produces the music.
Alex McLean created TidalCycles as part of his PhD research at Goldsmiths, University of London. His thesis (Making Programming Languages to Dance to, 2014) argued that pattern is the fundamental unit of musical thought, not the note. TidalCycles models music as functions of time, not sequences of events. Strudel (Felix Roos, 2022) ports these ideas to JavaScript, making them accessible in a browser. The .chunk(), .every(), and .superimpose() functions are pattern transformations — the same class of operations Bach used, formalized as code.
Sources: Hofstadter, Gödel, Escher, Bach (1979); Eno, “Generative Music” (1996); McLean, Making Programming Languages to Dance to (2014); Roos, “Strudel” (2022).
Brian Eno used tape loops of different lengths playing simultaneously. A piano phrase on a loop of 17 seconds. A vocal tone on a loop of 23 seconds. A synth pad on a loop of 29 seconds. Because the lengths are coprime, the combination never exactly repeats. The pattern is always familiar, never identical.
That’s generative music. You define a system—a set of rules, constraints, and processes—and the music emerges from the system running. You don’t write every note. You write the conditions under which notes appear.
The monster works the same way. n("0(3,8)") is a rule: three notes, eight slots, maximally even. .chunk(4, x => x.ply(8).speed(sine.range(0.5, 2)).gain(0.3)) is a rule: one quarter stutters with pitch modulation, rotating. .juxBy(0.6, rev) is a rule: left plays forward, right plays backward. .speed("<1 2>") is a rule: alternate octaves every cycle.
None of those rules specify exact notes at exact times. They specify processes that generate notes. The result is music that varies without randomness—deterministic but too complex to predict by ear. That’s what makes it feel alive.
Strudel is a generative instrument. Every pattern is a rule. Every transform modifies the rule. .every(), .sometimes(), .chunk(), euclidean rhythms, sine modulation—these are all rule-based. You built a generative composition. The monster is proof.