#ifndef CHANNEL_H #define CHANNEL_H // cppcheck-suppress missingIncludeSystem #include #include #define LOOP_BUF_SIZE (5 * 48000) #define MAX_MIDI_EVENTS 1024 #define MAX_SCENES 16 typedef enum { CHANNEL_AUDIO, CHANNEL_MIDI } channel_type_t; typedef struct { jack_nframes_t timestamp; /* frame offset relative to loop start */ unsigned char status; unsigned char note; unsigned char velocity; } midi_event_t; typedef enum { STATE_IDLE, STATE_RECORD, STATE_LOOPING, STATE_PAUSED } looper_state; typedef struct { union { float audio_buffer[LOOP_BUF_SIZE]; midi_event_t midi_events[MAX_MIDI_EVENTS]; } loop; atomic_int loop_count; atomic_int record_pos; atomic_int playback_pos; atomic_int state; atomic_int prev_state; } scene_t; struct channel_t { channel_type_t type; atomic_int active; jack_port_t *audio_in; jack_port_t *audio_out; jack_port_t *midi_in; jack_port_t *midi_out; scene_t scenes[MAX_SCENES]; atomic_int scene_count; atomic_int current_scene; }; /* Globals declared in looper.c */ extern struct channel_t *_Atomic channels; extern atomic_int channel_capacity; extern atomic_int channel_count; extern int next_channel_id; /* Safe accessor for the real‑time thread (returns a snapshot of the current pointer) */ static inline struct channel_t *get_channels_array(void) { return atomic_load(&channels); } void channel_add(jack_client_t *client, int idx); void channel_remove(jack_client_t *client, int idx); void channel_add_midi(jack_client_t *client, int idx); /* Scene management (called from main loop) */ void channel_add_scene(jack_client_t *client, int idx); void channel_remove_scene(jack_client_t *client, int idx); void channel_next_scene(jack_client_t *client, int idx); void channel_prev_scene(jack_client_t *client, int idx); #endif