Composing on the grid
You have a grid, a key, a clock. Time to fill it with notes. The Sequencer's edit surface has two tools (Paint and Select), per-step velocity, per-step hold (gate length), a Chord Palette, and the Suggest Progression flow. Plus undo / redo so you can experiment freely.
Two tools, one toggle
Flip between Paint and Select with the footer toggle (or the keyboard shortcut shown in the tooltip).
Paint
- Click a cell → add a note at that pitch + step.
- Click a filled cell → remove it.
- Vertical drag while painting → set velocity. The cell tints based on velocity (faint = low, saturated = high).
- Cmd/Ctrl-drag horizontally → smear. Copies the source cell into every REST cell across the drag range. Already-filled cells are left alone (smear never overwrites — clear explicitly first if needed).
For AI & automation · MCP
sequencer.step.set { step, note? | chord? | rest: true | clear: true, velocity?, track_id?, instance_id? } for a single cell. sequencer.step.smear { from, to, track_id? } for the smear gesture. sequencer.step.duplicate { step, track_id? } for "same as previous step".
Select
- Click a note → select it.
- Shift-click → extend the selection.
- Arrow keys — move selection up / down (±1 semitone), Shift+Up / Down (± octave).
- Escape — clear selection.
The Suggest-Progression flow auto-selects the inserted notes so the next gesture (e.g. arrow-down) shifts them all together. Same for chord-palette drops.
For AI & automation · MCP
sequencer.notes.transpose { semitones: -12..12, steps?: [indices], track_id? }. Pass steps to limit the move to specific step indices (e.g. just the steps a progression filled); omit to transpose every note in the track. The move is clamped to the C0..C8 grid range so chords keep their shape and just stop at the edge instead of collapsing voices.
Per-step velocity
Every step carries a velocity 1..127, defaulting to 100. Set via:
- Paint-drag: vertical drag while painting.
- Right-click → Velocity preset (Quiet / Medium / Loud / Accent / Custom).
- MCP:
sequencer.step.set { velocity }orsequencer.step.gate.set(see below) for already-placed steps.
Velocity rides through the dispatch path to the receiver's [midi:keyon] callback, so a velocity-sensitive Faust DSP (gain = hslider("gain[midi:keyon]", 0.5, 0, 1, 0.01)) responds correctly.
Per-step hold (gate length)
Each painted step has an optional hold multiplier — how long the note rings relative to the step duration:
| Hold | Behaviour |
|---|---|
0.25 | Staccato — very short. |
1.0 | Default — release at the next step boundary. |
2.0 | Tied — rings into the next step. |
4.0 | Held one beat (4 × 16th). |
16.0 | Held a full bar. |
> pattern length | Legato across the wrap. Same pitch on the next loop extends the held note instead of retriggering. |
Set via right-click → Hold preset (Staccato / Default / Tied / Beat / Half-bar / Whole bar / Custom) or:
For AI & automation · MCP
sequencer.step.gate.set { step, hold, track_id? } for an already-placed step. To author hold inline during step creation, use sequencer.step.set { note, hold }.
The per-step length / hold flows through the seq-clock to the dispatch path so the gate-off event lands at the right sample.
Per-step length (pattern-level)
Distinct from hold: the step's WALL-CLOCK duration. Defaults to 16th-note (one tick of the master clock). Can be overridden per-step, but the override is pattern-level — every track's column-N advances on the SAME wall-clock, by construction of the single seq-clock.
For AI & automation · MCP
sequencer.step.length.set { step, ms: 250 } to override step step's duration; ms: null reverts to default. sequencer.step.length.clear-all resets every step's length override in one shot.
Useful for: triplet feels (set every third step to a longer ms), swing (alternate ms on odd / even steps), polymeter trickery.
The diatonic Chord Palette
To the right of the key/scale picker, the footer shows a row of chord buttons — the diatonic chords for the current key + scale. For A minor: i (Am), ii° (Bdim), III (C), iv (Dm), v (Em), VI (F), VII (G).
Click a chord button → the next grid click drops a 3-note stack (root + 3rd + 5th) on that step column. Velocity carries; drag-velocity works on the whole stack at once.
For AI & automation · MCP
chord stacks land via sequencer.step.set { ..., chord: [<midi>, <midi>, <midi>] }. The diatonic palette is purely UI sugar over that surface — from MCP you'd hand-build the chord array.
Suggest Progression
Click the lightbulb on a track chip (or the footer's Suggest button). A KB-search menu opens against the curated 8-progression theory corpus:
axis-major,axis-minor— the Hooktheory "axis".i-iv-v-major,i-vi-iv-v— pop classics.ii-v-i— jazz turnaround.minor-pop-loop,folk-minor.twelve-bar-blues.
Free-text search is German + English aliased: "Pop-Schleife", "Sad Axis", "12 Bar Blues" all land. Pick a progression + a distribution:
bar(default) — 1 chord per 4 steps. Max 4 chords on a 16-step pattern; longer progressions truncate with a note.half-bar— 1 chord per 2 steps. Max 8 chords.
Hitting a result drops the progression onto the active track. Existing steps at the target indices are replaced; other steps are left alone.
actions:
- action_id: surface.open
input: { surface: sequencer-default#roll }
label: "▶ 0. Open the Sequencer (watch the grid fill)"
- action_id: sequencer.progressions.list
input: {}
save_as: progs
label: "▶ 1. List documented progressions"
- action_id: sequencer.key.set
input: { tonic_name: A, scale_id: aeolian }
label: "▶ 2. Set key to A minor"
- action_id: sequencer.track.add
input: { name: "Progression demo" }
save_as: t
label: "▶ 3. Add a demo track (leaves your tracks alone)"
- action_id: sequencer.progression.insert
input:
progression_id: axis-minor
distribution: bar
track_id: "{{t.track_id}}"
label: "▶ 4. Drop the axis-minor progression on it"
For AI & automation · MCP
sequencer.progression.insert { progression_id, distribution, key?, track_id? }. key optionally transposes to a chromatic tonic ("C" | "C#" | ... | "B"); omit to keep the canonical voicing from the progression's example key (axis-major is in C, axis-minor in A, etc.).
Clearing the grid
- Right-click chip → Clear for one track.
- MCP
sequencer.clear { track_id?, instance_id? }— resets every step on the active (or specified) track to rest.
Undo / Redo
Snapshot-based. Every meaningful edit (step set, track add, track delete, pattern-length change) commits a snapshot. Cmd/Ctrl+Z = undo, Cmd/Ctrl+Shift+Z = redo. Stack capped at ~100 entries per session.
For AI & automation · MCP
sequencer.undo {} and sequencer.redo {}. Both return "No history" when the stack is empty. Optional instance_id — undo is per-instance.
NOT captured: cursor position (not a state mutation), playback transitions (transient), velocity-drag in-progress (commits on release).
Next section: patterns + scenes — the live-arrangement model that lets you launch sections without composing inline.