Files
midi-sequencer/protocol.yaml
mikael-lovqvists-claude-agent 515cc87382 Add PREVIEW_NOTE, auto-save, per-row play button, and click-to-rename
Protocol:
- Add PREVIEW_NOTE record (id 0x09, node→C): channel, note, velocity,
  duration_ms — plays a note immediately without touching sequencer state

C backend:
- sequencer_preview_note(): fires ALSA note-on, spawns detached thread
  for note-off after duration_ms
- RT_PREVIEW_NOTE handler in on_frame()

Node server:
- encode_preview_note imported from generated protocol
- POST /api/preview route forwards to backend

Frontend (app.mjs):
- Remove pending_notes / is_dirty / Save Notes button; every step-button
  toggle now calls PUT /api/patterns/:id/notes immediately (auto-save)
- Single delegated click handler on #content — no per-render listener
  accumulation
- Row-level ▶ play button per note row → POST /api/preview
- Click-to-rename on note/percussion labels: inline <input>, saves to
  state.custom_labels (Map keyed by "patternId:note"), Escape to cancel
- pattern_updated SSE no longer guarded by is_dirty

CSS (index.html):
- .note-label: cursor pointer + hover highlight
- .note-label-input for inline rename field
- .row-play-btn and .row-play-spacer for per-row preview buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 03:33:05 +00:00

163 lines
4.1 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
version: 1
description: Binary protocol between Node sequencer and C ALSA MIDI backend
# Frame format: [record_type: uint8][payload_length: uint16le][payload: bytes...]
# Header size: 3 bytes
# High bit set (0x80+) means C → Node direction
frame:
- name: record_type
type: uint8
- name: payload_length
type: uint16
# Type mapping used by codegen
types:
uint8: { c_type: uint8_t, c_put: put_u8, c_get: get_u8, node_write: writeUInt8, node_read: readUInt8, size: 1 }
uint16: { c_type: uint16_t, c_put: put_u16, c_get: get_u16, node_write: writeUInt16LE, node_read: readUInt16LE, size: 2 }
records:
HELLO:
id: 0x01
direction: node_to_c
description: Protocol version handshake
fields:
- name: version
type: uint8
DEFINE_PATTERN:
id: 0x02
direction: node_to_c
description: Define or redefine a pattern (clears existing data)
fields:
- name: pattern_id
type: uint16
- name: steps
type: uint8
note: Total step count e.g. 16 for a one-bar pattern at 16th-note resolution
- name: channel
type: uint8
note: MIDI channel 0-15
CLEAR_PATTERN:
id: 0x03
direction: node_to_c
description: Remove all notes and sub-pattern references from a pattern
fields:
- name: pattern_id
type: uint16
ADD_NOTE:
id: 0x04
direction: node_to_c
description: Add a note event to a pattern at a specific step
fields:
- name: pattern_id
type: uint16
- name: step
type: uint8
note: 0-based step index within the pattern
- name: note
type: uint8
note: MIDI note number 0-127 (middle C = 60)
- name: velocity
type: uint8
note: 0-127
- name: duration_steps
type: uint8
note: Duration in steps (1 = one step)
ADD_SUB_PATTERN:
id: 0x05
direction: node_to_c
description: Schedule a sub-pattern to start at a given step within a parent pattern
fields:
- name: pattern_id
type: uint16
note: Parent pattern ID
- name: step
type: uint8
note: Step within parent at which the sub-pattern begins playing
- name: sub_pattern_id
type: uint16
PLAY:
id: 0x06
direction: node_to_c
description: Start playing a pattern from step 0
fields:
- name: pattern_id
type: uint16
STOP:
id: 0x07
direction: node_to_c
description: Stop all playback and send MIDI all-notes-off
fields: []
SET_TEMPO:
id: 0x08
direction: node_to_c
description: Set global tempo (applies immediately, even mid-sequence)
fields:
- name: bpm_x10
type: uint16
note: "BPM × 10 for 0.1 BPM resolution — e.g. 1200 = 120.0 BPM"
PREVIEW_NOTE:
id: 0x09
direction: node_to_c
description: Play a single note immediately without affecting sequencer state
fields:
- name: channel
type: uint8
- name: note
type: uint8
- name: velocity
type: uint8
- name: duration_ms
type: uint16
note: Note-off will be sent after this many milliseconds
ACK:
id: 0x81
direction: c_to_node
description: Acknowledge a received command
fields:
- name: acked_type
type: uint8
note: Record type being acknowledged
ERROR:
id: 0x82
direction: c_to_node
description: Report an error condition
fields:
- name: code
type: uint8
- name: context_type
type: uint8
note: Record type that triggered this error
BEAT_TICK:
id: 0x83
direction: c_to_node
description: Timing notification sent on every sequencer step
fields:
- name: pattern_id
type: uint16
- name: step
type: uint8
note: Current step within the pattern (0-based)
- name: beat
type: uint8
note: Current beat number within the current cycle (wraps at 255)
PATTERN_END:
id: 0x84
direction: c_to_node
description: Notification that a pattern has completed one full cycle
fields:
- name: pattern_id
type: uint16