Thread-safety at LV2 level

This commit is contained in:
Jean Pierre Cimalando 2021-02-01 22:46:02 +01:00
parent c110acc966
commit 1d6b06aa2e
2 changed files with 63 additions and 9 deletions

View file

@ -22,25 +22,25 @@ add_library(${LV2PLUGIN_PRJ_NAME} MODULE
${PROJECT_NAME}.c ${PROJECT_NAME}.c
atomic_compat.h atomic_compat.h
${LV2PLUGIN_TTL_SRC_FILES}) ${LV2PLUGIN_TTL_SRC_FILES})
target_link_libraries(${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex)
if(SFIZZ_LV2_UI) if(SFIZZ_LV2_UI)
add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE
${PROJECT_NAME}_ui.cpp ${PROJECT_NAME}_ui.cpp
vstgui_helpers.h vstgui_helpers.h
vstgui_helpers.cpp) vstgui_helpers.cpp)
target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz::editor sfizz::vstgui) target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui)
endif() endif()
# Explicitely strip all symbols on Linux but lv2_descriptor() # Explicitely strip all symbols on Linux but lv2_descriptor()
# MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555 # MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2)
target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,--version-script=lv2.version") target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=lv2.version")
# target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor") # target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor")
if(SFIZZ_LV2_UI) if(SFIZZ_LV2_UI)
file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2)
target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,--version-script=lv2ui.version") target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "-Wl,--version-script=lv2ui.version")
# target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor") # target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor")
endif() endif()
endif() endif()

View file

@ -53,6 +53,8 @@
#include <ardour/lv2_extensions.h> #include <ardour/lv2_extensions.h>
#include <spin_mutex.h>
#include <math.h> #include <math.h>
#include <sfizz.h> #include <sfizz.h>
#include <stdbool.h> #include <stdbool.h>
@ -160,6 +162,7 @@ typedef struct
// Sfizz related data // Sfizz related data
sfizz_synth_t *synth; sfizz_synth_t *synth;
sfizz_client_t *client; sfizz_client_t *client;
spin_mutex_t *synth_mutex;
bool expect_nominal_block_length; bool expect_nominal_block_length;
char sfz_file_path[MAX_PATH_SIZE]; char sfz_file_path[MAX_PATH_SIZE];
char scala_file_path[MAX_PATH_SIZE]; char scala_file_path[MAX_PATH_SIZE];
@ -599,6 +602,7 @@ instantiate(const LV2_Descriptor *descriptor,
self->synth = sfizz_create_synth(); self->synth = sfizz_create_synth();
self->client = sfizz_create_client(self); self->client = sfizz_create_client(self);
self->synth_mutex = spin_mutex_create();
sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self); sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self);
sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message);
@ -617,6 +621,7 @@ static void
cleanup(LV2_Handle instance) cleanup(LV2_Handle instance)
{ {
sfizz_plugin_t *self = (sfizz_plugin_t *)instance; sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
spin_mutex_destroy(self->synth_mutex);
sfizz_delete_client(self->client); sfizz_delete_client(self->client);
sfizz_free(self->synth); sfizz_free(self->synth);
free(self); free(self);
@ -876,8 +881,14 @@ static void
run(LV2_Handle instance, uint32_t sample_count) run(LV2_Handle instance, uint32_t sample_count)
{ {
sfizz_plugin_t *self = (sfizz_plugin_t *)instance; sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
if (!self->control_port || !self->notify_port) assert(self->control_port && self->notify_port);
if (!spin_mutex_trylock(self->synth_mutex))
{
for (int channel = 0; channel < 2; ++channel)
memset(self->output_buffers[channel], 0, sample_count * sizeof(float));
return; return;
}
// Set up forge to write directly to notify output port. // Set up forge to write directly to notify output port.
const size_t notify_capacity = self->notify_port->atom.size; const size_t notify_capacity = self->notify_port->atom.size;
@ -1048,6 +1059,8 @@ run(LV2_Handle instance, uint32_t sample_count)
// Render the block // Render the block
sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count); sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count);
spin_mutex_unlock(self->synth_mutex);
if (self->midnam && atomic_exchange(&self->must_update_midnam, 0)) if (self->midnam && atomic_exchange(&self->must_update_midnam, 0))
{ {
self->midnam->update(self->midnam->handle); self->midnam->update(self->midnam->handle);
@ -1099,7 +1112,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options)
if (opt->key == self->sample_rate_uri) if (opt->key == self->sample_rate_uri)
{ {
sfizz_lv2_parse_sample_rate(self, opt); sfizz_lv2_parse_sample_rate(self, opt);
spin_mutex_lock(self->synth_mutex);
sfizz_set_sample_rate(self->synth, self->sample_rate); sfizz_set_sample_rate(self->synth, self->sample_rate);
spin_mutex_unlock(self->synth_mutex);
} }
else if (!self->expect_nominal_block_length && opt->key == self->max_block_length_uri) else if (!self->expect_nominal_block_length && opt->key == self->max_block_length_uri)
{ {
@ -1109,7 +1124,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options)
continue; continue;
} }
self->max_block_size = *(int *)opt->value; self->max_block_size = *(int *)opt->value;
spin_mutex_lock(self->synth_mutex);
sfizz_set_samples_per_block(self->synth, self->max_block_size); sfizz_set_samples_per_block(self->synth, self->max_block_size);
spin_mutex_unlock(self->synth_mutex);
} }
else if (opt->key == self->nominal_block_length_uri) else if (opt->key == self->nominal_block_length_uri)
{ {
@ -1119,7 +1136,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options)
continue; continue;
} }
self->max_block_size = *(int *)opt->value; self->max_block_size = *(int *)opt->value;
spin_mutex_lock(self->synth_mutex);
sfizz_set_samples_per_block(self->synth, self->max_block_size); sfizz_set_samples_per_block(self->synth, self->max_block_size);
spin_mutex_unlock(self->synth_mutex);
} }
} }
return LV2_OPTIONS_SUCCESS; return LV2_OPTIONS_SUCCESS;
@ -1263,6 +1282,7 @@ restore(LV2_Handle instance,
} }
// Sync the parameters to the synth // Sync the parameters to the synth
spin_mutex_lock(self->synth_mutex);
// Load an empty file to remove the default sine, and then the new file. // Load an empty file to remove the default sine, and then the new file.
sfizz_load_string(self->synth, "empty.sfz", ""); sfizz_load_string(self->synth, "empty.sfz", "");
@ -1299,6 +1319,8 @@ restore(LV2_Handle instance,
lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling); lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling);
sfizz_set_oversampling_factor(self->synth, self->oversampling); sfizz_set_oversampling_factor(self->synth, self->oversampling);
spin_mutex_unlock(self->synth_mutex);
return status; return status;
} }
@ -1419,7 +1441,12 @@ work(LV2_Handle instance,
if (atom->type == self->sfizz_sfz_file_uri) if (atom->type == self->sfizz_sfz_file_uri)
{ {
const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom); const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom);
if (!sfizz_lv2_load_file(self, sfz_file_path)) {
spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_file(self, sfz_file_path);
spin_mutex_unlock(self->synth_mutex);
if (!success) {
lv2_log_error(&self->logger, lv2_log_error(&self->logger,
"[sfizz] Error with %s; no file should be loaded\n", sfz_file_path); "[sfizz] Error with %s; no file should be loaded\n", sfz_file_path);
} }
@ -1430,7 +1457,12 @@ work(LV2_Handle instance,
else if (atom->type == self->sfizz_scala_file_uri) else if (atom->type == self->sfizz_scala_file_uri)
{ {
const char *scala_file_path = LV2_ATOM_BODY_CONST(atom); const char *scala_file_path = LV2_ATOM_BODY_CONST(atom);
if (sfizz_lv2_load_scala_file(self, scala_file_path)) {
spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_scala_file(self, scala_file_path);
spin_mutex_unlock(self->synth_mutex);
if (success) {
lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", scala_file_path); lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", scala_file_path);
} else { } else {
lv2_log_error(&self->logger, lv2_log_error(&self->logger,
@ -1443,7 +1475,11 @@ work(LV2_Handle instance,
else if (atom->type == self->sfizz_num_voices_uri) else if (atom->type == self->sfizz_num_voices_uri)
{ {
const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom); const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom);
spin_mutex_lock(self->synth_mutex);
sfizz_set_num_voices(self->synth, num_voices); sfizz_set_num_voices(self->synth, num_voices);
spin_mutex_unlock(self->synth_mutex);
if (sfizz_get_num_voices(self->synth) == num_voices) { if (sfizz_get_num_voices(self->synth) == num_voices) {
lv2_log_note(&self->logger, "[sfizz] Number of voices changed to: %d\n", num_voices); lv2_log_note(&self->logger, "[sfizz] Number of voices changed to: %d\n", num_voices);
} else { } else {
@ -1453,7 +1489,11 @@ work(LV2_Handle instance,
else if (atom->type == self->sfizz_preload_size_uri) else if (atom->type == self->sfizz_preload_size_uri)
{ {
const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom); const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom);
spin_mutex_lock(self->synth_mutex);
sfizz_set_preload_size(self->synth, preload_size); sfizz_set_preload_size(self->synth, preload_size);
spin_mutex_unlock(self->synth_mutex);
if (sfizz_get_preload_size(self->synth) == preload_size) { if (sfizz_get_preload_size(self->synth) == preload_size) {
lv2_log_note(&self->logger, "[sfizz] Preload size changed to: %d\n", preload_size); lv2_log_note(&self->logger, "[sfizz] Preload size changed to: %d\n", preload_size);
} else { } else {
@ -1464,7 +1504,11 @@ work(LV2_Handle instance,
{ {
const sfizz_oversampling_factor_t oversampling = const sfizz_oversampling_factor_t oversampling =
*(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom); *(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom);
spin_mutex_lock(self->synth_mutex);
sfizz_set_oversampling_factor(self->synth, oversampling); sfizz_set_oversampling_factor(self->synth, oversampling);
spin_mutex_unlock(self->synth_mutex);
if (sfizz_get_oversampling_factor(self->synth) == oversampling) { if (sfizz_get_oversampling_factor(self->synth) == oversampling) {
lv2_log_note(&self->logger, "[sfizz] Oversampling changed to: %d\n", oversampling); lv2_log_note(&self->logger, "[sfizz] Oversampling changed to: %d\n", oversampling);
} else { } else {
@ -1482,7 +1526,12 @@ work(LV2_Handle instance,
lv2_log_note(&self->logger, lv2_log_note(&self->logger,
"[sfizz] File %s seems to have been updated, reloading\n", "[sfizz] File %s seems to have been updated, reloading\n",
self->sfz_file_path); self->sfz_file_path);
if (!sfizz_lv2_load_file(self, self->sfz_file_path)) {
spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_file(self, self->sfz_file_path);
spin_mutex_unlock(self->synth_mutex);
if (!success) {
lv2_log_error(&self->logger, lv2_log_error(&self->logger,
"[sfizz] Error with %s; no file should be loaded\n", self->sfz_file_path); "[sfizz] Error with %s; no file should be loaded\n", self->sfz_file_path);
} }
@ -1493,7 +1542,12 @@ work(LV2_Handle instance,
lv2_log_note(&self->logger, lv2_log_note(&self->logger,
"[sfizz] Scala file %s seems to have been updated, reloading\n", "[sfizz] Scala file %s seems to have been updated, reloading\n",
self->scala_file_path); self->scala_file_path);
if (sfizz_lv2_load_scala_file(self, self->scala_file_path)) {
spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_scala_file(self, self->scala_file_path);
spin_mutex_unlock(self->synth_mutex);
if (success) {
lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", self->scala_file_path); lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", self->scala_file_path);
} else { } else {
lv2_log_error(&self->logger, lv2_log_error(&self->logger,