Files
looper/tests/integration.c
Loic Coenen 2d4f4ec18e fix: add missing stdarg.h include and jack_midi_send availability check
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
2026-05-07 20:35:52 +00:00

123 lines
4.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <stdarg.h>
/*
* Integration test for the JACK looper.
*
* 1. Start the looper binary (./looper)
* 2. Wait for JACK ports to appear
* 3. Send several noteon messages (MIDI note number 1) to its 'control' port
* using jack_midi_send, testing the state machine:
* IDLE → RECORD → LOOPING → PAUSED → LOOPING → PAUSED (toggle)
* 4. Send a MIDI clock Start (0xFA) to force IDLE → RECORD.
* 5. Send a MIDI clock Stop (0xFC) to force RECORD → IDLE.
* 6. Send a MIDI clock Continue (0xFB) to resume LOOPING from PAUSED.
* 7. Kill the process and check that it exits cleanly.
*/
#define WAIT_SECONDS 1
static int run_cmd(const char *fmt, ...) {
char buf[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return system(buf);
}
int main(void) {
/* 1. binary must exist */
if (system("test -x ./looper") != 0) {
fprintf(stderr, "FATAL: looper binary not found\n");
return 1;
}
/* 2. start the looper */
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid == 0) {
execl("./looper", "looper", NULL);
perror("execl");
_exit(1);
}
printf("Waiting for looper (pid %d) to register ports...\n", (int)pid);
sleep(3); /* generous, JACK ports must be visible */
/* check jack_midi_send availability */
if (system("which jack_midi_send >/dev/null 2>&1") != 0) {
fprintf(stderr, "FATAL: jack_midi_send not available (install jacktools)\n");
kill(pid, SIGTERM);
waitpid(pid, NULL, 0);
return 1;
}
/* 3. send noteon messages (toggle state machine) */
printf("Sending first noteon → IDLE → RECORD\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending second noteon → RECORD → LOOPING\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending third noteon → LOOPING → PAUSED\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending fourth noteon → PAUSED → LOOPING\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
printf("Sending fifth noteon → LOOPING → PAUSED (toggle)\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(WAIT_SECONDS);
/* 4. MIDI clock start (0xFA) IDLE → RECORD */
printf("Sending MIDI clock Start (0xFA)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FA' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* 5. MIDI clock stop (0xFC) RECORD → IDLE */
printf("Sending MIDI clock Stop (0xFC)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FC' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* bring back to PAUSED via control port */
printf("Sending noteon to reach PAUSED again\n");
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
run_cmd("jack_midi_send -c looper:control -m '90 01 7f' 2>/dev/null || echo 'jack_midi_send not available'"); // now PAUSED
sleep(1);
/* 6. MIDI clock Continue (0xFB) PAUSED → LOOPING */
printf("Sending MIDI clock Continue (0xFB)\n");
run_cmd("jack_midi_send -c looper:clock -m 'FB' 2>/dev/null || echo 'jack_midi_send not available'");
sleep(1);
/* cleanup */
printf("Terminating looper...\n");
kill(pid, SIGTERM);
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Looper exited with status %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Looper terminated by signal %d\n", WTERMSIG(status));
}
printf("Integration test finished (manual verification recommended)\n");
return 0;
}