lv2 thread-safe store/restore, all other templates are now broken

This commit is contained in:
Stefano D'Angelo 2025-01-20 10:42:06 +01:00
parent ae513dae30
commit 8f6285a884
3 changed files with 116 additions and 28 deletions

View File

@ -28,6 +28,8 @@ typedef struct {
const char * (*get_datadir)(void *handle); const char * (*get_datadir)(void *handle);
int (*write_state)(void *handle, const char *data, size_t length); int (*write_state)(void *handle, const char *data, size_t length);
void (*load_parameter)(void *handle, size_t index, float value); void (*load_parameter)(void *handle, size_t index, float value);
void (*lock_state)(void *handle);
void (*unlock_state)(void *handle);
} plugin_callbacks; } plugin_callbacks;
typedef struct { typedef struct {

View File

@ -57,6 +57,24 @@
# include <pmmintrin.h> # include <pmmintrin.h>
#endif #endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N > 0) && defined(DATA_STATE_DSP_CUSTOM)
# include <stdatomic.h>
# if defined(_WIN32) || defined(__CYGWIN__)
# include <processthreadsapi.h>
# define yield SwitchToThread
# else
# include <sched.h>
# define yield sched_yield
# endif
#endif
#define CONTROL_INPUT_INDEX_OFFSET ( \
DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N \
+ DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N \
+ DATA_PRODUCT_MIDI_INPUTS_N \
+ DATA_PRODUCT_MIDI_OUTPUTS_N )
#define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N)
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 #if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static inline float clampf(float x, float m, float M) { static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x); return x < m ? m : (x > M ? M : x);
@ -92,6 +110,12 @@ typedef struct {
#endif #endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 #if DATA_PRODUCT_CONTROL_INPUTS_N > 0
float params[DATA_PRODUCT_CONTROL_INPUTS_N]; float params[DATA_PRODUCT_CONTROL_INPUTS_N];
# ifdef DATA_STATE_DSP_CUSTOM
float params_sync[DATA_PRODUCT_CONTROL_INPUTS_N];
atomic_flag sync_lock_flag;
char synced;
char loaded;
# endif
#endif #endif
void * mem; void * mem;
char * bundle_path; char * bundle_path;
@ -122,12 +146,24 @@ static int write_state_cb(void *handle, const char *data, size_t length) {
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0 # if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static void load_parameter_cb(void *handle, size_t index, float value) { static void load_parameter_cb(void *handle, size_t index, float value) {
plugin_instance * i = (plugin_instance *)handle; plugin_instance * i = (plugin_instance *)handle;
size_t idx = index_to_param[index]; size_t idx = index_to_param[index] - CONTROL_INPUT_INDEX_OFFSET;
value = adjust_param(idx, value); value = adjust_param(idx, value);
i->params[idx] = value; i->params_sync[idx] = value;
plugin_set_parameter(&i->p, index, value); i->loaded = 1;
} }
# endif # endif
static void lock_state_cb(void *handle) {
plugin_instance * i = (plugin_instance *)handle;
while (atomic_flag_test_and_set(&i->sync_lock_flag))
yield();
i->synced = 0;
}
static void unlock_state_cb(void *handle) {
plugin_instance * i = (plugin_instance *)handle;
atomic_flag_clear(&i->sync_lock_flag);
}
#endif #endif
static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) { static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
@ -175,13 +211,17 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
# ifdef DATA_STATE_DSP_CUSTOM # ifdef DATA_STATE_DSP_CUSTOM
/* .write_state = */ write_state_cb, /* .write_state = */ write_state_cb,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0 # if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .load_parameter = */ load_parameter_cb /* .load_parameter = */ load_parameter_cb,
# else # else
/* .load_parameter = */ NULL /* .load_parameter = */ NULL,
# endif # endif
/* .lock_state = */ lock_state_cb,
/* .unlock_state = */ unlock_state_cb
# else # else
/* .write_state = */ NULL, /* .write_state = */ NULL,
/* .load_parameter = */ NULL /* .load_parameter = */ NULL,
/* .state_lock = */ NULL,
/* .state_unlock = */ NULL
# endif # endif
}; };
plugin_init(&instance->p, &cbs); plugin_init(&instance->p, &cbs);
@ -275,6 +315,15 @@ static void activate(LV2_Handle instance) {
i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def; i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def;
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]); plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
} }
# ifdef DATA_STATE_DSP_CUSTOM
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
i->params_sync[j] = i->params[j];
// why is this not correct?
// i->sync_lock_flag = ATOMIC_FLAG_INIT;
atomic_flag_clear(&i->sync_lock_flag);
i->synced = 1;
i->loaded = 0;
# endif
#endif #endif
plugin_reset(&i->p); plugin_reset(&i->p);
} }
@ -295,6 +344,27 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
#endif #endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 #if DATA_PRODUCT_CONTROL_INPUTS_N > 0
# ifdef DATA_STATE_DSP_CUSTOM
if (!atomic_flag_test_and_set(&i->sync_lock_flag)) {
if (!i->synced) {
if (i->loaded) {
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
i->params[j] = i->params_sync[j];
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
}
} else {
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
if (i->params[j] != i->params_sync[j]) {
i->params_sync[j] = i->params[j];
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
}
}
}
i->synced = 1;
i->loaded = 0;
atomic_flag_clear(&i->sync_lock_flag);
# endif
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) { for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
if (i->c[j] == NULL) if (i->c[j] == NULL)
continue; continue;
@ -304,6 +374,17 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_set_parameter(&i->p, param_data[j].index, v); plugin_set_parameter(&i->p, param_data[j].index, v);
} }
} }
# ifdef DATA_STATE_DSP_CUSTOM
} else {
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
if (i->c[j] == NULL)
continue;
float v = adjust_param(j, *i->c[j]);
if (v != i->params[j])
i->params[j] = v;
}
}
# endif
#endif #endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0 #if DATA_PRODUCT_MIDI_INPUTS_N > 0
@ -429,13 +510,6 @@ typedef struct {
# endif # endif
} ui_instance; } ui_instance;
# define CONTROL_INPUT_INDEX_OFFSET ( \
DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N \
+ DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N \
+ DATA_PRODUCT_MIDI_INPUTS_N \
+ DATA_PRODUCT_MIDI_OUTPUTS_N )
# define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N)
static const char * ui_get_bundle_path_cb(void *handle) { static const char * ui_get_bundle_path_cb(void *handle) {
ui_instance *instance = (ui_instance *)handle; ui_instance *instance = (ui_instance *)handle;
return instance->bundle_path; return instance->bundle_path;

View File

@ -141,18 +141,30 @@ static float parse_float(const uint8_t *data) {
static int plugin_state_save(plugin *instance) { static int plugin_state_save(plugin *instance) {
uint8_t data[13]; uint8_t data[13];
serialize_float(data, instance->gain); instance->cbs.lock_state(instance->cbs.handle);
serialize_float(data + 4, instance->delay); const float gain = instance->gain;
serialize_float(data + 8, instance->cutoff); const float delay = instance->delay;
data[12] = instance->bypass ? 1 : 0; const float cutoff = instance->cutoff;
const char bypass = instance->bypass;
instance->cbs.unlock_state(instance->cbs.handle);
serialize_float(data, gain);
serialize_float(data + 4, delay);
serialize_float(data + 8, cutoff);
data[12] = bypass ? 1 : 0;
return instance->cbs.write_state(instance->cbs.handle, (const char *)data, 13); return instance->cbs.write_state(instance->cbs.handle, (const char *)data, 13);
} }
static void plugin_state_load(plugin *instance, const char *data, size_t length) { static void plugin_state_load(plugin *instance, const char *data, size_t length) {
(void)length; (void)length;
const uint8_t *d = (const uint8_t *)data; const uint8_t *d = (const uint8_t *)data;
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_gain, parse_float(d)); const float gain = parse_float(d);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_delay, parse_float(d + 4)); const float delay = parse_float(d + 4);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_cutoff, parse_float(d + 8)); const float cutoff = parse_float(d + 8);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_bypass, d[12] ? 1.f : 0.f); const float bypass = d[12] ? 1.f : 0.f;
instance->cbs.lock_state(instance->cbs.handle);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_gain, gain);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_delay, delay);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_cutoff, cutoff);
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_bypass, bypass);
instance->cbs.unlock_state(instance->cbs.handle);
} }