#ifndef DISPATCHER_H #define DISPATCHER_H #include #include #include #include #include #include "carla.h" // ============================================================ // Application State - contains ALL application state // ============================================================ #define MAX_SCENES 8 #define MAX_CHANNELS 8 #define MAX_CLIPS (MAX_SCENES * MAX_CHANNELS) // 64 #define MAX_BUFFER_SIZE 441000 // 10 seconds at 44.1kHz #define MAX_UNDO_HISTORY 256 #define CLIP_INDEX(scene, channel) ((scene) * MAX_CHANNELS + (channel)) typedef enum { CLIP_EMPTY, CLIP_RECORDING, CLIP_LOOPING, CLIP_STOPPED } ClipState; typedef enum { QUANTIZE_OFF, QUANTIZE_BEAT, QUANTIZE_BAR } QuantizeMode; typedef enum { TRANSPORT_STOPPED, TRANSPORT_PLAYING, TRANSPORT_PAUSED } TransportState; typedef enum { CLOCK_SOURCE_INTERNAL, CLOCK_SOURCE_MIDI } ClockSource; typedef struct { ClipState state; float *buffer; size_t buffer_size; size_t write_position; size_t read_position; } Clip; typedef struct { // Transport state TransportState transport_state; ClockSource clock_source; uint32_t clock_count; uint32_t beat_position; uint32_t bar_position; uint32_t sample_position; double bpm; double samples_per_beat; double sample_accumulator; // Quantization QuantizeMode quantize_mode; jack_nframes_t quantize_threshold; // Clips Clip clips[MAX_CLIPS]; // Undo history struct { int undo_index; int redo_index; int count; ClipState prev_clip_states[MAX_UNDO_HISTORY]; int prev_clip_indices[MAX_UNDO_HISTORY]; size_t prev_buffer_sizes[MAX_UNDO_HISTORY]; size_t prev_write_positions[MAX_UNDO_HISTORY]; size_t prev_read_positions[MAX_UNDO_HISTORY]; int batch_sizes[MAX_UNDO_HISTORY]; // NEW: track batch sizes int current_batch_size; // NEW: current batch being recorded } undo; // Carla host CarlaHost carla_host; // JACK info (needed by audio thread) jack_nframes_t sample_rate; bool running; } AppState; // ============================================================ // Actions // ============================================================ typedef enum { ACTION_TRIGGER_CLIP, ACTION_TRIGGER_SCENE, ACTION_RESET_CLIP, ACTION_SET_QUANTIZE_MODE, ACTION_SET_QUANTIZE_THRESHOLD, ACTION_TRANSPORT_PLAY, ACTION_TRANSPORT_PAUSE, ACTION_TRANSPORT_STOP, ACTION_TRANSPORT_TOGGLE_PLAY, ACTION_SET_CLOCK_SOURCE, ACTION_SET_BPM, ACTION_RESET_TRANSPORT, ACTION_UNDO, ACTION_REDO, ACTION_SAVE_CLIP, ACTION_LOAD_CLIP, ACTION_MIDI_NOTE_ON, ACTION_MIDI_SCENE_LAUNCH, ACTION_RACK_ADD_PLUGIN, ACTION_RACK_REMOVE_PLUGIN, ACTION_RACK_SET_PARAMETER, ACTION_RACK_SET_VOLUME, ACTION_RACK_BYPASS, ACTION_SAVE_PROJECT, ACTION_LOAD_PROJECT, ACTION_PROCESS_AUDIO, ACTION_QUIT } ActionType; typedef struct { ActionType type; union { struct { int clip_index; } trigger_clip; struct { int scene_index; } trigger_scene; struct { int clip_index; } reset_clip; struct { QuantizeMode mode; } set_quantize_mode; struct { jack_nframes_t threshold; } set_quantize_threshold; struct { ClockSource source; } set_clock_source; struct { double bpm; } set_bpm; struct { int clip_index; } save_clip; struct { int clip_index; char filename[256]; } load_clip; struct { int note; int velocity; int channel; jack_nframes_t time; } midi_note_on; struct { int scene_index; jack_nframes_t time; } midi_scene_launch; struct { int channel; char uri[512]; PluginType type; } rack_add_plugin; struct { int channel; int plugin_index; } rack_remove_plugin; struct { int channel; int plugin_index; int param_index; float value; } rack_set_parameter; struct { int channel; float volume; } rack_set_volume; struct { int channel; bool bypass; } rack_bypass; struct { char filename[512]; } save_project; struct { char filename[512]; } load_project; struct { jack_nframes_t nframes; } process_audio; } data; } Action; // ============================================================ // Dispatcher API // ============================================================ // Thread-safe dispatch function - called by any thread typedef void (*DispatchFn)(Action action); // Subscriber callback - called after each state update (from dispatcher thread) typedef void (*SubscriberFn)(AppState *state, void *user_data); // Initialize the dispatcher with initial state // Returns the dispatch function that consumers can call DispatchFn dispatcher_init(AppState *initial_state); // Register a subscriber (call before dispatcher_start) void dispatcher_subscribe(SubscriberFn fn, void *user_data); // Start the dispatcher thread void dispatcher_start(void); // Stop the dispatcher and cleanup void dispatcher_stop(void); // Get current state (thread-safe snapshot) AppState dispatcher_get_state(void); // ============================================================ // Reducer - pure function // ============================================================ AppState reducer(AppState state, Action action); #endif // DISPATCHER_H