test: add MIDI stop and full record-loop-stop integration tests
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
@@ -909,6 +909,207 @@ static int test_fifo_pipe(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* test stop via MIDI (control key + note 65) */
|
||||
static int test_stop_midi(void) {
|
||||
printf("Test: MIDI stop (note 65 under control key)\n");
|
||||
pid_t pid = start_looper();
|
||||
if (pid < 0) return 1;
|
||||
jack_client_t *client;
|
||||
jack_status_t status;
|
||||
client = jack_client_open("test_stop", JackNoStartServer, &status);
|
||||
if (!client) {
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " SKIP: no JACK\n");
|
||||
return 1;
|
||||
}
|
||||
jack_port_t *audio_out = jack_port_register(client, "out",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
jack_port_t *audio_in = jack_port_register(client, "in",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput, 0);
|
||||
if (!audio_out || !audio_in) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
char my_out[64], my_in[64];
|
||||
snprintf(my_out, sizeof(my_out), "test_stop:out");
|
||||
snprintf(my_in, sizeof(my_in), "test_stop:in");
|
||||
if (jack_connect(client, my_out, "looper:input") ||
|
||||
jack_connect(client, "looper:output", my_in)) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
/* start recording: send note 1 */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: send note1 failed\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(0.2f * sr); /* 0.2s beep while recording */
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
passthrough_output_port = audio_out;
|
||||
passthrough_input_port = audio_in;
|
||||
passthrough_phase = 0.0f;
|
||||
passthrough_freq = 440.0f;
|
||||
passthrough_sample_rate = sr;
|
||||
passthrough_total_samples = 0;
|
||||
passthrough_sum_sq = 0.0;
|
||||
passthrough_done = 0;
|
||||
jack_set_process_callback(client, passthrough_process, NULL);
|
||||
if (jack_activate(client)) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(150000);
|
||||
/* loop: send note 1 again */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: loop note1\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(500000);
|
||||
/* stop: control key then note 65 */
|
||||
if (send_jack_note_on("looper:control", 64, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: control key\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
if (send_jack_note_on("looper:control", 65, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: stop note 65\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
int bursts_before = bursts;
|
||||
safe_usleep(500000);
|
||||
int bursts_after = bursts;
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM);
|
||||
waitpid(pid, NULL, 0);
|
||||
if (bursts_after > bursts_before) {
|
||||
fprintf(stderr, " FAIL: bursts continued after stop (%d -> %d)\n",
|
||||
bursts_before, bursts_after);
|
||||
return 1;
|
||||
}
|
||||
printf(" PASS (stop stopped playback)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* full flow: record 1s, loop 5 times, stop, verify at least 5 bursts */
|
||||
static int test_record_loop_stop(void) {
|
||||
printf("Test: full record‑loop‑stop (≥5 repetitions)\n");
|
||||
pid_t pid = start_looper();
|
||||
if (pid < 0) return 1;
|
||||
jack_client_t *client;
|
||||
jack_status_t status;
|
||||
client = jack_client_open("test_full", JackNoStartServer, &status);
|
||||
if (!client) {
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " SKIP: no JACK\n");
|
||||
return 1;
|
||||
}
|
||||
jack_port_t *audio_out = jack_port_register(client, "out",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
jack_port_t *audio_in = jack_port_register(client, "in",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput, 0);
|
||||
if (!audio_out || !audio_in) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
char my_out[64], my_in[64];
|
||||
snprintf(my_out, sizeof(my_out), "test_full:out");
|
||||
snprintf(my_in, sizeof(my_in), "test_full:in");
|
||||
if (jack_connect(client, my_out, "looper:input") ||
|
||||
jack_connect(client, "looper:output", my_in)) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
/* start recording */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: send note1\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(500000);
|
||||
/* generate a 0.5 s beep while recording */
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(0.5f * sr);
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
passthrough_output_port = audio_out;
|
||||
passthrough_input_port = audio_in;
|
||||
passthrough_phase = 0.0f;
|
||||
passthrough_freq = 440.0f;
|
||||
passthrough_sample_rate = sr;
|
||||
passthrough_total_samples = 0;
|
||||
passthrough_sum_sq = 0.0;
|
||||
passthrough_done = 0;
|
||||
jack_set_process_callback(client, passthrough_process, NULL);
|
||||
if (jack_activate(client)) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
/* end recording -> loop */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: loop note1\n");
|
||||
return 1;
|
||||
}
|
||||
/* wait for about 5 loops (assuming 0.5s recorded -> ~2.5s loop) */
|
||||
safe_usleep(2500000);
|
||||
/* stop via control+65 */
|
||||
if (send_jack_note_on("looper:control", 64, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: control key\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
if (send_jack_note_on("looper:control", 65, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: stop note 65\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
int total_bursts = bursts;
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM);
|
||||
waitpid(pid, NULL, 0);
|
||||
if (total_bursts < 5) {
|
||||
fprintf(stderr, " FAIL: expected ≥5 bursts, got %d\n", total_bursts);
|
||||
return 1;
|
||||
}
|
||||
printf(" PASS (≥5 repetitions, stopped cleanly)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
/* 1. binary must exist */
|
||||
if (system("test -x ./looper") != 0) {
|
||||
@@ -965,6 +1166,18 @@ int main(void) {
|
||||
failures++;
|
||||
}
|
||||
|
||||
/* 11. Test MIDI stop */
|
||||
if (test_stop_midi() != 0) {
|
||||
fprintf(stderr, " FAILED\n");
|
||||
failures++;
|
||||
}
|
||||
|
||||
/* 12. Test full record‑loop‑stop flow */
|
||||
if (test_record_loop_stop() != 0) {
|
||||
fprintf(stderr, " FAILED\n");
|
||||
failures++;
|
||||
}
|
||||
|
||||
if (failures > 0) {
|
||||
fprintf(stderr, "%d test(s) FAILED\n", failures);
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user