fix: make channel state variables atomic to eliminate data races
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
@@ -19,11 +19,11 @@ typedef enum {
|
|||||||
|
|
||||||
struct channel_t {
|
struct channel_t {
|
||||||
atomic_int state;
|
atomic_int state;
|
||||||
int prev_state;
|
atomic_int prev_state;
|
||||||
float loop_buffer[LOOP_BUF_SIZE];
|
float loop_buffer[LOOP_BUF_SIZE];
|
||||||
atomic_int loop_count;
|
atomic_int loop_count;
|
||||||
int record_pos;
|
atomic_int record_pos;
|
||||||
int playback_pos;
|
atomic_int playback_pos;
|
||||||
atomic_int active;
|
atomic_int active;
|
||||||
jack_port_t *audio_in;
|
jack_port_t *audio_in;
|
||||||
jack_port_t *audio_out;
|
jack_port_t *audio_out;
|
||||||
|
|||||||
36
src/looper.c
36
src/looper.c
@@ -68,16 +68,16 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
|
|
||||||
int state = atomic_load(&channels[c].state);
|
int state = atomic_load(&channels[c].state);
|
||||||
|
|
||||||
if (state != channels[c].prev_state) {
|
if (state != atomic_load(&channels[c].prev_state)) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_RECORD:
|
case STATE_RECORD:
|
||||||
channels[c].record_pos = 0;
|
atomic_store(&channels[c].record_pos, 0);
|
||||||
atomic_store(&channels[c].loop_count, 0);
|
atomic_store(&channels[c].loop_count, 0);
|
||||||
break;
|
break;
|
||||||
case STATE_LOOPING:
|
case STATE_LOOPING:
|
||||||
if (channels[c].prev_state == STATE_RECORD && channels[c].record_pos > 0)
|
if (atomic_load(&channels[c].prev_state) == STATE_RECORD && atomic_load(&channels[c].record_pos) > 0)
|
||||||
atomic_store(&channels[c].loop_count, channels[c].record_pos);
|
atomic_store(&channels[c].loop_count, atomic_load(&channels[c].record_pos));
|
||||||
channels[c].playback_pos = 0;
|
atomic_store(&channels[c].playback_pos, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -91,9 +91,9 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
float *f_out = (float *)out;
|
float *f_out = (float *)out;
|
||||||
const float *f_in = (const float *)in;
|
const float *f_in = (const float *)in;
|
||||||
for (i = 0; i < nframes; i++) {
|
for (i = 0; i < nframes; i++) {
|
||||||
if (channels[c].record_pos < LOOP_BUF_SIZE)
|
int rp = atomic_fetch_add(&channels[c].record_pos, 1);
|
||||||
channels[c].loop_buffer[channels[c].record_pos++] =
|
if (rp < LOOP_BUF_SIZE)
|
||||||
f_in[i];
|
channels[c].loop_buffer[rp] = f_in[i];
|
||||||
f_out[i] = f_in[i];
|
f_out[i] = f_in[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -106,9 +106,9 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
if (lc > 0) {
|
if (lc > 0) {
|
||||||
float *outf = (float *)out;
|
float *outf = (float *)out;
|
||||||
for (i = 0; i < nframes; i++) {
|
for (i = 0; i < nframes; i++) {
|
||||||
outf[i] = channels[c].loop_buffer[channels[c].playback_pos];
|
int pp = atomic_load(&channels[c].playback_pos);
|
||||||
channels[c].playback_pos =
|
outf[i] = channels[c].loop_buffer[pp];
|
||||||
(channels[c].playback_pos + 1) % lc;
|
atomic_store(&channels[c].playback_pos, (pp + 1) % lc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
||||||
@@ -137,7 +137,7 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channels[c].prev_state = state;
|
atomic_store(&channels[c].prev_state, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI clock events – affect channel 0 only */
|
/* MIDI clock events – affect channel 0 only */
|
||||||
@@ -197,10 +197,10 @@ int looper_init(jack_client_t *client) {
|
|||||||
/* channel 0 */
|
/* channel 0 */
|
||||||
channels[0].active = 1;
|
channels[0].active = 1;
|
||||||
atomic_store(&channels[0].state, STATE_IDLE);
|
atomic_store(&channels[0].state, STATE_IDLE);
|
||||||
channels[0].prev_state = -1;
|
atomic_store(&channels[0].prev_state, -1);
|
||||||
channels[0].loop_count = 0;
|
channels[0].loop_count = 0;
|
||||||
channels[0].record_pos = 0;
|
atomic_store(&channels[0].record_pos, 0);
|
||||||
channels[0].playback_pos = 0;
|
atomic_store(&channels[0].playback_pos, 0);
|
||||||
atomic_store_explicit(&channels[0].save_ring, NULL, memory_order_release);
|
atomic_store_explicit(&channels[0].save_ring, NULL, memory_order_release);
|
||||||
|
|
||||||
channels[0].audio_in = jack_port_register(
|
channels[0].audio_in = jack_port_register(
|
||||||
@@ -312,10 +312,10 @@ void looper_process_commands(jack_client_t *client) {
|
|||||||
if (frames > LOOP_BUF_SIZE) frames = LOOP_BUF_SIZE;
|
if (frames > LOOP_BUF_SIZE) frames = LOOP_BUF_SIZE;
|
||||||
memcpy(channels[0].loop_buffer, buf, frames * sizeof(float));
|
memcpy(channels[0].loop_buffer, buf, frames * sizeof(float));
|
||||||
atomic_store(&channels[0].loop_count, (int)frames);
|
atomic_store(&channels[0].loop_count, (int)frames);
|
||||||
channels[0].record_pos = 0;
|
atomic_store(&channels[0].record_pos, 0);
|
||||||
channels[0].playback_pos = 0;
|
atomic_store(&channels[0].playback_pos, 0);
|
||||||
atomic_store(&channels[0].state, STATE_LOOPING);
|
atomic_store(&channels[0].state, STATE_LOOPING);
|
||||||
channels[0].prev_state = -1;
|
atomic_store(&channels[0].prev_state, -1);
|
||||||
free(buf);
|
free(buf);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Failed to load loop.wav\n");
|
fprintf(stderr, "Failed to load loop.wav\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user