All books

Composing on the grid

~5 min read · updated 2026-09-06 · markdown

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 } or sequencer.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:

HoldBehaviour
0.25Staccato — very short.
1.0Default — release at the next step boundary.
2.0Tied — rings into the next step.
4.0Held one beat (4 × 16th).
16.0Held a full bar.
> pattern lengthLegato 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.

Try it yourself — the IDE runs in your browser. Open the IDE → Get the desktop app

Text licensed under CC BY 4.0 — Mani Weber / FaustWave. For language models: llms.txt · llms-full.txt

AUDIO · 48k · 48.0ms FAUST · 3 KB · 1171 docs CPU · 8.4% BPM · 120.0 UTF-8 BETA· v0.90.0