Initial scaffold: ALSA MIDI C backend + Node ESM sequencer web app
- protocol.yaml: SSoT for the binary framing protocol (12 record types) - codegen/gen.mjs: generates C header/source and Node ESM from protocol.yaml - c-backend: ALSA sequencer with drift-free clock_nanosleep tick thread, pattern store (hierarchical sub-patterns), Unix socket server - node-server: Express 5 web app — REST API, SSE for real-time beat events, step-sequencer frontend with pending-edit / explicit-save flow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
147
protocol.yaml
Normal file
147
protocol.yaml
Normal file
@@ -0,0 +1,147 @@
|
||||
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"
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user