151 lines
4.2 KiB
C
151 lines
4.2 KiB
C
#ifndef ENGINE_H
|
|
#define ENGINE_H
|
|
|
|
#include <jack/jack.h>
|
|
#include <jack/midiport.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdatomic.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
|
|
#define MIDI_CLOCKS_PER_BEAT 24
|
|
#define BEATS_PER_BAR 4
|
|
|
|
// 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 {
|
|
bool rolling;
|
|
uint32_t clock_count;
|
|
uint32_t beat_position; // 0-3
|
|
uint32_t bar_position;
|
|
uint32_t sample_position; // derived from clock at current sample rate
|
|
} TransportState;
|
|
|
|
typedef struct {
|
|
ClipState state;
|
|
float *buffer;
|
|
size_t buffer_size;
|
|
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
|
|
|
|
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;
|
|
bool is_scene;
|
|
jack_nframes_t trigger_time;
|
|
struct QueuedTrigger *next;
|
|
} QueuedTrigger;
|
|
|
|
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_out_port;
|
|
|
|
Clip clips[MAX_CLIPS];
|
|
int control_channel;
|
|
jack_nframes_t sample_rate;
|
|
|
|
// Transport and clock
|
|
TransportState transport;
|
|
bool clock_sync_enabled;
|
|
|
|
// 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 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;
|
|
|
|
// Engine lifecycle
|
|
int engine_init(Engine *engine, const char *client_name);
|
|
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_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);
|
|
const char* quantize_mode_to_string(QuantizeMode mode);
|
|
|
|
#endif // ENGINE_H
|