diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index 1eaf89de..73de6ee5 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -49,6 +49,17 @@ if (SFIZZ_USE_VCPKG OR SFIZZ_STATIC_LIBSNDFILE OR CMAKE_CXX_COMPILER_ID MATCHES file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR}) endif() +# Copy resource files into the bundle +set(LV2_RESOURCES + DefaultInstrument.sfz + DefaultScale.scl) +execute_process( + COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Resources") +foreach(res ${LV2_RESOURCES}) + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${res}" + DESTINATION "${PROJECT_BINARY_DIR}/Resources") +endforeach() + # Installation if (NOT MSVC) install (DIRECTORY ${PROJECT_BINARY_DIR} DESTINATION ${LV2PLUGIN_INSTALL_DIR} diff --git a/lv2/resources/DefaultInstrument.sfz b/lv2/resources/DefaultInstrument.sfz new file mode 100644 index 00000000..5f82f9c2 --- /dev/null +++ b/lv2/resources/DefaultInstrument.sfz @@ -0,0 +1,3 @@ + +sample=*sine +ampeg_attack=0.02 ampeg_release=0.1 diff --git a/lv2/resources/DefaultScale.scl b/lv2/resources/DefaultScale.scl new file mode 100644 index 00000000..081422f0 --- /dev/null +++ b/lv2/resources/DefaultScale.scl @@ -0,0 +1,14 @@ +Equal temperament +12 +100.0 +200.0 +300.0 +400.0 +500.0 +600.0 +700.0 +800.0 +900.0 +1000.0 +1100.0 +1200.0 diff --git a/lv2/sfizz.c b/lv2/sfizz.c index d3459ef0..d7c7e93f 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -58,7 +58,6 @@ #include "atomic_compat.h" -#define DEFAULT_SFZ_FILE "/home/paul/Documents/AVL_Percussions/AVL_Drumkits_Percussion-1.0-Alt.sfz" #define SFIZZ_URI "http://sfztools.github.io/sfizz" #define SFIZZ_PREFIX SFIZZ_URI "#" #define SFIZZ__sfzFile "http://sfztools.github.io/sfizz:sfzfile" @@ -83,16 +82,17 @@ #define LOG_SAMPLE_COUNT 48000 #define UNUSED(x) (void)(x) +#define DEFAULT_SCALA_FILE "Resources/DefaultScale.scl" +#define DEFAULT_SFZ_FILE "Resources/DefaultInstrument.sfz" +// This assumes that the longest path is the default sfz file; if not, change it +#define MAX_BUNDLE_PATH_SIZE (MAX_PATH_SIZE - sizeof(DEFAULT_SFZ_FILE)) + #ifndef NDEBUG #define LV2_DEBUG(...) lv2_log_note(&self->logger, "[DEBUG] " __VA_ARGS__) #else #define LV2_DEBUG(...) #endif -static const char default_sfz_text[] = - "sample=*sine" "\n" - "ampeg_attack=0.02 ampeg_release=0.1" "\n"; - typedef struct { // Features @@ -163,6 +163,9 @@ typedef struct int sample_counter; float sample_rate; atomic_int must_update_midnam; + + // Paths + char bundle_path[MAX_BUNDLE_PATH_SIZE]; } sfizz_plugin_t; enum @@ -302,14 +305,27 @@ sfizz_lv2_parse_sample_rate(sfizz_plugin_t* self, const LV2_Options_Option* opt) } } +static void +sfizz_lv2_get_default_sfz_path(LV2_Handle instance, char *path, size_t size) +{ + sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + snprintf(path, size, "%s/%s", self->bundle_path, DEFAULT_SFZ_FILE); +} + +static void +sfizz_lv2_get_default_scala_path(LV2_Handle instance, char *path, size_t size) +{ + sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + snprintf(path, size, "%s/%s", self->bundle_path, DEFAULT_SCALA_FILE); +} + static LV2_Handle instantiate(const LV2_Descriptor *descriptor, double rate, - const char *path, + const char *bundle_path, const LV2_Feature *const *features) { UNUSED(descriptor); - UNUSED(path); LV2_Options_Option *options = NULL; bool supports_bounded_block_size = false; bool options_has_block_size = false; @@ -320,6 +336,11 @@ instantiate(const LV2_Descriptor *descriptor, if (!self) return NULL; + LV2_Handle instance = (LV2_Handle)self; + + strncpy(self->bundle_path, bundle_path, MAX_BUNDLE_PATH_SIZE); + self->bundle_path[MAX_BUNDLE_PATH_SIZE - 1] = '\0'; + // Set defaults self->max_block_size = MAX_BLOCK_SIZE; self->sample_rate = (float)rate; @@ -330,7 +351,7 @@ instantiate(const LV2_Descriptor *descriptor, self->oversampling = DEFAULT_OVERSAMPLING; self->preload_size = DEFAULT_PRELOAD; self->stretch_tuning = 0.0f; - self->check_modification = true; + self->check_modification = false; self->sample_counter = 0; // Get the features from the host and populate the structure @@ -437,7 +458,12 @@ instantiate(const LV2_Descriptor *descriptor, } self->synth = sfizz_create_synth(); - sfizz_load_string(self->synth, "default.sfz", default_sfz_text); + + sfizz_lv2_get_default_sfz_path(instance, self->sfz_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_scala_path(instance, self->scala_file_path, MAX_PATH_SIZE); + + sfizz_load_file(self->synth, self->sfz_file_path); + sfizz_load_scala_file(self->synth, self->scala_file_path); return (LV2_Handle)self; } @@ -886,10 +912,10 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) static void sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path) { - strcpy(self->sfz_file_path, file_path); + if (file_path != self->sfz_file_path) + strcpy(self->sfz_file_path, file_path); - const char *display_path = (file_path[0] != '\0') ? file_path : "(default)"; - lv2_log_note(&self->logger, "[sfizz] File changed to: %s\n", display_path); + lv2_log_note(&self->logger, "[sfizz] File changed to: %s\n", file_path); char *unknown_opcodes = sfizz_get_unknown_opcodes(self->synth); if (unknown_opcodes) @@ -908,20 +934,19 @@ static bool sfizz_lv2_load_file(LV2_Handle instance, const char *file_path) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; - - if (file_path[0] == '\0') - { - if (!sfizz_load_string(self->synth, "default.sfz", default_sfz_text)) - return false; - } - else - { - if (!sfizz_load_file(self->synth, file_path)) - return false; - } - + bool status = sfizz_load_file(self->synth, file_path); sfizz_lv2_update_file_info(self, file_path); - return true; + return status; +} + +static bool +sfizz_lv2_load_scala_file(LV2_Handle instance, const char *file_path) +{ + sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + bool status = sfizz_load_scala_file(self->synth, file_path); + if (file_path != self->scala_file_path) + strcpy(self->scala_file_path, file_path); + return status; } static LV2_State_Status @@ -932,6 +957,7 @@ restore(LV2_Handle instance, const LV2_Feature *const *features) { UNUSED(flags); + LV2_State_Status status = LV2_STATE_SUCCESS; sfizz_plugin_t *self = (sfizz_plugin_t *)instance; LV2_State_Map_Path *map_path = NULL; @@ -944,6 +970,13 @@ restore(LV2_Handle instance, free_path = (LV2_State_Free_Path *)(**f).data; } + // Set default values + sfizz_lv2_get_default_sfz_path(instance, self->sfz_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_scala_path(instance, self->scala_file_path, MAX_PATH_SIZE); + self->num_voices = DEFAULT_VOICES; + self->preload_size = DEFAULT_PRELOAD; + self->oversampling = DEFAULT_OVERSAMPLING; + // Fetch back the saved file path, if any size_t size; uint32_t type; @@ -957,11 +990,11 @@ restore(LV2_Handle instance, { path = map_path->absolute_path(map_path->handle, path); if (!path) - return LV2_STATE_ERR_UNKNOWN; + status = LV2_STATE_ERR_UNKNOWN; } - lv2_log_note(&self->logger, "[sfizz] Restoring the file %s\n", path); - sfizz_lv2_load_file(instance, path); + strncpy(self->sfz_file_path, path, MAX_PATH_SIZE); + self->sfz_file_path[MAX_PATH_SIZE - 1] = '\0'; if (map_path) free_path->free_path(free_path->handle, (char *)path); @@ -975,20 +1008,11 @@ restore(LV2_Handle instance, { path = map_path->absolute_path(map_path->handle, path); if (!path) - return LV2_STATE_ERR_UNKNOWN; + status = LV2_STATE_ERR_UNKNOWN; } - if (sfizz_load_scala_file(self->synth, path)) - { - lv2_log_note(&self->logger, - "[sfizz] Restoring the scale %s\n", path); - strcpy(self->scala_file_path, path); - } - else - { - lv2_log_error(&self->logger, - "[sfizz] Error while restoring the scale %s\n", path); - } + strncpy(self->scala_file_path, path, MAX_PATH_SIZE); + self->scala_file_path[MAX_PATH_SIZE - 1] = '\0'; if (map_path) free_path->free_path(free_path->handle, (char *)path); @@ -998,38 +1022,62 @@ restore(LV2_Handle instance, if (value) { int num_voices = *(const int *)value; - if (num_voices > 0 && num_voices <= MAX_VOICES && num_voices != self->num_voices) - { - lv2_log_note(&self->logger, "[sfizz] Restoring the number of voices to %d\n", num_voices); - sfizz_set_num_voices(self->synth, num_voices); + if (num_voices > 0 && num_voices <= MAX_VOICES) self->num_voices = num_voices; - } } value = retrieve(handle, self->sfizz_preload_size_uri, &size, &type, &val_flags); if (value) { unsigned int preload_size = *(const unsigned int *)value; - if (preload_size != self->preload_size) - { - lv2_log_note(&self->logger, "[sfizz] Restoring the preload size to %d\n", preload_size); - sfizz_set_preload_size(self->synth, preload_size); - self->preload_size = preload_size; - } + self->preload_size = preload_size; } value = retrieve(handle, self->sfizz_oversampling_uri, &size, &type, &val_flags); if (value) { sfizz_oversampling_factor_t oversampling = *(const sfizz_oversampling_factor_t *)value; - if (oversampling != self->oversampling) - { - lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", oversampling); - sfizz_set_oversampling_factor(self->synth, oversampling); - self->oversampling = oversampling; - } + self->oversampling = oversampling; } - return LV2_STATE_SUCCESS; + + // Sync the parameters to the synth + + // Load an empty file to remove the default sine, and then the new file. + sfizz_load_string(self->synth, "empty.sfz", ""); + self->check_modification = false; + if (sfizz_lv2_load_file(instance, self->sfz_file_path)) + { + lv2_log_note(&self->logger, + "[sfizz] Restoring the file %s\n", self->sfz_file_path); + self->check_modification = true; + } + else + { + lv2_log_error(&self->logger, + "[sfizz] Error while restoring the file %s\n", self->sfz_file_path); + } + + if (sfizz_load_scala_file(self->synth, self->scala_file_path)) + { + lv2_log_note(&self->logger, + "[sfizz] Restoring the scale %s\n", self->scala_file_path); + } + else + { + lv2_log_error(&self->logger, + "[sfizz] Error while restoring the scale %s\n", self->scala_file_path); + } + + lv2_log_note(&self->logger, "[sfizz] Restoring the number of voices to %d\n", self->num_voices); + sfizz_set_num_voices(self->synth, self->num_voices); + + lv2_log_note(&self->logger, "[sfizz] Restoring the preload size to %d\n", self->preload_size); + sfizz_set_preload_size(self->synth, self->preload_size); + + lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling); + sfizz_set_oversampling_factor(self->synth, self->oversampling); + + return status; } static LV2_State_Status @@ -1138,6 +1186,7 @@ work(LV2_Handle instance, uint32_t size, const void *data) { + UNUSED(size); sfizz_plugin_t *self = (sfizz_plugin_t *)instance; if (!data) { lv2_log_error(&self->logger, "[sfizz] Ignoring empty data in the worker thread\n"); @@ -1159,8 +1208,7 @@ 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_load_scala_file(self->synth, scala_file_path)) { - strcpy(self->scala_file_path, scala_file_path); + if (sfizz_lv2_load_scala_file(self->synth, scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", scala_file_path); } else { lv2_log_error(&self->logger, @@ -1223,7 +1271,7 @@ 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_load_scala_file(self->synth, self->scala_file_path)) { + if (sfizz_lv2_load_scala_file(self->synth, self->scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", self->scala_file_path); } else { lv2_log_error(&self->logger,