Files
midi-sequencer/c-backend/generated/protocol.h
mikael-lovqvists-claude-agent 9b45905d80 Add multi-track playback with mute/solo support
Replaces the single-root-pattern sequencer with a Track[] array that
allows multiple patterns to loop independently. Adds ADD_TRACK (0x0A),
REMOVE_TRACK (0x0B), PLAY_TRACKS (0x0C), and SET_TRACK_MUTE (0x0D)
protocol records. The C backend gains per-track pending_subs and a
tracks_mutex. The Node server gains track-state APIs (/api/tracks/:id/
active, mute, solo) and the frontend shows per-pattern track/mute/solo
buttons in the sidebar list.

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

156 lines
6.1 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_PREVIEW_NOTE = 0x09,
RT_ADD_TRACK = 0x0A,
RT_REMOVE_TRACK = 0x0B,
RT_PLAY_TRACKS = 0x0C,
RT_SET_TRACK_MUTE = 0x0D,
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_PREVIEW_NOTE 5
#define PAYLOAD_SIZE_ADD_TRACK 2
#define PAYLOAD_SIZE_REMOVE_TRACK 2
#define PAYLOAD_SIZE_PLAY_TRACKS 0
#define PAYLOAD_SIZE_SET_TRACK_MUTE 3
#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 channel;
uint8_t note;
uint8_t velocity;
uint16_t duration_ms; /* Note-off will be sent after this many milliseconds */
} Msg_Preview_Note;
typedef struct {
uint16_t pattern_id;
} Msg_Add_Track;
typedef struct {
uint16_t pattern_id;
} Msg_Remove_Track;
typedef struct {
char _empty;
} Msg_Play_Tracks;
typedef struct {
uint16_t pattern_id;
uint8_t muted;
} Msg_Set_Track_Mute;
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_preview_note(uint8_t *buf, const Msg_Preview_Note *r);
int proto_encode_add_track(uint8_t *buf, const Msg_Add_Track *r);
int proto_encode_remove_track(uint8_t *buf, const Msg_Remove_Track *r);
int proto_encode_play_tracks(uint8_t *buf);
int proto_encode_set_track_mute(uint8_t *buf, const Msg_Set_Track_Mute *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_preview_note(const uint8_t *payload, uint16_t len, Msg_Preview_Note *r);
int proto_decode_add_track(const uint8_t *payload, uint16_t len, Msg_Add_Track *r);
int proto_decode_remove_track(const uint8_t *payload, uint16_t len, Msg_Remove_Track *r);
int proto_decode_play_tracks(const uint8_t *payload, uint16_t len, Msg_Play_Tracks *r);
int proto_decode_set_track_mute(const uint8_t *payload, uint16_t len, Msg_Set_Track_Mute *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);