A probabilistic note engine. Two independent domains — rhythm and melody — each roll fresh (Live) or replay a shaped snapshot (Loop), with bursts, articulation, and per-cycle evolution.
The Stochastic track rolls notes from weighted distributions instead of storing fixed steps. Two independent domains run side by side — rhythm (timing, gate, articulation) and melody (pitch). Each runs in one of two modes: Live (re-rolled fresh every trigger) or Loop (a captured snapshot that gets thinned, masked, and slowly mutated). Over the roll sit per-cycle evolution knobs — patience, mutate, jump, sleep — that let the pattern drift.
Everything here is grounded in the firmware as built — defaults, ranges, enum members, key bindings, and step-grid maps come from the model, engine, and UI code.
A Stochastic track has no hand-drawn step data. Instead it:
Each domain runs in one of two modes:
The two domains' modes are set separately, so you can run Live rhythm under Loop melody, or any other split.
Rhythm and melody each carry their own source mode (Live or Loop). Setting both equal reads back as "Live" or "Loop"; setting them differently reads as "Split".
| Domain | Live | Loop |
|---|---|---|
| Rhythm | re-rolls duration/rest/slide/legato/burst every trigger | one seeded snapshot, replayed and shaped |
| Melody | re-rolls scale degree + octave every trigger | one seeded snapshot, replayed and shaped |
In Live mode the slide and legato flags on stored events are dead — the engine's playback cache owns those picks per trigger. The Loop-only shaping params (mask/tilt for both domains) are inert in Live.
A Loop domain holds its snapshot until one of these fires:
NewR / NewM is mode-aware:
Each rhythm event is a duration plus articulation. The roll draws from duration tickets, then applies rest/slide/legato probabilities and an optional burst cluster.
The duration LUT (kStochasticDurationLut) has 8 slots, each a fraction of the clock divisor. Labels shown at divisor = 1/16:
| Slot | Multiplier | Label @ 1/16 |
|---|---|---|
| 0 | ×8 | 1/2 |
| 1 | ×4 | 1/4 |
| 2 | ×3 | 3/16 |
| 3 | ×2 | 1/8 |
| 4 | ×4/3 | 1/8T |
| 5 | ×1 | 1/16 (= divisor) |
| 6 | ×2/3 | 1/16T |
| 7 | ×1/2 | 1/32 |
Labels are redrawn from the live divisor, so they track clock changes instead of lying.
noteDuration, slot 0-7, default 5 = ×1, routable) — the home slot the duration bell centres on.variation, 0-100%, default 16, routable) — spread away from the home slot. 0 locks to the home bell; 50 hands weight to the tickets; 100 explores the mirror slot.rest, 0-100%, routable) — per-event chance the event is silent.slide, 0-100%, routable) — per-event chance the note slides (glide time set by track Slide Time).legatoProb, 0-100%) — per-event chance the gate ties into the next.gateLength, 0-100%, routable) — spread of gate length around a fixed 50%-of-duration centre. 0 = exactly 50% every event; 100 = triangular spread 10..100% peaked at 50%. Floored at 10% of duration and at an absolute audible-tick minimum.Patience R (patienceRhythm, 0-100%, routable) is a boredom timer. Knob 0-99 maps to a Poisson rate; the engine rolls a Poisson CDF against how many cycles the loop has survived, and when it fires the rhythm domain regenerates with a fresh seed. Knob 100 = off. Loop-mode only.
These thin a Loop snapshot by duration rank — they don't change the roll, they sieve it at playback.
maskRhythm, 0-100%, default 100 = bypass, routable, routing name "Mask") — rank filter on duration. Below 50, long notes survive; above 50, short notes survive.tiltRhythm, 0-100%, centre 50, routable, routing name "Tilt") — blends the duration-rank axis with a per-cell salt hash. The engine recovers a signed magnitude as (knob − 50): 50 = pure salt cut, below 50 = negative rank-cut, above 50 = positive rank-cut.Both are inert in Live rhythm.
Melody rolls a scale degree and octave through a five-step pitch law: pick a degree class with a recency penalty, build an octave field, then place the pitch through a Marbles-style bell and a contour nudge.
degreeRotation, -32..+32) — rotates which degree the tickets attach to (DROT on the PITCH page).maskRotation, -32..+32) — rotates the non-excluded ticket weights among themselves (MROT on the PITCH page).marblesBias, 0-100%, default 50, routable) — centre of pitch attraction within the field.marblesSpread, 0-100%, default 50, routable) — shape: concentrated, uniform, or pulled to the edges.marblesMode, Off/On) — legacy toggle; the engine runs the distribution regardless.range, 0-100%, centre 50, routable) — field width. 50 = single octave; above 50 widens the candidate set up to 4 octaves; below 50 keeps a single octave but adds a per-slot octave-displacement chance.contour, -100..+100%, routable) — directional drift. The roll probabilistically swaps toward a candidate that moves up (positive) or down (negative).complexity, 0-100%, default 50, routable) — how aggressively a repeated degree class is rejected and re-rolled.These sieve a Loop snapshot by pitch centrality (how tonal the degree is — root, fifth, thirds rank high).
maskMelody, 0-100%, default 100 = bypass) — passes pitches whose centrality clears the threshold (high-centrality survives).tiltMelody, 0-100%, default 0) — inverts the filter: passes low-centrality pitches. The two act as an OR union.Both inert in Live melody.
Repeat (repeatProb, 0-100%) — per-trigger chance to freeze and replay the previous event verbatim (note, octave, duration, articulation). 100% holds on the last event; mid values cluster durations like a human player. Works in both modes. No routing target.
Patience M (patienceMelody, 0-100%) — the melody domain's own boredom timer, same Poisson-CDF behavior, independent of Patience R. Knob 100 = off. No routing target. When it fires it also resets the octave-jump register.
A burst replaces one event with a short cluster of notes packed into that event's duration. The cluster is rolled per event.
burst, 0-100%, default 0, routable) — per-event chance a cluster fires.burstCount, 0-100%, routable) — picks the number of cells (2..8) by triangular weight. Stored as tails = total − 1.burstRate, 0-100%, routable) — picks the spacing denominator (2..6) by triangular weight.| Burst Hold | Pitch axis | Timing axis |
|---|---|---|
| Hold/Fit | cells share the anchor's pitch | pack into one duration on the BurstRate curve |
| Hold/Over (default) | cells share the anchor's pitch | uniform spacing, may overflow the duration |
| Roll/Fit | each cell rolls its own pitch | pack into one duration |
| Roll/Over | each cell rolls its own pitch | uniform spacing, may overflow |
kMinBurstParentTicks (96 ticks) the parent event is too short to host a cluster and burst count auto-clips to 0. The Burst readout appends * when the current Note Duration + divisor combo can't produce an audible burst, so you can see why the knob is inert.At each cycle boundary — a natural pattern wrap or a preempted reset-measure — four hooks fire in lockstep.
mutate, 0-100%, routable) — chance to destructively re-roll one random step inside the window. Picks rhythm or melody (or both if both are Loop+valid), then rebuilds the mask ranks.jump, 0-100%, routable) — chance of a ±1 octave walk, reflected at ±2 octaves. Applied as a playback-time register offset; stored events are never touched.sleep, 0-100%, routable) — sets a skip counter: (knob × 4 + 5) / 10 steps are silently skipped before play resumes.size, 2..CONFIG_STEP_COUNT, default 32) — steps in the pattern. Last is collapsed into Size (last = size − 1).first, 0..size−1) — the start step.rotate, -64..+64, routable) — rotates the read position within the window.divisor, default 12) — base tick spacing.clockMultiplier, 50-150%, default 1.00x, routable) — fine clock scaling.resetMeasure, off / 1..128 bars, default off) — snaps the read position back to First on the bar boundary.The effective tick spacing is the divisor scaled by the PPQN ratio (CONFIG_PPQN / CONFIG_SEQUENCE_PPQN = 4) and divided by the clock multiplier.
Feel (feel, 0-100%, centre 50, default 50, routable) bends the cycle toward a different beat count. The detent 45..55 is off (no scaling). Below 50 lerps the cycle toward 3 beats; above 50 toward 5 beats. Computed per trigger so routed Feel takes effect immediately; scaling clamps to ¼×..4×.
Page+S0 opens the Stochastic edit page. F5 (NEXT) cycles four layers: LIVE → LOOP → PITCH → DURATION → LIVE. The first two are the hands-on knob-grid pages (each step holds one shaping param); the last two edit the degree and duration tickets.
On every layer, hold a step (or several) and turn the encoder to edit. Shift multiplies the encoder delta by 10. A single held step shows its full name + value at the top; more than one held shows "MANY SELECTED". The context menu (long-press) offers INIT / EVEN / RAND / BPITCH — behavior is per-page.
The performance knob grid. Footer F-keys: rhythm-mode toggle, melody-mode toggle, NewR, NewM, NEXT.
LiveR / LiveM / NewR / NewM / NEXT.LoopR/LiveR — toggle rhythm mode Live↔Loop.LoopM/LiveM — toggle melody mode Live↔Loop.NewR (Shift UndoR) — capture-or-renew rhythm (mode-aware); Shift undoes last renew.NewM (Shift UndoM) — capture-or-renew melody; Shift undoes last renew.NEXT — next page.| Step | Param | Step | Param |
|---|---|---|---|
| S1 | Note Duration | S9 | Complexity |
| S2 | Variation | S10 | Contour |
| S3 | Rest | S11 | Bias |
| S4 | Feel | S12 | Spread |
| S5 | Gate Length | S13 | Range |
| S6 | Legato | S14 | Slide |
| S7 | Burst | S15 | Repeat |
| S8 | Burst Count | S16 | Burst Rate |
LEDs: rhythm + articulation + repeat (S1-S6, S15) red; pitch shape (S9-S14) green; burst (S7-S8, S16) orange; a held step adds the opposite colour (amber).
Context menu: INIT resets all 16 knobs to defaults; RAND randomizes them (or the held selection); BPITCH cycles Burst Hold (Hold/Over → Roll/Over → Hold/Fit → Roll/Fit). EVEN is not used on LIVE. Quick-edit: Page + S16 fires RAND directly.
The Loop-shaping and evolution grid. Footer F-keys mirror LIVE (rhythm/melody toggles, NewR, NewM, NEXT).
first..last play window, the bright slot is currently audible, bar height encodes pitch. Two patience meters fill below; side bars are Mask/Tilt per domain. Footer reads LoopR / LoopM / NewR / NewM / NEXT in Loop mode.| Step | Param | Step | Param |
|---|---|---|---|
| S1 | Patience R | S9 | First |
| S2 | Patience M | S10 | Size |
| S3 | Mutate | S11 | Rotate |
| S4 | Jump | S15 | Mask R |
| S5 | Sleep | S16 | Tilt R |
| S7 | Mask M | ||
| S8 | Tilt M |
(S6, S12-S14 unbound.) First and Size trigger an engine window-sync; Rotate does not.
LEDs: patience + walk (S1-S5) red; Mask/Tilt Melody (S7-S8), window (S9-S11), Mask/Tilt Rhythm (S15-S16) green; held step adds amber. Context menu: INIT resets patience/mutate/jump/sleep/window/masks/tilts (selection-aware). EVEN and RAND are not used on LOOP.
Scale-degree tickets. Header SCALE TICKETS. Each step S1-S16 selects a degree (degree index = bank × 16 + step); the encoder edits that degree's ticket (or all held degrees). A single held degree reads DEG n: <weight or EXCL>.
DROT / MROT.LoopM/LiveM — toggle melody mode.NewM — capture/renew melody.DROT — focus Degree Rotation for the encoder (highlights when active).MROT — focus Mask Rotation for the encoder (highlights when active).NEXT — next page.LEDs: in-scale degrees green; the currently-playing degree red; a selected degree amber. Quick-edit: Page + S14 = INIT (all degrees uniform), Page + S15 = EVEN (all to selected degree's value), Page + S16 = RAND.
Duration-slot tickets. Header DURATION TICKETS. Steps S1-S8 select a duration slot; the encoder edits that slot's ticket weight. The label shows the divisor-relative duration name and the weight.
REST % sits top-right.LoopR/LiveR — toggle rhythm mode.NewR — capture/renew rhythm.RST — focus Rest probability for the encoder (highlights when active).NEXT — next page.LEDs: the 8 slots green; the playing slot red; a selected slot amber. Quick-edit: Page + S14 = INIT (all slots 50, rest 0), Page + S15 = EVEN, Page + S16 = RAND.
The Stochastic config list, in display order:
(Divisor, Clock Mult, Reset Measure, Scale, Root Note, Scale Rotate are per-sequence values shown here; the rest are track-wide.)
The performance list, in display order (grouped Playback / Pitch / Rhythm / Burst / Sieve / Window / Evolution): Rhythm (mode), Melody (mode), Refresh, Complexity, Contour, Repeat, Bias, Spread, MaskM, TiltM, Range, Note Duration, Variation, Rest, Gate Length, Slide Prob, Legato, Burst, Burst Count, Burst Rate, Burst Hold, MaskR, TiltR, Size, First, Rotate, Sleep, Patience R, Patience M, Mutate, Jump.
Refresh ("Exec") invalidates both Loop domains so they regenerate on the next trigger.
The Stochastic routing targets — all per-sequence:
Mask (maskRhythm), Gate Length, Tilt (tiltRhythm), Feel, BurstComplexity, Contour, Note Duration, Variation, Rest, SlideSleep, Patience R (patienceRhythm), Mutate, Jump, RangeBias (marblesBias), Spread (marblesSpread), Burst Count, Burst RateTrack-scope params route through the shared targets: Octave, Transpose, Slide Time, Clock Mult, Scale, Root Note, Rotate.
Not routable: Patience M, Repeat, Legato, Mask/Tilt Melody, Degree/Mask Rotation, the tickets, Size, First, the mode toggles.