feat: add transport.h header with transport state machine and MIDI clock support

Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
Loic Coenen
2026-05-01 21:14:26 +00:00
parent ca2c8de12f
commit 6d52e076dc

92
transport.h Normal file
View File

@@ -0,0 +1,92 @@
#ifndef TRANSPORT_H
#define TRANSPORT_H
#include <jack/jack.h>
#include <jack/midiport.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#define MIDI_CLOCKS_PER_BEAT 24
#define BEATS_PER_BAR 4
#define DEFAULT_BPM 120.0
typedef enum {
TRANSPORT_STOPPED,
TRANSPORT_PLAYING,
TRANSPORT_PAUSED
} TransportState;
typedef enum {
CLOCK_SOURCE_INTERNAL, // Master clock
CLOCK_SOURCE_MIDI // Slave to external MIDI clock
} ClockSource;
typedef struct {
// State
TransportState state;
ClockSource clock_source;
// Position
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
// Internal clock generation
double bpm;
double samples_per_beat;
double sample_accumulator; // For precise BPM timing
// Atomic mirrors for frontend reads
atomic_int state_atomic; // TransportState
atomic_uint clock_count_atomic;
atomic_uint beat_position_atomic;
atomic_uint bar_position_atomic;
atomic_uint sample_position_atomic;
atomic_int clock_source_atomic; // ClockSource
atomic_double bpm_atomic;
// JACK ports for MIDI clock output (when master)
jack_port_t *midi_clock_out_port;
// Reference to engine for sample rate
jack_nframes_t sample_rate;
} Transport;
// Lifecycle
void transport_init(Transport *transport, jack_nframes_t sample_rate);
void transport_cleanup(Transport *transport);
// Control
void transport_play(Transport *transport);
void transport_pause(Transport *transport);
void transport_stop(Transport *transport);
void transport_toggle_play(Transport *transport);
// Clock source
void transport_set_clock_source(Transport *transport, ClockSource source);
ClockSource transport_get_clock_source(Transport *transport);
// BPM (only relevant for internal clock)
void transport_set_bpm(Transport *transport, double bpm);
double transport_get_bpm(Transport *transport);
// Process function called from audio thread
// Returns number of MIDI clock ticks generated (for master mode)
int transport_process(Transport *transport, jack_nframes_t nframes,
void *midi_clock_in_buf, void *midi_clock_out_buf);
// Reset position
void transport_reset(Transport *transport);
// Get next quantization boundary (in frames from current position)
jack_nframes_t transport_get_next_quantize_frame(Transport *transport,
jack_nframes_t current_frame,
QuantizeMode mode);
// Utility
const char* transport_state_to_string(TransportState state);
const char* clock_source_to_string(ClockSource source);
#endif // TRANSPORT_H