Summary
Give each part its own clock divide and timing offset so the four lines don't all march on the same 16th grid. Today every part advances together at STEPS_PER_BAR = 16 (js/generator.js), driven globally by js/scheduler.js. Let the Pad run at 1/1, the bass at 1/4, the arp at 1/8-triplet, each optionally shifted by a 16th — and the lines drift into evolving, non-repeating polyrhythm.
Why it fits
Phasing and cross-rhythm are the most modular-native textures there are — exactly what you want under a long-evolving patch. Because the parts are already strictly monophonic and independently generated, staggering their rates is cheap musically and gives a lot of motion for very little UI.
Proposed scope
Per-part rate + offset (js/generator.js, js/scheduler.js)
- Add per-part
clockDiv (e.g. 1/1, 1/2, 1/4, 1/8, 1/16, plus triplet 1/4T, 1/8T) and offset (0, 1/16, 1/8, 3/16) to each entry in state.parts.
- The scheduler already advances time incrementally; have each part decide whether this global step is one of its trigger steps given its divide, and apply its offset when stamping the note time.
- Keep mono enforcement per part (drop coincident starts, clip before the next note / bar line) exactly as it works today.
The phasing trick (length ≠ length)
- Allow a part's note-source length and its rhythmic length to differ, so the note pool rotates against the pulse and never lines up the same way twice. (Dovetails with the step/rhythm editor idea, but works on the generated streams too.)
UI (js/app.js)
- Two selects in each part's ⚙ panel: Clock divide and Offset. Show the resulting feel (e.g. a "notes : beats" readout) so the polyrhythm is legible.
Where
js/generator.js (per-part step gating + offset), js/scheduler.js (time stamping), js/app.js (⚙ controls + state).
Done when
Open questions
- Should swing apply per divide, or stay global for now?
- Cap on combined divides to avoid pathological density at high tempo?
Summary
Give each part its own clock divide and timing offset so the four lines don't all march on the same 16th grid. Today every part advances together at
STEPS_PER_BAR = 16(js/generator.js), driven globally byjs/scheduler.js. Let the Pad run at 1/1, the bass at 1/4, the arp at 1/8-triplet, each optionally shifted by a 16th — and the lines drift into evolving, non-repeating polyrhythm.Why it fits
Phasing and cross-rhythm are the most modular-native textures there are — exactly what you want under a long-evolving patch. Because the parts are already strictly monophonic and independently generated, staggering their rates is cheap musically and gives a lot of motion for very little UI.
Proposed scope
Per-part rate + offset (
js/generator.js,js/scheduler.js)clockDiv(e.g. 1/1, 1/2, 1/4, 1/8, 1/16, plus triplet 1/4T, 1/8T) andoffset(0, 1/16, 1/8, 3/16) to each entry instate.parts.The phasing trick (length ≠ length)
UI (
js/app.js)Where
js/generator.js(per-part step gating + offset),js/scheduler.js(time stamping),js/app.js(⚙ controls + state).Done when
Open questions