diff --git a/tests/integration.c b/tests/integration.c index def7767..9314afe 100644 --- a/tests/integration.c +++ b/tests/integration.c @@ -33,6 +33,10 @@ static jack_client_t *midi_inject_client = NULL; static unsigned char midi_inject_note = 0; static unsigned char midi_inject_velocity = 0; +/* Persistent MIDI injection client – avoids race conditions of transient clients */ +static jack_client_t *persistent_midi_client = NULL; +static jack_port_t *persistent_midi_port = NULL; + static void safe_usleep(unsigned int usec) { struct timespec ts; ts.tv_sec = usec / 1000000; @@ -56,6 +60,51 @@ static int midi_inject_process(jack_nframes_t nframes, void *arg) { return 0; } +/* Initialise the persistent MIDI client (must be called once before any send) */ +static int init_persistent_midi_client(void) { + if (persistent_midi_client) return 0; /* already initialised */ + jack_status_t st; + persistent_midi_client = jack_client_open("test_midi_persistent", JackNoStartServer, &st); + if (!persistent_midi_client) return -1; + persistent_midi_port = jack_port_register(persistent_midi_client, "out", + JACK_DEFAULT_MIDI_TYPE, + JackPortIsOutput, 0); + if (!persistent_midi_port) { + jack_client_close(persistent_midi_client); + persistent_midi_client = NULL; + return -1; + } + jack_set_process_callback(persistent_midi_client, midi_inject_process, NULL); + if (jack_activate(persistent_midi_client) != 0) { + jack_client_close(persistent_midi_client); + persistent_midi_client = NULL; + return -1; + } + /* Connect to looper control port */ + if (jack_connect(persistent_midi_client, "test_midi_persistent:out", "looper:control") != 0) { + jack_deactivate(persistent_midi_client); + jack_client_close(persistent_midi_client); + persistent_midi_client = NULL; + return -1; + } + /* Use the persistent port for injection */ + midi_inject_port = persistent_midi_port; + midi_inject_client = persistent_midi_client; + return 0; +} + +/* Clean up the persistent MIDI client at the end */ +static void cleanup_persistent_midi_client(void) { + if (persistent_midi_client) { + jack_deactivate(persistent_midi_client); + jack_client_close(persistent_midi_client); + persistent_midi_client = NULL; + persistent_midi_port = NULL; + midi_inject_port = NULL; + midi_inject_client = NULL; + } +} + /* The test code uses this callback in two ways: - For the audio passthrough test (existing function) it still works. - For the loop test we need a version that respects the static variables @@ -224,49 +273,22 @@ static int test_audio_pass_through(void) { } -/* Helper: open a transient JACK client, send a MIDI note‑on, close */ +/* Helper: send a MIDI note‑on using the persistent client */ static int send_jack_note_on(const char *target_port, unsigned char note, unsigned char velocity) { + (void)target_port; /* connection is already made to looper:control */ + /* Ensure persistent client is initialised */ + if (!persistent_midi_client && init_persistent_midi_client() != 0) { + return -1; + } midi_inject_note = note; midi_inject_velocity = velocity; - - jack_status_t st; - midi_inject_client = jack_client_open("test_midi_inject", JackNoStartServer, &st); - if (!midi_inject_client) return -1; - - midi_inject_port = jack_port_register(midi_inject_client, "out", - JACK_DEFAULT_MIDI_TYPE, - JackPortIsOutput, 0); - if (!midi_inject_port) { - jack_client_close(midi_inject_client); - midi_inject_client = NULL; - return -1; - } - char src[64]; - snprintf(src, sizeof(src), "test_midi_inject:out"); - if (jack_connect(midi_inject_client, src, target_port) != 0) { - jack_client_close(midi_inject_client); - midi_inject_client = NULL; - midi_inject_port = NULL; - return -1; - } - midi_inject_pending = 1; /* signal before activation */ - jack_set_process_callback(midi_inject_client, midi_inject_process, NULL); - if (jack_activate(midi_inject_client) != 0) { - jack_client_close(midi_inject_client); - midi_inject_client = NULL; - midi_inject_port = NULL; - return -1; - } + midi_inject_pending = 1; /* wait for the process callback to clear the flag (event delivered) */ - for (int attempts = 0; attempts < 50; attempts++) { /* ~50 * 10ms = 500ms */ + for (int attempts = 0; attempts < 50; attempts++) { /* ~500ms */ safe_usleep(10000); if (!midi_inject_pending) break; } - jack_deactivate(midi_inject_client); - jack_client_close(midi_inject_client); - midi_inject_client = NULL; - midi_inject_port = NULL; - return 0; + return (midi_inject_pending == 0) ? 0 : -1; } /* @@ -1346,6 +1368,7 @@ int main(void) { failures++; } + cleanup_persistent_midi_client(); if (failures > 0) { fprintf(stderr, "%d test(s) FAILED\n", failures); return 1;