Files
midi-sequencer/c-backend/generated/protocol.h
mikael-lovqvists-claude-agent 9aba8057a8 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>
2026-04-25 00:54:38 +00:00

117 lines
4.6 KiB
C
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.
/* AUTO-GENERATED by codegen/gen.mjs — DO NOT EDIT */
/* Source: protocol.yaml version 1 */
#pragma once
#include <stdint.h>
#include <string.h>
#define PROTOCOL_VERSION 1
#define FRAME_HEADER_SIZE 3
#define DIRECTION_C_TO_NODE(t) ((t) >= 0x80)
/* Record types */
typedef enum {
RT_HELLO = 0x01,
RT_DEFINE_PATTERN = 0x02,
RT_CLEAR_PATTERN = 0x03,
RT_ADD_NOTE = 0x04,
RT_ADD_SUB_PATTERN = 0x05,
RT_PLAY = 0x06,
RT_STOP = 0x07,
RT_SET_TEMPO = 0x08,
RT_ACK = 0x81,
RT_ERROR = 0x82,
RT_BEAT_TICK = 0x83,
RT_PATTERN_END = 0x84,
} Record_Type;
/* Payload sizes (bytes, not including 3-byte frame header) */
#define PAYLOAD_SIZE_HELLO 1
#define PAYLOAD_SIZE_DEFINE_PATTERN 4
#define PAYLOAD_SIZE_CLEAR_PATTERN 2
#define PAYLOAD_SIZE_ADD_NOTE 6
#define PAYLOAD_SIZE_ADD_SUB_PATTERN 5
#define PAYLOAD_SIZE_PLAY 2
#define PAYLOAD_SIZE_STOP 0
#define PAYLOAD_SIZE_SET_TEMPO 2
#define PAYLOAD_SIZE_ACK 1
#define PAYLOAD_SIZE_ERROR 2
#define PAYLOAD_SIZE_BEAT_TICK 4
#define PAYLOAD_SIZE_PATTERN_END 2
/* Record payload structs */
typedef struct {
uint8_t version;
} Msg_Hello;
typedef struct {
uint16_t pattern_id;
uint8_t steps; /* Total step count e.g. 16 for a one-bar pattern at 16th-note resolution */
uint8_t channel; /* MIDI channel 0-15 */
} Msg_Define_Pattern;
typedef struct {
uint16_t pattern_id;
} Msg_Clear_Pattern;
typedef struct {
uint16_t pattern_id;
uint8_t step; /* 0-based step index within the pattern */
uint8_t note; /* MIDI note number 0-127 (middle C = 60) */
uint8_t velocity; /* 0-127 */
uint8_t duration_steps; /* Duration in steps (1 = one step) */
} Msg_Add_Note;
typedef struct {
uint16_t pattern_id; /* Parent pattern ID */
uint8_t step; /* Step within parent at which the sub-pattern begins playing */
uint16_t sub_pattern_id;
} Msg_Add_Sub_Pattern;
typedef struct {
uint16_t pattern_id;
} Msg_Play;
typedef struct {
char _empty;
} Msg_Stop;
typedef struct {
uint16_t bpm_x10; /* BPM × 10 for 0.1 BPM resolution — e.g. 1200 = 120.0 BPM */
} Msg_Set_Tempo;
typedef struct {
uint8_t acked_type; /* Record type being acknowledged */
} Msg_Ack;
typedef struct {
uint8_t code;
uint8_t context_type; /* Record type that triggered this error */
} Msg_Error;
typedef struct {
uint16_t pattern_id;
uint8_t step; /* Current step within the pattern (0-based) */
uint8_t beat; /* Current beat number within the current cycle (wraps at 255) */
} Msg_Beat_Tick;
typedef struct {
uint16_t pattern_id;
} Msg_Pattern_End;
/* Encode: write complete frame to buf, return total bytes written */
int proto_encode_hello(uint8_t *buf, const Msg_Hello *r);
int proto_encode_define_pattern(uint8_t *buf, const Msg_Define_Pattern *r);
int proto_encode_clear_pattern(uint8_t *buf, const Msg_Clear_Pattern *r);
int proto_encode_add_note(uint8_t *buf, const Msg_Add_Note *r);
int proto_encode_add_sub_pattern(uint8_t *buf, const Msg_Add_Sub_Pattern *r);
int proto_encode_play(uint8_t *buf, const Msg_Play *r);
int proto_encode_stop(uint8_t *buf);
int proto_encode_set_tempo(uint8_t *buf, const Msg_Set_Tempo *r);
int proto_encode_ack(uint8_t *buf, const Msg_Ack *r);
int proto_encode_error(uint8_t *buf, const Msg_Error *r);
int proto_encode_beat_tick(uint8_t *buf, const Msg_Beat_Tick *r);
int proto_encode_pattern_end(uint8_t *buf, const Msg_Pattern_End *r);
/* Decode: parse payload into struct, return 0 on success, -1 on error */
int proto_decode_hello(const uint8_t *payload, uint16_t len, Msg_Hello *r);
int proto_decode_define_pattern(const uint8_t *payload, uint16_t len, Msg_Define_Pattern *r);
int proto_decode_clear_pattern(const uint8_t *payload, uint16_t len, Msg_Clear_Pattern *r);
int proto_decode_add_note(const uint8_t *payload, uint16_t len, Msg_Add_Note *r);
int proto_decode_add_sub_pattern(const uint8_t *payload, uint16_t len, Msg_Add_Sub_Pattern *r);
int proto_decode_play(const uint8_t *payload, uint16_t len, Msg_Play *r);
int proto_decode_stop(const uint8_t *payload, uint16_t len, Msg_Stop *r);
int proto_decode_set_tempo(const uint8_t *payload, uint16_t len, Msg_Set_Tempo *r);
int proto_decode_ack(const uint8_t *payload, uint16_t len, Msg_Ack *r);
int proto_decode_error(const uint8_t *payload, uint16_t len, Msg_Error *r);
int proto_decode_beat_tick(const uint8_t *payload, uint16_t len, Msg_Beat_Tick *r);
int proto_decode_pattern_end(const uint8_t *payload, uint16_t len, Msg_Pattern_End *r);