187 lines
5.4 KiB
C
187 lines
5.4 KiB
C
#ifndef DISPATCHER_H
|
|
#define DISPATCHER_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdatomic.h>
|
|
#include <jack/jack.h>
|
|
#include <pthread.h>
|
|
#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
|