feat: add mock JACK test target and unit tests for carla host

This commit is contained in:
Loic Coenen
2026-05-17 10:18:58 +00:00
parent e6e0a47749
commit d28e1f45f5
7 changed files with 247 additions and 105 deletions

View File

@@ -4,48 +4,56 @@
#include "command.h"
#include "midi.h"
#include "queue.h"
#include <jack/jack.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include <math.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define STATUS_FIFO "/tmp/looper_status"
static void looper_write_status(void) {
int fd = open(STATUS_FIFO, O_WRONLY | O_NONBLOCK);
if (fd < 0)
return;
struct channel_t *cur = get_channels_array();
int cap = atomic_load(&channel_capacity);
char buf[256];
for (int ch = 0; ch < cap; ch++) {
if (!atomic_load(&cur[ch].active))
continue;
int sc_idx = atomic_load(&cur[ch].current_scene);
int state = atomic_load(&cur[ch].scenes[sc_idx].state);
const char *state_str;
switch (state) {
case STATE_IDLE: state_str = "IDLE"; break;
case STATE_RECORD: state_str = "RECORD"; break;
case STATE_LOOPING: state_str = "LOOPING"; break;
case STATE_PAUSED: state_str = "PAUSED"; break;
default: state_str = "UNKNOWN";
}
int n = snprintf(buf, sizeof(buf),
"CH=%d SC=%d STATE=%s\n",
ch, sc_idx, state_str);
if (n > 0) {
int ret = write(fd, buf, n);
(void)ret;
}
int fd = open(STATUS_FIFO, O_WRONLY | O_NONBLOCK);
if (fd < 0)
return;
struct channel_t *cur = get_channels_array();
int cap = atomic_load(&channel_capacity);
char buf[256];
for (int ch = 0; ch < cap; ch++) {
if (!atomic_load(&cur[ch].active))
continue;
int sc_idx = atomic_load(&cur[ch].current_scene);
int state = atomic_load(&cur[ch].scenes[sc_idx].state);
const char *state_str;
switch (state) {
case STATE_IDLE:
state_str = "IDLE";
break;
case STATE_RECORD:
state_str = "RECORD";
break;
case STATE_LOOPING:
state_str = "LOOPING";
break;
case STATE_PAUSED:
state_str = "PAUSED";
break;
default:
state_str = "UNKNOWN";
}
close(fd);
int n = snprintf(buf, sizeof(buf), "CH=%d SC=%d STATE=%s\n", ch, sc_idx,
state_str);
if (n > 0) {
int ret = write(fd, buf, n);
(void)ret;
}
}
close(fd);
}
/* Global state (shared across files) */
@@ -252,8 +260,7 @@ int process_callback(jack_nframes_t nframes, void *arg) {
if (rp < MAX_MIDI_EVENTS) {
sc->loop.midi_events[rp].timestamp = ev.time;
sc->loop.midi_events[rp].status = ev.buffer[0];
sc->loop.midi_events[rp].note =
(ev.size > 1) ? ev.buffer[1] : 0;
sc->loop.midi_events[rp].note = (ev.size > 1) ? ev.buffer[1] : 0;
sc->loop.midi_events[rp].velocity =
(ev.size > 2) ? ev.buffer[2] : 0;
atomic_store(&sc->record_pos, rp + 1);
@@ -295,23 +302,22 @@ int process_callback(jack_nframes_t nframes, void *arg) {
/* no output */
break;
default: /* IDLE */
{
void *midi_in_buf =
jack_port_get_buffer(active_channels[c].midi_in, nframes);
void *midi_out_buf =
jack_port_get_buffer(active_channels[c].midi_out, nframes);
if (midi_in_buf && midi_out_buf) {
jack_midi_clear_buffer(midi_out_buf);
jack_nframes_t nevents = jack_midi_get_event_count(midi_in_buf);
jack_midi_event_t ev;
for (jack_nframes_t j = 0; j < nevents; j++) {
if (jack_midi_event_get(&ev, midi_in_buf, j) != 0)
continue;
jack_midi_event_write(midi_out_buf, ev.time, ev.buffer, ev.size);
}
{
void *midi_in_buf =
jack_port_get_buffer(active_channels[c].midi_in, nframes);
void *midi_out_buf =
jack_port_get_buffer(active_channels[c].midi_out, nframes);
if (midi_in_buf && midi_out_buf) {
jack_midi_clear_buffer(midi_out_buf);
jack_nframes_t nevents = jack_midi_get_event_count(midi_in_buf);
jack_midi_event_t ev;
for (jack_nframes_t j = 0; j < nevents; j++) {
if (jack_midi_event_get(&ev, midi_in_buf, j) != 0)
continue;
jack_midi_event_write(midi_out_buf, ev.time, ev.buffer, ev.size);
}
}
break;
} break;
}
if (state == STATE_LOOPING) {
atomic_store(&sc->loop_count, atomic_load(&sc->record_pos));