diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 2271a466..e779a72b 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -179,6 +179,20 @@ enum SFIZZ_STRETCH_TUNING = 11, }; +static void +sfizz_lv2_state_free_path(LV2_State_Free_Path_Handle handle, + char *path) +{ + (void)handle; + free(path); +} + +static LV2_State_Free_Path sfizz_State_Free_Path = +{ + .handle = NULL, + .free_path = &sfizz_lv2_state_free_path, +}; + static void sfizz_lv2_map_required_uris(sfizz_plugin_t *self) { @@ -911,9 +925,18 @@ restore(LV2_Handle instance, const LV2_Feature *const *features) { UNUSED(flags); - UNUSED(features); sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + LV2_State_Map_Path *map_path = NULL; + LV2_State_Free_Path *free_path = &sfizz_State_Free_Path; + for (const LV2_Feature *const *f = features; *f; ++f) + { + if (!strcmp((*f)->URI, LV2_STATE__mapPath)) + map_path = (LV2_State_Map_Path *)(**f).data; + else if (!strcmp((*f)->URI, LV2_STATE__freePath)) + free_path = (LV2_State_Free_Path *)(**f).data; + } + // Fetch back the saved file path, if any size_t size; uint32_t type; @@ -922,24 +945,46 @@ restore(LV2_Handle instance, value = retrieve(handle, self->sfizz_sfz_file_uri, &size, &type, &val_flags); if (value) { - lv2_log_note(&self->logger, "[sfizz] Restoring the file %s\n", (const char *)value); - sfizz_lv2_load_file(instance, (const char *)value); + const char *path = (const char *)value; + if (map_path) + { + path = map_path->absolute_path(map_path->handle, path); + if (!path) + return LV2_STATE_ERR_UNKNOWN; + } + + lv2_log_note(&self->logger, "[sfizz] Restoring the file %s\n", path); + sfizz_lv2_load_file(instance, path); + + if (map_path) + free_path->free_path(free_path->handle, (char *)path); } value = retrieve(handle, self->sfizz_scala_file_uri, &size, &type, &val_flags); if (value) { - if (sfizz_load_scala_file(self->synth, (const char *)value)) + const char *path = (const char *)value; + if (map_path) + { + path = map_path->absolute_path(map_path->handle, path); + if (!path) + return LV2_STATE_ERR_UNKNOWN; + } + + if (sfizz_load_scala_file(self->synth, path)) { lv2_log_note(&self->logger, - "[sfizz] Restoring the scale %s\n", (const char *)value); - strcpy(self->scala_file_path, (const char *)value); + "[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", (const char *)value); + "[sfizz] Error while restoring the scale %s\n", path); } + + if (map_path) + free_path->free_path(free_path->handle, (char *)path); } value = retrieve(handle, self->sfizz_num_voices_uri, &size, &type, &val_flags); @@ -988,23 +1033,55 @@ save(LV2_Handle instance, const LV2_Feature *const *features) { UNUSED(flags); - UNUSED(features); sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + + LV2_State_Map_Path *map_path = NULL; + LV2_State_Free_Path *free_path = &sfizz_State_Free_Path; + for (const LV2_Feature *const *f = features; *f; ++f) + { + if (!strcmp((*f)->URI, LV2_STATE__mapPath)) + map_path = (LV2_State_Map_Path *)(**f).data; + else if (!strcmp((*f)->URI, LV2_STATE__freePath)) + free_path = (LV2_State_Free_Path *)(**f).data; + } + + const char *path; + // Save the file path + path = self->sfz_file_path; + if (map_path) + { + path = map_path->abstract_path(map_path->handle, path); + if (!path) + return LV2_STATE_ERR_UNKNOWN; + } store(handle, self->sfizz_sfz_file_uri, - self->sfz_file_path, - strlen(self->sfz_file_path) + 1, + path, + strlen(path) + 1, self->atom_path_uri, LV2_STATE_IS_POD); + if (map_path) + free_path->free_path(free_path->handle, (char *)path); // Save the scala file path + path = self->scala_file_path; + if (map_path) + { + path = map_path->abstract_path(map_path->handle, path); + if (!path) + return LV2_STATE_ERR_UNKNOWN; + } + if (!path) + return LV2_STATE_ERR_UNKNOWN; store(handle, self->sfizz_scala_file_uri, - self->scala_file_path, - strlen(self->scala_file_path) + 1, + path, + strlen(path) + 1, self->atom_path_uri, LV2_STATE_IS_POD); + if (map_path) + free_path->free_path(free_path->handle, (char *)path); // Save the number of voices store(handle, diff --git a/lv2/sfizz.ttl.in b/lv2/sfizz.ttl.in index 217e56d9..6c661987 100644 --- a/lv2/sfizz.ttl.in +++ b/lv2/sfizz.ttl.in @@ -68,7 +68,7 @@ midnam:update a lv2:Feature . lv2:microVersion @LV2PLUGIN_VERSION_MICRO@ ; lv2:requiredFeature urid:map, bufsize:boundedBlockLength, work:schedule ; - lv2:optionalFeature lv2:hardRTCapable, opts:options ; + lv2:optionalFeature lv2:hardRTCapable, opts:options, state:mapPath, state:freePath ; lv2:extensionData opts:interface, state:interface, work:interface ; lv2:optionalFeature midnam:update ; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index ded6eeaa..0016f300 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -395,7 +395,11 @@ bool sfz::Synth::loadSfzFile(const fs::path& file) clear(); const std::lock_guard disableCallback { callbackGuard }; - parser.parseFile(file); + + std::error_code ec; + fs::path realFile = fs::canonical(file, ec); + + parser.parseFile(ec ? file : realFile); if (parser.getErrorCount() > 0) return false;