fix: deep-copy audio buffers and add mutex to prevent race conditions in autosave
Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
21
fs.c
21
fs.c
@@ -74,6 +74,19 @@ static void* autosave_thread_func(void *arg) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep-copy the audio buffers to avoid race conditions
|
||||||
|
float *buffer_copies[MAX_CLIPS] = {NULL};
|
||||||
|
for (int i = 0; i < MAX_CLIPS; i++) {
|
||||||
|
if (state.clips[i].buffer != NULL && state.clips[i].buffer_size > 0) {
|
||||||
|
buffer_copies[i] = (float *)malloc(state.clips[i].buffer_size * sizeof(float));
|
||||||
|
if (buffer_copies[i]) {
|
||||||
|
memcpy(buffer_copies[i], state.clips[i].buffer, state.clips[i].buffer_size * sizeof(float));
|
||||||
|
// Temporarily point to our copy
|
||||||
|
state.clips[i].buffer = buffer_copies[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate autosave filename with timestamp
|
// Generate autosave filename with timestamp
|
||||||
char filename[512];
|
char filename[512];
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
@@ -87,6 +100,14 @@ static void* autosave_thread_func(void *arg) {
|
|||||||
fs_save_project(filename, &state);
|
fs_save_project(filename, &state);
|
||||||
last_autosave_time = now;
|
last_autosave_time = now;
|
||||||
|
|
||||||
|
// Free the buffer copies
|
||||||
|
for (int i = 0; i < MAX_CLIPS; i++) {
|
||||||
|
if (buffer_copies[i]) {
|
||||||
|
free(buffer_copies[i]);
|
||||||
|
buffer_copies[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove old autosaves (keep last 10)
|
// Remove old autosaves (keep last 10)
|
||||||
DIR *d = opendir(AUTOSAVE_DIR);
|
DIR *d = opendir(AUTOSAVE_DIR);
|
||||||
if (d) {
|
if (d) {
|
||||||
|
|||||||
28
wav_io.c
28
wav_io.c
@@ -3,6 +3,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
static pthread_mutex_t wav_io_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
// WAV file header structures (little-endian)
|
// WAV file header structures (little-endian)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -55,8 +58,13 @@ static uint32_t read_le32(const unsigned char *buf) {
|
|||||||
int save_wav_float(const char *filename, const float *buffer, size_t num_samples, unsigned int sample_rate) {
|
int save_wav_float(const char *filename, const float *buffer, size_t num_samples, unsigned int sample_rate) {
|
||||||
if (!filename || !buffer || num_samples == 0) return -1;
|
if (!filename || !buffer || num_samples == 0) return -1;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&wav_io_mutex);
|
||||||
|
|
||||||
FILE *f = fopen(filename, "wb");
|
FILE *f = fopen(filename, "wb");
|
||||||
if (!f) return -1;
|
if (!f) {
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate sizes
|
// Calculate sizes
|
||||||
uint32_t data_size = (uint32_t)(num_samples * sizeof(float));
|
uint32_t data_size = (uint32_t)(num_samples * sizeof(float));
|
||||||
@@ -85,24 +93,32 @@ int save_wav_float(const char *filename, const float *buffer, size_t num_samples
|
|||||||
fwrite(buffer, sizeof(float), num_samples, f);
|
fwrite(buffer, sizeof(float), num_samples, f);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_wav_float(const char *filename, float **buffer, size_t *num_samples, unsigned int *sample_rate) {
|
int load_wav_float(const char *filename, float **buffer, size_t *num_samples, unsigned int *sample_rate) {
|
||||||
if (!filename || !buffer || !num_samples || !sample_rate) return -1;
|
if (!filename || !buffer || !num_samples || !sample_rate) return -1;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&wav_io_mutex);
|
||||||
|
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
if (!f) return -1;
|
if (!f) {
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Read RIFF header
|
// Read RIFF header
|
||||||
unsigned char header[12];
|
unsigned char header[12];
|
||||||
if (fread(header, 1, 12, f) != 12) {
|
if (fread(header, 1, 12, f) != 12) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(header, "RIFF", 4) != 0 || memcmp(header + 8, "WAVE", 4) != 0) {
|
if (memcmp(header, "RIFF", 4) != 0 || memcmp(header + 8, "WAVE", 4) != 0) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +159,7 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
data_buffer = (float *)calloc(num_frames, sizeof(float));
|
data_buffer = (float *)calloc(num_frames, sizeof(float));
|
||||||
if (!data_buffer) {
|
if (!data_buffer) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,12 +171,14 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
if (!temp) {
|
if (!temp) {
|
||||||
free(data_buffer);
|
free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fread(temp, 1, read_size, f) != read_size) {
|
if (fread(temp, 1, read_size, f) != read_size) {
|
||||||
free(temp);
|
free(temp);
|
||||||
free(data_buffer);
|
free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Mix to mono if stereo
|
// Mix to mono if stereo
|
||||||
@@ -183,12 +202,14 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
if (!temp) {
|
if (!temp) {
|
||||||
free(data_buffer);
|
free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fread(temp, 1, read_size, f) != read_size) {
|
if (fread(temp, 1, read_size, f) != read_size) {
|
||||||
free(temp);
|
free(temp);
|
||||||
free(data_buffer);
|
free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Convert to float and mix to mono
|
// Convert to float and mix to mono
|
||||||
@@ -210,6 +231,7 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
// Unsupported format
|
// Unsupported format
|
||||||
free(data_buffer);
|
free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +239,7 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
*num_samples = num_frames;
|
*num_samples = num_frames;
|
||||||
*sample_rate = sample_rate_val;
|
*sample_rate = sample_rate_val;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// Skip unknown chunk
|
// Skip unknown chunk
|
||||||
@@ -227,5 +250,6 @@ int load_wav_float(const char *filename, float **buffer, size_t *num_samples, un
|
|||||||
// If we get here, we didn't find data
|
// If we get here, we didn't find data
|
||||||
if (data_buffer) free(data_buffer);
|
if (data_buffer) free(data_buffer);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
pthread_mutex_unlock(&wav_io_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user