fix: use atomic stores for clip state in dispatcher.c

Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
Loic Coenen
2026-05-05 12:31:34 +00:00
parent fa5bb0a1ad
commit 2429d48376

View File

@@ -127,11 +127,11 @@ AppState* dispatcher_get_state_ptr(void) {
static void save_undo_state(AppState *state, int clip_index) {
int undo_idx = state->undo.undo_index % MAX_UNDO_HISTORY;
state->undo.prev_clip_states[undo_idx] = state->clips[clip_index].state;
state->undo.prev_clip_states[undo_idx] = (ClipState)atomic_load(&state->clips[clip_index].state);
state->undo.prev_clip_indices[undo_idx] = clip_index;
state->undo.prev_buffer_sizes[undo_idx] = state->clips[clip_index].buffer_size;
state->undo.prev_write_positions[undo_idx] = state->clips[clip_index].write_position;
state->undo.prev_read_positions[undo_idx] = state->clips[clip_index].read_position;
state->undo.prev_read_positions[undo_idx] = atomic_load(&state->clips[clip_index].read_position);
state->undo.batch_sizes[undo_idx] = 0; // Will be set by caller
state->undo.undo_index++;
state->undo.redo_index = state->undo.undo_index;
@@ -145,17 +145,19 @@ static void clip_trigger(AppState *state, int clip_index) {
// Do NOT save undo here - caller will do it
switch (clip->state) {
ClipState current_state = (ClipState)atomic_load(&clip->state);
switch (current_state) {
case CLIP_EMPTY:
clip->state = CLIP_RECORDING;
atomic_store(&clip->state, CLIP_RECORDING);
clip->write_position = 0;
clip->buffer_size = 0;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
break;
case CLIP_RECORDING: {
// Transition to looping: copy from ring buffer to clip buffer
clip->state = CLIP_LOOPING;
clip->read_position = 0;
atomic_store(&clip->state, CLIP_LOOPING);
atomic_store(&clip->read_position, 0);
// Determine which channel this clip belongs to
int channel = clip_index % MAX_CHANNELS;
@@ -177,12 +179,12 @@ static void clip_trigger(AppState *state, int clip_index) {
break;
}
case CLIP_LOOPING:
clip->state = CLIP_STOPPED;
clip->read_position = 0;
atomic_store(&clip->state, CLIP_STOPPED);
atomic_store(&clip->read_position, 0);
break;
case CLIP_STOPPED:
clip->state = CLIP_LOOPING;
clip->read_position = 0;
atomic_store(&clip->state, CLIP_LOOPING);
atomic_store(&clip->read_position, 0);
break;
}
}
@@ -192,22 +194,24 @@ static void midi_clip_trigger(AppState *state, int clip_index) {
MidiClip *clip = &state->midi_clips[clip_index];
switch (clip->state) {
ClipState current_state = (ClipState)atomic_load(&clip->state);
switch (current_state) {
case CLIP_EMPTY:
clip->state = CLIP_RECORDING;
atomic_store(&clip->state, CLIP_RECORDING);
clip->event_count = 0;
clip->read_index = 0;
break;
case CLIP_RECORDING:
clip->state = CLIP_LOOPING;
atomic_store(&clip->state, CLIP_LOOPING);
clip->read_index = 0;
break;
case CLIP_LOOPING:
clip->state = CLIP_STOPPED;
atomic_store(&clip->state, CLIP_STOPPED);
clip->read_index = 0;
break;
case CLIP_STOPPED:
clip->state = CLIP_LOOPING;
atomic_store(&clip->state, CLIP_LOOPING);
clip->read_index = 0;
break;
}
@@ -243,10 +247,10 @@ static void clip_reset(AppState *state, int clip_index) {
save_undo_state(state, clip_index);
clip->state = CLIP_EMPTY;
atomic_store(&clip->state, CLIP_EMPTY);
clip->buffer_size = 0;
clip->write_position = 0;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
if (clip->buffer) memset(clip->buffer, 0, MAX_BUFFER_SIZE * sizeof(float));
// Also reset the ring buffer read position for this channel
@@ -269,10 +273,10 @@ static void undo_action(AppState *state) {
if (clip_idx >= 0 && clip_idx < MAX_CLIPS) {
Clip *clip = &state->clips[clip_idx];
clip->state = state->undo.prev_clip_states[current_idx];
atomic_store(&clip->state, state->undo.prev_clip_states[current_idx]);
clip->buffer_size = state->undo.prev_buffer_sizes[current_idx];
clip->write_position = state->undo.prev_write_positions[current_idx];
clip->read_position = state->undo.prev_read_positions[current_idx];
atomic_store(&clip->read_position, state->undo.prev_read_positions[current_idx]);
}
}
@@ -294,25 +298,26 @@ static void redo_action(AppState *state) {
if (clip_idx >= 0 && clip_idx < MAX_CLIPS) {
Clip *clip = &state->clips[clip_idx];
switch (clip->state) {
ClipState current_state = (ClipState)atomic_load(&clip->state);
switch (current_state) {
case CLIP_EMPTY:
clip->state = CLIP_RECORDING;
atomic_store(&clip->state, CLIP_RECORDING);
clip->write_position = 0;
clip->buffer_size = 0;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
break;
case CLIP_RECORDING:
clip->state = CLIP_LOOPING;
atomic_store(&clip->state, CLIP_LOOPING);
clip->buffer_size = clip->write_position;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
break;
case CLIP_LOOPING:
clip->state = CLIP_STOPPED;
clip->read_position = 0;
atomic_store(&clip->state, CLIP_STOPPED);
atomic_store(&clip->read_position, 0);
break;
case CLIP_STOPPED:
clip->state = CLIP_LOOPING;
clip->read_position = 0;
atomic_store(&clip->state, CLIP_LOOPING);
atomic_store(&clip->read_position, 0);
break;
}
}
@@ -430,10 +435,10 @@ void reducer(AppState *state, Action action) {
if (clip->buffer) {
size_t copy_size = (num_samples < MAX_BUFFER_SIZE) ? num_samples : MAX_BUFFER_SIZE;
memcpy(clip->buffer, new_buffer, copy_size * sizeof(float));
clip->state = CLIP_LOOPING;
atomic_store(&clip->state, CLIP_LOOPING);
clip->buffer_size = copy_size;
clip->write_position = copy_size;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
printf("Loaded clip %d from %s\n", clip_idx, action.data.load_clip.filename);
}
free(new_buffer);
@@ -516,7 +521,7 @@ void reducer(AppState *state, Action action) {
case ACTION_MIDI_CLIP_RESET: {
int idx = action.data.midi_clip_reset.clip_index;
if (idx >= 0 && idx < MAX_CLIPS) {
state->midi_clips[idx].state = CLIP_EMPTY;
atomic_store(&state->midi_clips[idx].state, CLIP_EMPTY);
state->midi_clips[idx].event_count = 0;
state->midi_clips[idx].read_index = 0;
// Don't free events here - just reset count
@@ -542,10 +547,10 @@ void reducer(AppState *state, Action action) {
// Reset clips first
for (int i = 0; i < MAX_CLIPS; i++) {
Clip *clip = &state->clips[i];
clip->state = CLIP_EMPTY;
atomic_store(&clip->state, CLIP_EMPTY);
clip->buffer_size = 0;
clip->write_position = 0;
clip->read_position = 0;
atomic_store(&clip->read_position, 0);
if (clip->buffer) {
memset(clip->buffer, 0, MAX_BUFFER_SIZE * sizeof(float));
} else {
@@ -554,7 +559,7 @@ void reducer(AppState *state, Action action) {
// NEW: Reset midi clips
MidiClip *mclip = &state->midi_clips[i];
mclip->state = CLIP_EMPTY;
atomic_store(&mclip->state, CLIP_EMPTY);
mclip->event_count = 0;
mclip->read_index = 0;
mclip->max_events = MAX_MIDI_EVENTS;
@@ -645,6 +650,7 @@ DispatchFn dispatcher_init(AppState *initial_state) {
dispatcher.state.midi_clips[i].events = (MidiEvent *)calloc(MAX_MIDI_EVENTS, sizeof(MidiEvent));
dispatcher.state.midi_clips[i].max_events = MAX_MIDI_EVENTS;
}
atomic_store(&dispatcher.state.midi_clips[i].state, CLIP_EMPTY);
}
atomic_store(&dispatcher.running, false);
@@ -673,6 +679,7 @@ void dispatcher_stop(void) {
for (int i = 0; i < MAX_CLIPS; i++) {
free(dispatcher.state.midi_clips[i].events);
dispatcher.state.midi_clips[i].events = NULL;
atomic_store(&dispatcher.state.midi_clips[i].state, CLIP_EMPTY);
}
pthread_mutex_lock(&dispatcher.subscribers_mutex);