diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index c5a4e861..d247dd14 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -22,25 +22,25 @@ add_library(${LV2PLUGIN_PRJ_NAME} MODULE ${PROJECT_NAME}.c atomic_compat.h ${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) add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE ${PROJECT_NAME}_ui.cpp vstgui_helpers.h 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() # 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 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") 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") if(SFIZZ_LV2_UI) 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") endif() endif() diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 57d80846..115fea48 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -53,6 +53,8 @@ #include +#include + #include #include #include @@ -160,6 +162,7 @@ typedef struct // Sfizz related data sfizz_synth_t *synth; sfizz_client_t *client; + spin_mutex_t *synth_mutex; bool expect_nominal_block_length; char sfz_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->client = sfizz_create_client(self); + self->synth_mutex = spin_mutex_create(); sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self); sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); @@ -617,6 +621,7 @@ static void cleanup(LV2_Handle instance) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); free(self); @@ -876,8 +881,14 @@ static void run(LV2_Handle instance, uint32_t sample_count) { 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; + } // Set up forge to write directly to notify output port. 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 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)) { 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) { sfizz_lv2_parse_sample_rate(self, opt); + spin_mutex_lock(self->synth_mutex); 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) { @@ -1109,7 +1124,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) continue; } self->max_block_size = *(int *)opt->value; + spin_mutex_lock(self->synth_mutex); 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) { @@ -1119,7 +1136,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) continue; } self->max_block_size = *(int *)opt->value; + spin_mutex_lock(self->synth_mutex); sfizz_set_samples_per_block(self->synth, self->max_block_size); + spin_mutex_unlock(self->synth_mutex); } } return LV2_OPTIONS_SUCCESS; @@ -1263,6 +1282,7 @@ restore(LV2_Handle instance, } // 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. 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); sfizz_set_oversampling_factor(self->synth, self->oversampling); + spin_mutex_unlock(self->synth_mutex); + return status; } @@ -1419,7 +1441,12 @@ work(LV2_Handle instance, if (atom->type == self->sfizz_sfz_file_uri) { 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, "[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) { 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); } else { lv2_log_error(&self->logger, @@ -1443,7 +1475,11 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_num_voices_uri) { 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); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_num_voices(self->synth) == num_voices) { lv2_log_note(&self->logger, "[sfizz] Number of voices changed to: %d\n", num_voices); } else { @@ -1453,7 +1489,11 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_preload_size_uri) { 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); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_preload_size(self->synth) == preload_size) { lv2_log_note(&self->logger, "[sfizz] Preload size changed to: %d\n", preload_size); } else { @@ -1464,7 +1504,11 @@ work(LV2_Handle instance, { const sfizz_oversampling_factor_t oversampling = *(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom); + + spin_mutex_lock(self->synth_mutex); sfizz_set_oversampling_factor(self->synth, oversampling); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_oversampling_factor(self->synth) == oversampling) { lv2_log_note(&self->logger, "[sfizz] Oversampling changed to: %d\n", oversampling); } else { @@ -1482,7 +1526,12 @@ work(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] File %s seems to have been updated, reloading\n", 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, "[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, "[sfizz] Scala file %s seems to have been updated, reloading\n", 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); } else { lv2_log_error(&self->logger,