Skip to content

music realtime: CoreMIDI steering for Magenta RT2 (OP-1 and friends) - #137

Merged
a-github-name merged 2 commits into
mainfrom
codex/op1-midi-realtime
Jul 4, 2026
Merged

music realtime: CoreMIDI steering for Magenta RT2 (OP-1 and friends)#137
a-github-name merged 2 commits into
mainfrom
codex/op1-midi-realtime

Conversation

@a-github-name

Copy link
Copy Markdown
Member

Feature

Live MIDI control for music realtime on macOS:

  • --list-midi-inputs — enumerate CoreMIDI sources (name | manufacturer | model | unique ID)
  • --midi-input <name-or-id> — connect a source; exact-ID and exact-name matches win, substring matches must be unambiguous
  • --midi-channel all|1-16, --midi-note-offset <n>
  • repeatable --midi-cc cc=target:min:max mappings (temp, topk, mc, notes, drums, drumless, unmask, seed, onset)

Note-on/off and mapped CCs feed the same MagentaRT2LiveControlQueue as interactive stdin steering (the former private interactive-controls class, extracted to Support/ and shared by both paths). Prompt changes stay on stdin — the prompt encoder swap can stall a frame, so MIDI is for notes and continuous controls (matching the engine constraints established in #132).

Review hardening on top of the initial implementation

  • Fixed a memory-safety bug in packet iteration: the original loop copied MIDIPacket into a local and called MIDIPacketNext on the copy — that walks past the copy's stack storage and reads garbage whenever a MIDIPacketList carries more than one packet (chords, CC sweeps, clock+note bursts). Now uses MIDIPacketList.unsafeSequence() and reads the true variable-length payload via the data field offset.
  • Running status support: the original parser treated every data byte outside a leading status byte as stray and dropped it — under running status (one status byte, many data pairs, common from hardware) every message after the first was lost. Parsing is now a small stateful MIDI 1.0 parser (MagentaRT2MIDIStreamParser) that keeps running status across packet boundaries, tolerates system-realtime bytes (clock, active sensing) interleaved mid-message, advances correctly past pitch-bend/program-change, and normalizes velocity-0 note-on to note-off per spec.
  • Testability: the parser is pure and platform-independent, so the protocol edge cases above are unit-tested directly (multi-message packets, running-status chords, split messages, SysEx + stray-byte recovery).
  • Ambiguous source matches fail loudly with the candidate list instead of silently binding the first substring hit.
  • Minor: stdin reader task only spawns in interactive mode; snapshot() drops an unused parameter.

Validation

🤖 Generated with Claude Code

a-github-name and others added 2 commits July 4, 2026 08:41
Adds live MIDI control to `music realtime` on macOS: --list-midi-inputs,
--midi-input (source name or unique ID), --midi-channel, --midi-note-offset,
and repeatable --midi-cc target mappings (cc=target:min:max) covering the
same controls as interactive stdin steering. The former private interactive
controls class is extracted as MagentaRT2LiveControlQueue and shared by the
stdin and MIDI paths.

Review hardening on top of the initial implementation:
- Packet iteration now uses MIDIPacketList.unsafeSequence(). The previous
  loop copied MIDIPacket into a local and called MIDIPacketNext on the
  copy, which walks past the copy's storage and reads garbage whenever a
  packet list carries more than one packet (chords, CC sweeps).
- MIDI byte parsing is extracted into MagentaRT2MIDIStreamParser, a pure
  incremental MIDI 1.0 parser that supports running status (previously
  dropped every message after the first under a shared status byte),
  survives system-realtime bytes interleaved mid-message and messages
  split across packet boundaries, advances correctly past pitch-bend and
  program-change messages, and normalizes velocity-0 note-on to note-off.
  Being platform-independent, it is unit-tested directly.
- Ambiguous --midi-input substring matches now fail with the candidate
  list instead of silently binding the first match.
- The stdin reader task is only spawned in interactive mode, and the live
  control queue's snapshot() drops its unused frame-index parameter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@a-github-name
a-github-name merged commit 122f29b into main Jul 4, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant