All books

The Keyboard

~6 min read · updated 2026-09-28 · markdown

actions:
  - action_id: surface.open
    input: { surface: keyboard-default }
    label: "▶ 0. Open the Keyboard panel"
  - action_id: keyboard.channel.set
    input: { channel: 1 }
    label: "▶ 1. Send on MIDI channel 1"
  - action_id: keyboard.octave.set
    input: { base: 60 }
    label: "▶ 2. Octave base = C4 (middle C)"
  - action_id: keyboard.note.on
    input: { note: 60, velocity: 100 }
    label: "▶ 3. Play C4 (loud)"
  - action_id: keyboard.note.on
    input: { note: 64, velocity: 100 }
    label: "▶ 4. Add E4 (major third)"
  - action_id: keyboard.note.on
    input: { note: 67, velocity: 100 }
    label: "▶ 5. Add G4 (C major chord)"
  - action_id: keyboard.notes.clear
    input: {}
    label: "■ Release all"

The Keyboard is FaustWave's virtual MIDI input — a clickable on-screen keyboard registered as a routing-table source (keyboard-default). Useful for testing a DSP ("does my Builder make a sound when I press a key?"), for performing without a hardware controller, and — as the action chain above shows — for driving notes programmatically from the assistant.

Opening + anatomy

Open the Keyboard rail panel from the left rail (piano-keys icon under the MIDI sources area). The panel shows:

  • A two-octave keyboard layout (default: leftmost key = MIDI 60 / C4 / middle C).
  • Octave shift buttons — move the visible range up / down by one octave.
  • A MIDI channel-picker chip (Omni / 1–16).
  • A hold-mode toggle (see below).
  • An ALL OFF button for the stuck-notes recovery.

Playing notes

Click a key to send a note-on MIDI event; release (or pointer-out) sends note-off. The event flows through the routing table to every connected MIDI sink — instruments, Builders, sequencer record-armed tracks, hardware MIDI outs, etc.

Holding multiple pointers (or stacking with hold-mode) plays a chord. The Keyboard itself has no polyphony cap; the receiving consumer decides what it can voice.

Hold mode — stacking chords with one pointer

The hold toggle changes the click semantics:

  • OFF (default, physical-key feel): pointer-down plays, pointer-up releases. Mono unless you have multi-touch.
  • ON (toggle / latch feel): click ONCE to start a note, click AGAIN to release. Stack chords by clicking multiple keys one after another, without holding the pointer down.

Hold-mode does NOT auto-clear when flipped — if you turn it OFF with notes still latched, they stay on until you hit ALL OFF or play and release them with a fresh pointer press.

For AI & automation · MCP

keyboard.hold.set { enabled: true | false }.

MIDI channel

The Keyboard sends on channel 1 by default. Change it via the panel's channel selector or:

For AI & automation · MCP

keyboard.channel.set { channel: 0..16 }. 0 = Omni broadcast (status-byte channel bits = 0, equivalent to channel 1 on the wire; receivers configured Omni accept any channel). 1..16 = specific channel.

Receiving consumers (Builder midi_note nodes, sequencer tracks) filter by channel — if they listen on a different channel than you send, they ignore the event. Heads-up: changing channel mid-held-note strands the note on the OLD channel. Call keyboard.notes.clear before the channel switch if any notes are held.

Octave shift

The Keyboard's visible range moves in semitones by setting the octave base — the MIDI number of the leftmost visible key. Default is 60 (C4). Range is clamped to 0–103 so the topmost visible key stays inside MIDI 0–127.

For AI & automation · MCP

keyboard.octave.set { base: 0..103 }. Examples: 48 = C3 (one octave down), 72 = C5 (one octave up). The panel's octave buttons step in 12-semitone increments and call keyboard.notes.clear first to avoid hung notes — do the same when scripting if any notes are held.

Stuck notes — ALL OFF / keyboard.notes.clear

Long sessions can leave notes hanging — a channel switch mid-held-note, a hold-mode flip, an MCP call that fired keyboard.note.on without a matching keyboard.note.off. The ALL OFF button (and its MCP twin keyboard.notes.clear) is the recovery: it sends a note-off for every entry in the held-set on the current channel, then clears the set.

Idempotent — calling it with nothing held is a no-op. Always safe to fire.

For AI & automation · MCP

keyboard.notes.clear {} — releases what THIS keyboard holds; useful as an action chain's epilogue. It is not the panic: for a note stuck on an instrument or on external hardware, use midi.panic {} (or the Panic button at the right end of the transport strip), which tells every MIDI sink and every hardware output to let go.

Routing

The Keyboard registers as the source keyboard-default. A fresh project has no seeded MIDI connections — there's no bundled instrument to wire to, so you draw the Keyboard's routing yourself.

Wire it via the Patchbay rail panel (click the cell at the row for keyboard-default and the column of any compatible MIDI sink). Common targets: your own Builders' midi_note nodes, sequencer record-armed tracks, hardware MIDI-out devices.

For AI & automation · MCP

connection management lives under routing.connect / routing.disconnect / routing.list. The Keyboard's source id is the stable keyboard-default.

Physical MIDI integration

Plug in a hardware MIDI controller (USB / Bluetooth / DIN-USB adapter). FaustWave's MIDI subsystem picks it up via WebMIDI — the OS prompts for permission on first use.

Physical controllers appear as separate routing sources (e.g. midi-input-input-0) alongside keyboard-default. Wire them into sinks via the Patchbay the same way you'd wire any source. The on-screen Keyboard and physical controllers can coexist — both feed the same sinks if both are wired up.

For AI & automation · MCP

list everything currently MIDI-audible with system.state { sections: ["midi_consumers"] }. For full topology hit routing.list and filter by kind: "midi".

The audible-consumer hint

A quality-of-life affordance in the Mixer: if you press a key and NOTHING is currently set to be audibly driven by MIDI, the Mixer panel shows a Smart Mute Hint — a soft "hey, your input isn't reaching anything that makes sound". Common causes: nothing is wired from the Keyboard to a sound source yet, every MIDI consumer is muted, or the Builder you're driving isn't on a MixerTrack (not "+ ADD AUDIO"-ed).

The hint clears as soon as an audible MIDI consumer becomes reachable again.

MCP surface — the real catalog

ActionPurpose
keyboard.note.onTrigger note-on (note, velocity). Velocity defaults to 100.
keyboard.note.offTrigger note-off. Idempotent re: stuck-note recovery.
keyboard.channel.setSet output channel (0 = Omni, 1–16 specific).
keyboard.octave.setSet the leftmost visible MIDI number (0–103).
keyboard.hold.setToggle hold-mode (latch vs press-and-release).
keyboard.notes.clearRelease every note THIS keyboard holds. Not the global panic — that is midi.panic.
keyboard.stateSnapshot: held notes, channel, hold flag, octave base.

All Keyboard MCP actions are palette.run-only (no hot-path tools) — they're low-frequency compared to the Sequencer's surface, which earns dedicated tools. See FaustWave — AI Assistant § Why some actions are hot-path and others aren't for the discipline.

Where to go from here

  • FaustWave — Sequencer for the other big MIDI source. Both route through the Patchbay; both share the master transport.
  • FaustWave — Builder for midi_note nodes so your DSP responds to Keyboard input.
  • FaustWave — Getting Started § Your first pattern — a Keyboard-driven walk-through.
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.93.0