refactor: implement unidirectional data flow with dispatcher pattern
Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
219
engine.h
219
engine.h
@@ -3,237 +3,30 @@
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/midiport.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <pthread.h>
|
||||
#include "transport.h"
|
||||
|
||||
#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
|
||||
|
||||
// Convert scene/channel to flat clip index
|
||||
#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 struct {
|
||||
atomic_int state; // ClipState (atomic for thread-safe access)
|
||||
float *buffer;
|
||||
atomic_size_t buffer_size; // size_t (atomic for thread-safe access)
|
||||
size_t write_position;
|
||||
size_t read_position;
|
||||
bool is_playing;
|
||||
} Clip;
|
||||
|
||||
// Maximum number of queued commands from frontend to audio thread
|
||||
#define MAX_QUEUED_COMMANDS 64
|
||||
|
||||
// Size of the pre-allocated trigger pool (must match engine.c)
|
||||
#define QUEUED_TRIGGER_POOL_SIZE 64
|
||||
|
||||
typedef enum {
|
||||
CMD_TRIGGER_CLIP,
|
||||
CMD_TRIGGER_SCENE,
|
||||
CMD_RESET_CLIP,
|
||||
CMD_SET_QUANTIZE_MODE,
|
||||
CMD_SET_QUANTIZE_THRESHOLD,
|
||||
CMD_RESET_TRANSPORT,
|
||||
CMD_UNDO,
|
||||
CMD_REDO,
|
||||
CMD_TRANSPORT_PLAY,
|
||||
CMD_TRANSPORT_PAUSE,
|
||||
CMD_TRANSPORT_STOP,
|
||||
CMD_TRANSPORT_TOGGLE_PLAY,
|
||||
CMD_SET_CLOCK_SOURCE,
|
||||
CMD_SET_BPM
|
||||
} CommandType;
|
||||
|
||||
// Undo/Redo action types
|
||||
typedef enum {
|
||||
ACTION_TRIGGER_CLIP,
|
||||
ACTION_TRIGGER_SCENE,
|
||||
ACTION_RESET_CLIP,
|
||||
ACTION_SET_QUANTIZE_MODE,
|
||||
ACTION_SET_QUANTIZE_THRESHOLD,
|
||||
ACTION_RESET_TRANSPORT,
|
||||
ACTION_TRANSPORT_STATE_CHANGE
|
||||
} ActionType;
|
||||
|
||||
// Undo/Redo action record
|
||||
typedef struct {
|
||||
ActionType type;
|
||||
int index; // clip_index, scene_index, or mode value
|
||||
jack_nframes_t value; // threshold value or other numeric param
|
||||
ClipState previous_state; // For clip state changes
|
||||
size_t previous_buffer_size;
|
||||
size_t previous_write_position;
|
||||
size_t previous_read_position;
|
||||
bool previous_rolling;
|
||||
uint32_t previous_clock_count;
|
||||
uint32_t previous_beat_position;
|
||||
uint32_t previous_bar_position;
|
||||
uint32_t previous_sample_position;
|
||||
QuantizeMode previous_quantize_mode;
|
||||
jack_nframes_t previous_quantize_threshold;
|
||||
} UndoAction;
|
||||
|
||||
// Undo/Redo history
|
||||
#define MAX_UNDO_HISTORY 256
|
||||
|
||||
typedef struct {
|
||||
UndoAction actions[MAX_UNDO_HISTORY];
|
||||
atomic_int undo_index; // Points to next action to undo
|
||||
atomic_int redo_index; // Points to next action to redo
|
||||
atomic_int count; // Total actions in history
|
||||
} UndoHistory;
|
||||
|
||||
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;
|
||||
|
||||
// Save/Load request types
|
||||
typedef enum {
|
||||
REQ_SAVE_CLIP,
|
||||
REQ_LOAD_CLIP
|
||||
} SaveLoadType;
|
||||
|
||||
typedef struct {
|
||||
SaveLoadType type;
|
||||
int clip_index;
|
||||
char filename[256];
|
||||
} SaveLoadRequest;
|
||||
|
||||
// Lock-free queue for save/load requests (audio thread -> save/load thread)
|
||||
typedef struct {
|
||||
SaveLoadRequest buffer[MAX_QUEUED_COMMANDS];
|
||||
atomic_uint write_index;
|
||||
atomic_uint read_index;
|
||||
} SaveLoadQueue;
|
||||
|
||||
// Queued trigger for quantization
|
||||
typedef struct QueuedTrigger {
|
||||
int clip_index;
|
||||
bool is_scene;
|
||||
jack_nframes_t trigger_time;
|
||||
struct QueuedTrigger *next;
|
||||
} QueuedTrigger;
|
||||
#include "dispatcher.h"
|
||||
|
||||
typedef struct {
|
||||
jack_client_t *client;
|
||||
jack_port_t *audio_in_ports[MAX_CHANNELS];
|
||||
jack_port_t *audio_out_ports[MAX_CHANNELS];
|
||||
jack_port_t *midi_in_port; // Control channel MIDI
|
||||
jack_port_t *midi_scene_in_port; // Scene launch MIDI
|
||||
jack_port_t *midi_clock_in_port; // MIDI clock input
|
||||
jack_port_t *midi_in_port;
|
||||
jack_port_t *midi_scene_in_port;
|
||||
jack_port_t *midi_clock_in_port;
|
||||
jack_port_t *midi_out_port;
|
||||
|
||||
Clip clips[MAX_CLIPS];
|
||||
int control_channel;
|
||||
DispatchFn dispatch;
|
||||
jack_nframes_t sample_rate;
|
||||
|
||||
// Transport and clock
|
||||
Transport *transport;
|
||||
|
||||
// Quantization
|
||||
QuantizeMode quantize_mode;
|
||||
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 quantize_mode_atomic; // QuantizeMode
|
||||
atomic_uint quantize_threshold_atomic;
|
||||
|
||||
bool running;
|
||||
|
||||
// Undo/Redo
|
||||
UndoHistory undo_history;
|
||||
|
||||
// Save/Load queue and thread
|
||||
SaveLoadQueue save_load_queue;
|
||||
pthread_t save_load_thread;
|
||||
volatile bool save_load_running;
|
||||
} Engine;
|
||||
|
||||
// Engine lifecycle
|
||||
int engine_init(Engine *engine, const char *client_name);
|
||||
int engine_init(Engine *engine, const char *client_name, DispatchFn dispatch);
|
||||
void engine_cleanup(Engine *engine);
|
||||
int engine_start(Engine *engine);
|
||||
void engine_stop(Engine *engine);
|
||||
|
||||
// Clip management
|
||||
void engine_trigger_clip(Engine *engine, int clip_index);
|
||||
void engine_trigger_scene(Engine *engine, int scene_index);
|
||||
void engine_reset_clip(Engine *engine, int clip_index);
|
||||
|
||||
// Transport
|
||||
void engine_set_quantize_mode(Engine *engine, QuantizeMode mode);
|
||||
void engine_set_quantize_threshold(Engine *engine, jack_nframes_t samples);
|
||||
void engine_transport_play(Engine *engine);
|
||||
void engine_transport_pause(Engine *engine);
|
||||
void engine_transport_stop(Engine *engine);
|
||||
void engine_transport_toggle_play(Engine *engine);
|
||||
void engine_set_clock_source(Engine *engine, ClockSource source);
|
||||
void engine_set_bpm(Engine *engine, double bpm);
|
||||
|
||||
// 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);
|
||||
|
||||
// Initialize command queue (exposed for testing)
|
||||
void command_queue_init(CommandQueue *q);
|
||||
|
||||
// Save/Load queue management
|
||||
void save_load_queue_init(SaveLoadQueue *q);
|
||||
int save_load_queue_push(SaveLoadQueue *q, SaveLoadType type, int clip_index, const char *filename);
|
||||
int save_load_queue_pop(SaveLoadQueue *q, SaveLoadRequest *req);
|
||||
|
||||
// Save/Load thread
|
||||
void* save_load_thread_func(void *arg);
|
||||
int engine_start_save_load_thread(Engine *engine);
|
||||
void engine_stop_save_load_thread(Engine *engine);
|
||||
|
||||
// Utility
|
||||
const char* clip_state_to_string(ClipState state);
|
||||
uint8_t clip_state_to_velocity(ClipState state);
|
||||
const char* quantize_mode_to_string(QuantizeMode mode);
|
||||
|
||||
// Undo/Redo
|
||||
void engine_undo(Engine *engine);
|
||||
void engine_redo(Engine *engine);
|
||||
void engine_push_undo_action(Engine *engine, UndoAction *action);
|
||||
void engine_undo_action(Engine *engine);
|
||||
void engine_redo_action(Engine *engine);
|
||||
|
||||
#endif // ENGINE_H
|
||||
|
||||
Reference in New Issue
Block a user