# Chapter 4 · Your First Generators: Euclidean and Spread Rhythms In [Chapter 3](03-notes-beats-durations) you placed every note by hand; here you hand the rhythm-making over to *generators* — single numbers that bloom into whole patterns — and learn to layer, ratchet, swing, and chain them. ```{testsetup} ch4 # Hidden per-chapter setup: the imports the first example shows in full, so later # blocks can build patterns without repeating the boilerplate each time. import subsequence import subsequence.constants.instruments.gm_drums as gm_drums composition = subsequence.Composition(bpm=120) ``` So far a rhythm has been a list you typed out: `[0, 4, 8, 12]` for the kick, `range(16)` for the hats. That's perfect when you know exactly what you want. But often you don't want *exact steps* — you want a *feel*: "spread five hits evenly across the bar," "make the hats busier as the section builds." A **generator** lets you say that with one number. You give it a count and it works out the steps, distributing them as evenly as the maths allows. The same idea — describe the density, let Subsequence fill the grid — runs through this whole chapter. (sec-euclidean)= ## 4.1 Euclidean rhythms from one number The **Euclidean rhythm** is the workhorse generator. You give it a number of **pulses** — how many hits to place — and it spreads them as evenly as possible across the bar's grid. That single idea sits under a startling share of the world's drum patterns: spread a handful of hits as evenly as a grid allows and you keep landing on rhythms that traditions everywhere already use — West African bell lines, the Cuban *tresillo*, the four-on-the-floor kick. They are all "N hits, spread evenly." ```{seealso} **Origins.** Euclid wrote this algorithm down around 300 BC; in 2003 it was repurposed to evenly space the pulses of a neutron accelerator, and in 2005 Godfried Toussaint showed the same even-spacing patterns underlie traditional rhythms the world over. The full story — and the pedigree of every other generator — is in [Appendix F](appendix-f-field-guide). ``` The verb is `p.euclidean`: ```python p.euclidean(pitch, pulses, velocity=..., duration=...) ``` - **`pitch`** — the drum (a name like `"kick_1"`) or a MIDI number, exactly as in `hit_steps`. - **`pulses`** — how many hits to place across the bar. This is the one number that does the work. - **`velocity`** — how hard, the same as everywhere: a single number, or a `(low, high)` tuple for a per-hit random draw ([§1.5](01-step-grid)). - **`duration`** — how long each hit rings, in beats (default a tight `0.1`). The hits land on the pattern's grid — sixteen sixteenth-note steps in a 4-beat bar, just like `hit_steps`. So `pulses=4` puts a hit every four steps, which is exactly the four-on-the-floor kick you've been writing by hand: ```{testcode} ch4 import subsequence import subsequence.constants.instruments.gm_drums as gm_drums composition = subsequence.Composition(bpm=120) @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=4, velocity=100) # = [0, 4, 8, 12] — four on the floor composition.render(bars=4, filename="euclid.mid") ``` `euclidean("kick_1", pulses=4)` produces hits on steps `0, 4, 8, 12` — the very list you typed in Chapter 1, now derived from a single `4`. The pay-off is that changing the *feel* is now changing *one number*. Ask for five pulses instead of four and Subsequence can't space them perfectly evenly (five doesn't divide sixteen), so it does the next-best thing — the famous slightly-lopsided spread that underlies a thousand grooves: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=5, velocity=100) # lands on steps 0, 3, 6, 9, 12 composition.render(bars=4, filename="euclid.mid") ``` A few pulse counts worth knowing by ear, on the standard 16-step bar: ```{list-table} Euclidean rhythms in a 16-step bar :header-rows: 1 :widths: 16 34 50 * - `pulses` - Lands on steps - Sounds like * - `3` - `0, 5, 10` - three even-ish hits straddling the bar — a loping 3-against-16 cross-rhythm * - `4` - `0, 4, 8, 12` - four on the floor * - `5` - `0, 3, 6, 9, 12` - five driving hits, the lopsided spread under countless grooves * - `7` - `0, 2, 4, 7, 9, 11, 14` - a busy, rolling line good for shakers and hats ``` ```{note} **Why "Euclidean"?** The spread is computed by the same algorithm Euclid used to find a greatest common divisor — the most even way to interleave N hits among M slots. You don't need the maths to use it; the musical rule of thumb is all you need: **`pulses` is how many, and the more evenly they *can't* divide the bar, the more interesting the syncopation.** Even divisors (2, 4, 8) give plain rhythms; odd counts (3, 5, 7) give the syncopated ones. The exact spread also depends on the grid `euclidean` works over — here the pattern's sixteen steps — so `pulses=3` is the 3-against-16 spread `[0, 5, 10]`, not the eight-step *tresillo* `[0, 3, 6]`. ``` Because it places notes the same way `hit_steps` does, everything you already know still applies — humanise with a velocity tuple, stack several `euclidean` calls to layer voices, and reach for plain `hit_steps` wherever a part needs an *exact* beat the even spread wouldn't choose. Here a Euclidean kick drives a busy, humanised Euclidean hat, while the snare keeps the backbeat by hand — Euclidean's even two-pulse spread would land on beats 1 and 3, not the 2 and 4 a backbeat wants: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=4, velocity=105) # steady floor p.hit_steps("snare_1", [4, 12], velocity=95) # backbeat, placed by hand p.euclidean("hi_hat_closed", pulses=11, velocity=(55, 80)) # busy, humanised composition.render(bars=4, filename="euclid.mid") ``` ```{tip} The most musical move with Euclidean rhythms is to make the pulse count *react* to where you are in the song, using `p.cycle` or `p.bar_cycle` from [Chapter 2](02-rebuild-loop). `pulses = 4 + p.bar_cycle(4).last * 4` plays four hats for three bars and eight on the turnaround — a build-up written in one line. ``` **Rotating the rhythm: the necklace move.** Picture a Euclidean rhythm as beads on a necklace — the same pattern can begin at a different bead. To rotate one, reach past the builder to its raw on/off list: `subsequence.sequence_utils.generate_euclidean_sequence(steps, pulses)` returns the `1`/`0` mask, and **`displace(mask, amount)`** phase-shifts it, wrapping (positive = later, negative = earlier): ```{doctest} ch4 >>> import subsequence.sequence_utils as utils >>> kick = utils.generate_euclidean_sequence(8, 3) # 3 pulses over 8 steps >>> kick [1, 0, 0, 1, 0, 0, 1, 0] >>> utils.displace(kick, 1) # the whole necklace, one step later [0, 1, 0, 0, 1, 0, 0, 1] ``` Rotating a Euclidean necklace against the downbeat is how its *clave*-like variants appear, and phasing two copies a step apart is the classic Steve-Reich move. `displace` only **reorders** the values you give it — distinct from `p.rotate` ([§12.9](12-deep-generative)), which shifts notes already placed on the grid. ```{admonition} Reference :class: seealso {py:meth}`~subsequence.pattern_algorithmic.PatternAlgorithmicMixin.euclidean`, {py:func}`~subsequence.sequence_utils.generate_euclidean_sequence`, {py:func}`~subsequence.sequence_utils.displace` ``` (sec-bresenham)= ## 4.2 Bresenham and weighted spread (`bresenham_poly`) Euclidean is not the only way to spread N hits evenly. `p.bresenham` is a close cousin — same call shape, same idea of distributing `pulses` across the grid — but it uses the **Bresenham line algorithm** (the one screens use to draw a straight diagonal as stair-steps), which gives a subtly different, often *end-weighted* distribution. Where Euclidean tends to put a pulse on the downbeat, Bresenham tends to push the run toward the end of the bar: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.bresenham("hi_hat_closed", pulses=5, velocity=(55, 80)) # lands on 3, 6, 9, 12, 15 composition.render(bars=4, filename="bres.mid") ``` Five Bresenham pulses land on steps `3, 6, 9, 12, 15` — the same even spacing as the Euclidean five, but shifted so the line *ends* on the last sixteenth instead of *starting* on the downbeat. That trailing-edge feel makes Bresenham a natural choice for a part that should lead *into* the next bar — a hat or shaker that pushes the groove forward — while Euclidean, anchored on beat one, suits the parts that hold it down. ```{list-table} Same five pulses, two generators :header-rows: 1 :widths: 24 38 38 * - Generator - Lands on steps - Feel * - `p.euclidean(..., pulses=5)` - `0, 3, 6, 9, 12` - anchored on the downbeat — holds the groove * - `p.bresenham(..., pulses=5)` - `3, 6, 9, 12, 15` - leans on the last step — pushes into the next bar ``` ### Weighted spread with `bresenham_poly` The real power tool here is **`p.bresenham_poly`**. Instead of one voice and a pulse count, you hand it *several* voices at once, each with a **density weight**, and it shares the grid out between them — assigning every step to exactly **one** voice, so the voices **never collide**. The result is an *interlocking* texture, the kind of woven hand-percussion groove that's fiddly to place by hand: ```python p.bresenham_poly(parts={pitch: weight, ...}, velocity=...) ``` - **`parts`** — a dictionary mapping each drum to a **density weight**. Higher weight means more hits. A weight of `0.5` aims for a hit roughly every other step; `0.25`, every fourth. - **`velocity`** — either one number for all voices, or a dictionary giving each voice its own velocity (a voice missing from the dict falls back to the default). ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.bresenham_poly( parts={"hi_hat_closed": 0.5, "shaker": 0.25, "tambourine": 0.125}, velocity={"hi_hat_closed": 70, "shaker": 55, "tambourine": 45}, ) composition.render(bars=4, filename="poly.mid") ``` The three voices share the sixteen steps with no overlaps: the hi-hat takes about half, the shaker a quarter, the tambourine an eighth — a single, dovetailed groove out of one call. If the weights add up to **less than 1.0**, the leftover steps become rests (silence), so you can leave the texture sparse on purpose. ```{important} **`bresenham_poly` is for the *background weave*, not the anchors.** Because it re-shares *every* step whenever the weights change, a voice's hits shift position from bar to bar if you ramp its density — wonderful for evolving hats and shakers, distracting for a signature clap or cowbell. The reliable recipe: lay the interlocking texture with `bresenham_poly`, then place the parts that must stay put — kick, snare — with plain `hit_steps` or a fixed-pulse `euclidean` on top. ``` ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): # Evolving background weave — these voices may shift bar to bar. p.bresenham_poly( parts={"hi_hat_closed": 0.5, "shaker": 0.2}, velocity={"hi_hat_closed": 65, "shaker": 50}, ) # Fixed anchors on top — placed by hand so they never move. p.hit_steps("kick_1", [0, 8], velocity=110) p.hit_steps("snare_1", [4, 12], velocity=100) composition.render(bars=4, filename="poly.mid") ``` ```{admonition} Reference :class: seealso {py:meth}`~subsequence.pattern_algorithmic.PatternAlgorithmicMixin.bresenham`, {py:meth}`~subsequence.pattern_algorithmic.PatternAlgorithmicMixin.bresenham_poly` ``` (sec-ratchet)= ## 4.3 Ratchets and rolls A **ratchet** (or **roll**, or **drum buzz**) is the move where a single hit becomes a rapid burst — `tk-tk` instead of `tk`. In Subsequence it's a *transform*: you place your notes first, then call **`p.ratchet`** to subdivide them into bursts. Each note is replaced by `subdivisions` evenly-spaced sub-hits inside its own time slot. ```python p.ratchet(subdivisions, pitch=..., velocity_start=..., velocity_end=...) ``` - **`subdivisions`** — how many sub-hits each note becomes (default `2`). - **`pitch`** — restrict the ratchet to one drum; leave it off and *every* note is ratcheted (handy on a melodic line, dangerous on a full kit). - **`velocity_start` / `velocity_end`** — multipliers on the original velocity across the burst, so you can shape a crescendo or a decay. Because it works on notes *already placed*, the order is: generate the rhythm, then ratchet. Here a Euclidean hat line gets every hit turned into a triplet flutter — note the chaining, which the next section unpacks: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("hi_hat_closed", pulses=8, velocity=70).ratchet(3, pitch="hi_hat_closed") composition.render(bars=4, filename="ratchet.mid") ``` The classic use is a **crescendo snare roll into a turnaround**. Place one snare hit near the end of a four-bar phrase, then ratchet it into four rising sub-hits so it swells into the downbeat of the next phrase. `velocity_start=0.3, velocity_end=1.0` makes it grow; the `shape="ease_in"` curve makes the growth accelerate: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=4, velocity=100) p.hit_steps("snare_1", [4, 12], velocity=95) # backbeat, by hand p.hit_steps("hi_hat_closed", range(16), velocity=(55, 75)) # On the last bar of every four, swell a roll into the next phrase. if p.bar_cycle(4).last: p.hit_steps("snare_1", [14], velocity=100, duration=0.5) p.ratchet(4, pitch="snare_1", velocity_start=0.3, velocity_end=1.0, shape="ease_in") composition.render(bars=8, filename="roll.mid") ``` ```{warning} **Ratchet only what you mean to.** Called bare — `p.ratchet(2)` — it subdivides *every* note in the pattern, kick and snare and hats alike, which usually turns a groove to mush. On a drum kit, almost always pass `pitch=` to target one voice. On a single-voice melodic or bass pattern, the bare form is exactly right. And place `ratchet` *after* your notes but *before* `swing` (next), so the swing still nudges the parent hit. ``` ```{admonition} Reference :class: seealso {py:meth}`~subsequence.pattern_algorithmic.PatternAlgorithmicMixin.ratchet` ``` (sec-swing)= ## 4.4 Swing and timing feel (not pitch) Everything so far has placed notes on the exact grid. **Swing** is what takes them *off* it — by a hair — to give a stiff pattern the pushed, human shuffle of a real drummer. It's the first **timing** transform we meet, and the distinction it draws is one to hold onto for the rest of the guide: ```{important} **Swing is timing, not pitch.** It nudges *when* notes play — sliding every other grid position a little late — and never touches *which* notes play. This is the opposite end of the instrument from `snap_to_scale` (Chapter 5), which changes a note's **pitch** and never its timing. Two different dials: `swing` for feel, `snap_to_scale` for notes. Keep them straight and you'll never reach for the wrong one. ``` The verb is `p.swing`: ```python p.swing(percent, grid=0.25) ``` - **`percent`** — the swing amount. **`50` is dead straight** (no swing); `57` is a gentle shuffle (the Ableton default); `67` is hard triplet swing. The useful range is roughly 50–75. - **`grid`** — which notes get pushed, as a beat value. `0.25` swings sixteenth notes (the common choice); `0.5` swings eighths. Like the articulation verbs in Chapter 3, swing is a *post-placement* transform: write the line straight, then swing the whole thing. Here a plain sixteenth-note hat line gets a moderate shuffle: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=4, velocity=100) p.hit_steps("snare_1", [4, 12], velocity=95) # backbeat, by hand p.hit_steps("hi_hat_closed", range(16), velocity=(55, 80)) p.swing(57) # gentle 16th-note shuffle over the whole bar composition.render(bars=4, filename="swing.mid") ``` Render that straight (delete the `p.swing` line) and then with it, and the difference is unmistakable: the off-grid hats lean back, and the loop stops sounding quantised. Two refinements you'll reach for: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.hit_steps("hi_hat_closed", range(16), velocity=70) p.swing(67, grid=0.25) # hard, triplet-ish shuffle on the sixteenths composition.render(bars=2, filename="swing.mid") ``` ```{tip} Swing is a *whole-pattern* feel, so apply it once, last, after every note is placed — including after `ratchet`, so the rolls ride along with the swing. If only some patterns should swing (say the hats but not the kick), put `p.swing` in each pattern you want to feel it, and leave it out of the ones that should stay locked to the grid. ``` ```{admonition} Reference :class: seealso {py:meth}`~subsequence.pattern_builder.PatternBuilder.swing` ``` (sec-chaining)= ## 4.5 "Learn one verb, predict the rest"; builder chaining You've now met a dozen `p.` verbs across four chapters, and they all share a shape on purpose. Once you've internalised it, a method you've never used before behaves the way you'd guess — which is the whole design goal. **The placement and transform verbs return the builder.** Look back at any of the signatures: `p.euclidean(...) -> PatternBuilder`, `p.ratchet(...) -> PatternBuilder`, `p.swing(...) -> PatternBuilder`. Each one does its job *and* hands `p` back to you. That means you can **chain** them — write one verb after another on the same line, left to right, in the order they apply: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): # Generate, then ratchet, then swing — read left to right as a sentence. p.euclidean("hi_hat_closed", pulses=8, velocity=70).ratchet(2, pitch="hi_hat_closed").swing(57) composition.render(bars=4, filename="chain.mid") ``` That one line reads as a recipe: *place eight even hats, turn each into a double, then shuffle the lot.* Chaining is purely a convenience — it does exactly the same thing as writing the three calls on separate lines, and you should break the chain across lines the moment it stops being readable: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("hi_hat_closed", pulses=8, velocity=70) p.ratchet(2, pitch="hi_hat_closed") p.swing(57) composition.render(bars=4, filename="chain.mid") ``` The deeper point is the **shared shape** of the verbs. Once you know it, you can predict an unfamiliar one: ```{list-table} The common shape of a `p.` verb :header-rows: 1 :widths: 30 70 * - Every verb… - …so when you meet a new one * - leads with its **most musical argument** (a placement verb's `pitch`, a transform's amount) - you can guess the argument order before reading the docs * - accepts `velocity=` as a number **or** a `(low, high)` tuple - per-note humanising works the same everywhere it's offered * - **places** notes (`euclidean`, `hit_steps`) **or transforms** placed notes (`ratchet`, `swing`, `legato`) - you know whether to call it first (placement) or last (transform) * - **returns the builder**, so it chains - you can string several together, or not — your call ``` ```{note} **Placement first, transforms last.** This is the one ordering rule that makes the chain read correctly. *Placement* verbs (`euclidean`, `bresenham`, `hit_steps`, `note`, `sequence`) put notes down; *transform* verbs (`ratchet`, `swing`, `legato`, `detached`, `velocity_shape`) reshape whatever is already there. Put the placements first and the transforms after, and a chain does what it reads like it does. ``` ```{seealso} This "predict the rest" idea is the tip of a larger contract the whole API keeps — the front the chord verbs share, what `(low, high)` and `seed=` always mean, which methods chain and which return data. It's gathered in one place in [Appendix G: Learn One Verb, Predict the Rest](appendix-g-api-contract). ``` (sec-repeatability)= ## 4.6 Repeatability (`seed=` / `rng=`) The moment a pattern uses randomness — a `(low, high)` velocity tuple, a probability that thins hits, a generator that makes a random choice — you face a question: should it sound *the same* every time you run it, or *fresh* every time? Both are useful, and Subsequence lets you choose, at three levels of scope. A generator can make random choices in two distinct places, and it pays to know which is which. The first is the **velocity tuple**: `velocity=(55, 80)` is *one independent random draw per note* ([§1.5](01-step-grid)) — sixteen hats give sixteen different velocities. The second is anything the *generator itself* rolls — most commonly **`probability`**, which thins a rhythm by giving each pulse a chance of *not* playing (`probability=0.5` drops about half). A 16-pulse Euclidean line at `probability=0.7` keeps a random-but-even ~70% of its hits, fresh each bar. **The whole-piece seed.** Pass `seed=` when you build the `Composition` and the *entire* piece becomes reproducible — every random draw in every pattern (velocity tuples *and* generator choices alike) unfolds the same way each run, so the take you liked is the take you get back: ```{testcode} ch4 import subsequence import subsequence.constants.instruments.gm_drums as gm_drums composition = subsequence.Composition(bpm=120, seed=42) # whole piece is now repeatable @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): p.euclidean("kick_1", pulses=4, velocity=100) p.hit_steps("hi_hat_closed", range(16), velocity=(55, 80)) # same 16 values every run composition.render(bars=4, filename="seeded.mid") ``` **The per-generator seed.** Sometimes you want *one* generator's own choices pinned while the rest of the piece stays free. Every generator takes its own **`seed=`** — a plain integer that fixes that call's random decisions, regardless of the composition's seed. Here the busy hat line is thinned to a *fixed* pattern of hits every run, while the shaker beside it is left free to thin differently each time: ```{testcode} ch4 @composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP) def drums(p): # Thinned to the same hits every run — seed=7 pins this generator's choices. p.euclidean("hi_hat_closed", pulses=16, velocity=70, probability=0.6, seed=7) # …while this shaker is left free, thinning differently each run. p.euclidean("shaker", pulses=16, velocity=55, probability=0.4) composition.render(bars=4, filename="seeded.mid") ``` ```{note} **A per-generator `seed=` pins the generator's *own* dice — `probability` thinning and the like — not the `(low, high)` velocity draw.** Velocity tuples always draw from the pattern's shared generator, so to make *those* repeatable you seed the `Composition` (above). In practice the whole-piece `seed=` is the one you'll reach for nine times out of ten; a per-generator `seed=` is for pinning one part's *structure* (which hits survive a thinning) while the rest stays loose. ``` **The advanced form: `rng=`.** For full control you can hand a generator its own `random.Random` object via **`rng=`**. This is the power-user escape hatch — it lets several calls *share* one stream, or lets you advance the stream yourself. You'll rarely need it as a beginner; just know the precedence when more than one is in play: ```{important} **Precedence: `rng=` beats `seed=` beats the pattern's own generator.** If you pass `rng=`, it wins (and Subsequence warns you if you passed `seed=` too — pass only one). If you pass `seed=` alone, that call uses a fresh generator fixed to that number. If you pass neither, the call draws from the pattern's own generator, which is reproducible whenever the *composition* was given a `seed=`. So: `rng` > `seed` > composition seed. Reach for the composition `seed=` to pin a whole piece, a per-generator `seed=` to pin one part, and `rng=` only when you genuinely need to share or steer the stream. ``` Two more things worth knowing. Patterns can already vary by `p.cycle` ([Chapter 2](02-rebuild-loop)), and that and the seed are independent: a seeded piece still evolves bar to bar — it just evolves *the same way* every run. And the same `seed=`/`rng=` controls appear on *every* generator in the library, not only the ones in this chapter — another payoff of the shared verb shape from [§4.5](#sec-chaining). ```{tip} The everyday workflow: compose with no seed at all, hitting re-run until a variation delights you; then drop a `seed=` on the `Composition` to *lock* that variation in place. We return to this — seeds, locks, and freezing a take — as a production workflow in a later chapter; here you have the two knobs that matter, the whole-piece seed and the per-generator one. ``` --- You can now grow a whole groove from a handful of density numbers — Euclidean and Bresenham spreads, interlocking `bresenham_poly` voices, ratcheted rolls, and a swing feel — chain the verbs fluently, and make any of it repeatable on demand. In [Chapter 5](05-pitch-and-scales) we turn the same generative thinking on **pitch**: working in scale degrees and keys, and snapping notes to a scale — the pitch-side counterpart to the timing tools you just learned.