feat: implement lock-free command queue and atomic state for thread safety

Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
Loic Coenen
2026-05-01 14:52:53 +00:00
parent 563380df66
commit 7b23c75dd1
6 changed files with 293 additions and 63 deletions

View File

@@ -5,6 +5,7 @@
#include <jack/midiport.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#define MAX_SCENES 8
#define MAX_CHANNELS 8
@@ -46,6 +47,31 @@ typedef struct {
bool is_playing;
} Clip;
// Maximum number of queued commands from frontend to audio thread
#define MAX_QUEUED_COMMANDS 64
typedef enum {
CMD_TRIGGER_CLIP,
CMD_TRIGGER_SCENE,
CMD_RESET_CLIP,
CMD_SET_QUANTIZE_MODE,
CMD_SET_QUANTIZE_THRESHOLD,
CMD_RESET_TRANSPORT
} CommandType;
typedef struct {
CommandType type;
int index; // clip_index, scene_index, or mode value
jack_nframes_t value; // threshold value or other numeric param
} Command;
// Lock-free single-producer single-consumer ring buffer
typedef struct {
Command buffer[MAX_QUEUED_COMMANDS];
atomic_uint write_index;
atomic_uint read_index;
} CommandQueue;
// Queued trigger for quantization
typedef struct QueuedTrigger {
int clip_index;
@@ -76,6 +102,18 @@ typedef struct {
jack_nframes_t quantize_threshold; // in samples (lookahead)
QueuedTrigger *queued_triggers;
// Thread-safe command queue for frontend -> audio thread communication
CommandQueue command_queue;
// Atomic flags for simple state that frontend reads
atomic_int transport_rolling; // bool
atomic_uint transport_clock_count;
atomic_uint transport_beat_position;
atomic_uint transport_bar_position;
atomic_uint transport_sample_position;
atomic_int quantize_mode_atomic; // QuantizeMode
atomic_uint quantize_threshold_atomic;
bool running;
} Engine;
@@ -98,6 +136,12 @@ void engine_reset_transport(Engine *engine);
// Queue management (exposed for testing)
void queue_trigger(Engine *engine, int clip_index, bool is_scene, jack_nframes_t time);
// Thread-safe command submission (called from frontend threads)
int engine_submit_command(Engine *engine, CommandType type, int index, jack_nframes_t value);
// Process pending commands (called from audio thread)
void engine_process_commands(Engine *engine);
// Utility
const char* clip_state_to_string(ClipState state);
uint8_t clip_state_to_velocity(ClipState state);