From d4ba1589ffad345a31b14afdfc2ba0ae807757db Mon Sep 17 00:00:00 2001 From: Loic Coenen Date: Mon, 4 May 2026 22:25:33 +0000 Subject: [PATCH] fix: use pointer to dispatcher state in process callback for real-time access Co-authored-by: aider (deepseek/deepseek-coder) --- dispatcher.c | 4 ++++ dispatcher.h | 5 +++++ engine.c | 12 +++++++----- engine.h | 2 ++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/dispatcher.c b/dispatcher.c index 8e2e2e8..47b0f48 100644 --- a/dispatcher.c +++ b/dispatcher.c @@ -117,6 +117,10 @@ void dispatcher_get_state(AppState *out) { pthread_mutex_unlock(&dispatcher.state_mutex); } +AppState* dispatcher_get_state_ptr(void) { + return &dispatcher.state; +} + // ============================================================ // Reducer implementation // ============================================================ diff --git a/dispatcher.h b/dispatcher.h index e8f4310..1d0158b 100644 --- a/dispatcher.h +++ b/dispatcher.h @@ -210,6 +210,11 @@ void dispatcher_stop(void); // Get current state (thread-safe snapshot) void dispatcher_get_state(AppState *out); +// Get pointer to dispatcher's state (for real-time threads that can't block) +// WARNING: This is NOT thread-safe. Only use in JACK process callback +// which is serialized per client. +AppState* dispatcher_get_state_ptr(void); + // ============================================================ // Reducer - pure function // ============================================================ diff --git a/engine.c b/engine.c index f228194..dbd762f 100644 --- a/engine.c +++ b/engine.c @@ -28,9 +28,8 @@ static int process_callback(jack_nframes_t nframes, void *arg) { jack_midi_clear_buffer(midi_out_buf); - // Get state snapshot for reads - AppState state; - dispatcher_get_state(&state); + // Get pointer to dispatcher's state for real-time access + AppState *state = engine->state; // Process MIDI input int event_index; @@ -100,7 +99,7 @@ static int process_callback(jack_nframes_t nframes, void *arg) { for (int s = 0; s < MAX_SCENES; s++) { for (int g = 0; g < 8; g++) { int clip_idx = g * GRID_ROWS * GRID_COLS + s * GRID_COLS + ch; - MidiClip *mclip = &state.midi_clips[clip_idx]; + MidiClip *mclip = &state->midi_clips[clip_idx]; if (mclip->state == CLIP_LOOPING && mclip->event_count > 0 && mclip->events != NULL) { if (mclip->read_index < mclip->event_count) { @@ -142,7 +141,7 @@ static int process_callback(jack_nframes_t nframes, void *arg) { // Iterate over all grids for this scene and channel for (int g = 0; g < 8; g++) { int clip_idx = g * GRID_ROWS * GRID_COLS + s * GRID_COLS + ch; - Clip *clip = &state.clips[clip_idx]; + Clip *clip = &state->clips[clip_idx]; if (clip->state == CLIP_RECORDING) { if (clip->write_position < MAX_BUFFER_SIZE && clip->buffer != NULL) { @@ -237,6 +236,9 @@ int engine_init(Engine *engine, const char *client_name, DispatchFn dispatch) { carla_init(&engine->carla_host, engine->client); carla_scan_plugins(&engine->carla_host); + // Get pointer to dispatcher's state for real-time access + engine->state = dispatcher_get_state_ptr(); + return 0; } diff --git a/engine.h b/engine.h index 223302b..f617c9e 100644 --- a/engine.h +++ b/engine.h @@ -21,6 +21,8 @@ typedef struct { bool running; CarlaHost carla_host; // Carla host state for plugin management + + AppState *state; // Pointer to dispatcher's state (for real-time access) } Engine; int engine_init(Engine *engine, const char *client_name, DispatchFn dispatch);