refactor: replace writer thread with synchronous save and fix ring buffer memory ordering
This commit is contained in:
committed by
Loic Coenen (aider)
parent
10e47e6c0c
commit
f38797fe0a
@@ -11,6 +11,7 @@
|
||||
#include <jack/midiport.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sndfile.h>
|
||||
|
||||
/* static variables for passthrough test */
|
||||
static jack_port_t *passthrough_output_port = NULL;
|
||||
@@ -333,20 +334,12 @@ static int test_looper_looping(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* first note‑on: IDLE -> RECORD */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(500000); /* allow state to change (500ms) */
|
||||
|
||||
/* connect audio and activate immediately */
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0; /* disable continuous tone */
|
||||
beep_remaining = (int)(0.1f * sr); /* 0.1 second beep */
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(3.0f * sr); /* 3 sec beep – covers entire recording */
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
|
||||
passthrough_output_port = audio_out;
|
||||
passthrough_input_port = audio_in;
|
||||
passthrough_phase = 0.0f;
|
||||
@@ -355,7 +348,6 @@ static int test_looper_looping(void) {
|
||||
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);
|
||||
@@ -363,19 +355,23 @@ static int test_looper_looping(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
safe_usleep(150000); /* let beep start */
|
||||
|
||||
/* ensure beep is fully captured */
|
||||
safe_usleep(800000); /* 0.8s after start of beep */
|
||||
/* first note‑on: IDLE -> RECORD */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(3000000); /* 3s to capture beep */
|
||||
|
||||
/* second note‑on: RECORD -> LOOPING */
|
||||
if (send_jack_note_on("looper:control", 1, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* wait enough time for several loops (4 seconds to be safe) */
|
||||
safe_usleep(4000000);
|
||||
/* wait for several loop repetitions */
|
||||
safe_usleep(8000000); /* 8 seconds listen */
|
||||
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
@@ -504,7 +500,7 @@ static int test_control_key_modifier(void) {
|
||||
/* Wait for looper to enter RECORD and detect audio */
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(0.1f * sr); /* 0.1 second beep */
|
||||
beep_remaining = (int)(0.5f * sr); /* 0.5 sec beep (was 0.1) */
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
passthrough_output_port = audio_out;
|
||||
@@ -517,26 +513,30 @@ static int test_control_key_modifier(void) {
|
||||
passthrough_done = 0;
|
||||
jack_set_process_callback(client, passthrough_process, NULL);
|
||||
if (jack_activate(client)) {
|
||||
fprintf(stderr, " FAIL: cannot activate test client\n");
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000); /* allow beep */
|
||||
/* send note 62 again under control key to move RECORD->LOOPING */
|
||||
safe_usleep(500000); /* allow beep to start */
|
||||
|
||||
/* second note 64 + note 62 to move RECORD → LOOPING */
|
||||
if (send_jack_note_on("looper:control", 64, 127) != 0) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: control key re‑send\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
safe_usleep(500000);
|
||||
if (send_jack_note_on("looper:control", 62, 127) != 0) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: send note 62 for loop\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(2000000);
|
||||
safe_usleep(5000000); /* listen for 5 seconds */
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM);
|
||||
@@ -619,7 +619,7 @@ static int test_bind_channel(void) {
|
||||
/* Wait and detect bursts as before */
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(0.1f * sr);
|
||||
beep_remaining = (int)(0.5f * sr); /* 0.5 sec beep (was 0.1) */
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
passthrough_output_port = audio_out;
|
||||
@@ -632,26 +632,30 @@ static int test_bind_channel(void) {
|
||||
passthrough_done = 0;
|
||||
jack_set_process_callback(client, passthrough_process, NULL);
|
||||
if (jack_activate(client)) {
|
||||
fprintf(stderr, " FAIL: cannot activate test client\n");
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000); /* allow beep */
|
||||
/* send control+note62 again to move RECORD->LOOPING */
|
||||
safe_usleep(500000); /* allow beep to start */
|
||||
|
||||
/* second note 64 + note 62 to move RECORD → LOOPING */
|
||||
if (send_jack_note_on("looper:control", 64, 127) != 0) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: control key for loop\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
safe_usleep(500000);
|
||||
if (send_jack_note_on("looper:control", 62, 127) != 0) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: toggle for loop\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(2000000);
|
||||
safe_usleep(5000000); /* listen for 5 seconds */
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM);
|
||||
@@ -749,7 +753,7 @@ static int test_bind_unbind(void) {
|
||||
/* Wait for beep and loop */
|
||||
int sr = jack_get_sample_rate(client);
|
||||
continuous_sine = 0;
|
||||
beep_remaining = (int)(0.1f * sr);
|
||||
beep_remaining = (int)(0.5f * sr); /* 0.5 sec beep (was 0.1) */
|
||||
bursts = 0;
|
||||
prev_above = 0;
|
||||
passthrough_output_port = audio_out;
|
||||
@@ -766,7 +770,7 @@ static int test_bind_unbind(void) {
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000); /* allow beep */
|
||||
safe_usleep(1000000); /* allow recording to start before we set beep */
|
||||
/* second control+62 -> loop */
|
||||
if (send_jack_note_on("looper:control", 64, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
@@ -774,7 +778,7 @@ static int test_bind_unbind(void) {
|
||||
fprintf(stderr, " FAIL: control key for loop\n");
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(200000);
|
||||
safe_usleep(2000000); /* give time to record beep */
|
||||
if (send_jack_note_on("looper:control", 62, 127) != 0) {
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
@@ -882,38 +886,17 @@ static int test_remove_channel(void) {
|
||||
* Helper: generate a simple 440 Hz WAV file for load tests
|
||||
* ------------------------------------------------------------ */
|
||||
static int generate_test_wav(const char *path, unsigned sample_rate, unsigned duration_frames) {
|
||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) return -1;
|
||||
unsigned data_bytes = duration_frames * 2;
|
||||
unsigned file_size = 44 + data_bytes;
|
||||
unsigned char header[44];
|
||||
memset(header, 0, 44);
|
||||
memcpy(header, "RIFF", 4);
|
||||
unsigned chunk_size = file_size - 8;
|
||||
header[4] = chunk_size & 0xff; header[5] = (chunk_size>>8)&0xff;
|
||||
header[6] = (chunk_size>>16)&0xff; header[7] = (chunk_size>>24)&0xff;
|
||||
memcpy(header+8, "WAVE", 4);
|
||||
memcpy(header+12, "fmt ", 4);
|
||||
header[16]=16; header[17]=0; header[18]=0; header[19]=0;
|
||||
header[20]=1; header[21]=0; /* PCM */
|
||||
header[22]=1; header[23]=0; /* mono */
|
||||
header[24]= sample_rate & 0xff; header[25]=(sample_rate>>8)&0xff;
|
||||
header[26]=(sample_rate>>16)&0xff; header[27]=(sample_rate>>24)&0xff;
|
||||
unsigned br = sample_rate * 2;
|
||||
header[28]= br & 0xff; header[29]=(br>>8)&0xff;
|
||||
header[30]=(br>>16)&0xff; header[31]=(br>>24)&0xff;
|
||||
header[32]=2; header[33]=0;
|
||||
header[34]=16; header[35]=0;
|
||||
memcpy(header+36, "data", 4);
|
||||
header[40]= data_bytes & 0xff; header[41]=(data_bytes>>8)&0xff;
|
||||
header[42]=(data_bytes>>16)&0xff; header[43]=(data_bytes>>24)&0xff;
|
||||
if (write(fd, header, 44) != 44) { close(fd); return -1; }
|
||||
SF_INFO info;
|
||||
info.samplerate = sample_rate;
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||
SNDFILE *sf = sf_open(path, SFM_WRITE, &info);
|
||||
if (!sf) return -1;
|
||||
for (unsigned i = 0; i < duration_frames; i++) {
|
||||
float sample = sinf(2.0f * (float)M_PI * 440.0f * i / sample_rate);
|
||||
int16_t s = (int16_t)(sample * 32767);
|
||||
if (write(fd, &s, 2) != 2) { close(fd); return -1; }
|
||||
sf_writef_float(sf, &sample, 1);
|
||||
}
|
||||
close(fd);
|
||||
sf_close(sf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1062,15 +1045,17 @@ static int test_wav_save(void) {
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(800000);
|
||||
/* stop recording (cycle again) */
|
||||
safe_usleep(3000000); /* record for 3s (ensure enough beep) */
|
||||
|
||||
/* Send second record command to transition RECORD → LOOPING */
|
||||
if (send_fifo_command("record 0") != 0) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(500000);
|
||||
safe_usleep(1000000); /* give time for state change and loop_count to be set */
|
||||
|
||||
/* save */
|
||||
if (send_fifo_command("save") != 0) {
|
||||
jack_deactivate(client);
|
||||
@@ -1078,16 +1063,28 @@ static int test_wav_save(void) {
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
safe_usleep(2000000);
|
||||
/* check save.wav */
|
||||
int fd = open("save.wav", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
safe_usleep(8000000); /* wait for synchronous save to complete (8s) */
|
||||
|
||||
/* check save.wav with retries */
|
||||
int saved = 0;
|
||||
for (int retry = 0; retry < 5; retry++) {
|
||||
int fd = open("save.wav", O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
saved = 1;
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
safe_usleep(1000000);
|
||||
}
|
||||
if (!saved) {
|
||||
jack_deactivate(client);
|
||||
jack_client_close(client);
|
||||
kill(pid, SIGTERM); waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, " FAIL: save.wav not created\n");
|
||||
return 1;
|
||||
}
|
||||
/* verify header */
|
||||
int fd = open("save.wav", O_RDONLY);
|
||||
unsigned char hdr[44];
|
||||
if (read(fd, hdr, 44) != 44) {
|
||||
close(fd); unlink("save.wav");
|
||||
|
||||
Reference in New Issue
Block a user