diff --git a/lv2/sfizz.c b/lv2/sfizz.c index a295a3f7..d58a923b 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -132,7 +132,6 @@ typedef struct sfizz_synth_t *synth; bool expect_nominal_block_length; char sfz_file_path[MAX_PATH_SIZE]; - struct stat sfz_file_info; int num_voices; unsigned int preload_size; sfizz_oversampling_factor_t oversampling; @@ -274,7 +273,6 @@ instantiate(const LV2_Descriptor *descriptor, self->sample_rate = (float)rate; self->expect_nominal_block_length = false; self->sfz_file_path[0] = '\0'; - self->sfz_file_info.st_mtime = (time_t)(-1); self->num_voices = DEFAULT_VOICES; self->oversampling = DEFAULT_OVERSAMPLING; self->preload_size = DEFAULT_PRELOAD; @@ -524,25 +522,6 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev) } } -static bool -sfizz_lv2_check_modification(sfizz_plugin_t *self) -{ - if (self->sfz_file_path == NULL) - return false; - - if (strlen(self->sfz_file_path) == 0) - return false; - - struct stat new_file_info; - if (stat(self->sfz_file_path, &new_file_info) != 0) - return false; - - if (new_file_info.st_mtim.tv_sec > self->sfz_file_info.st_mtim.tv_sec) - return true; - - return false; -} - static void sfizz_lv2_status_log(sfizz_plugin_t *self) { @@ -787,7 +766,6 @@ static void sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char* file_path) { strcpy(self->sfz_file_path, file_path); - stat(self->sfz_file_path, &self->sfz_file_info); lv2_log_note(&self->logger, "[sfizz] File changed to: %s\n", self->sfz_file_path); char *unknown_opcodes = sfizz_get_unknown_opcodes(self->synth); @@ -972,7 +950,7 @@ work(LV2_Handle instance, } else if (atom->type == self->sfizz_check_modification_uri) { - if (sfizz_lv2_check_modification(self)) + if (sfizz_should_reload_file(self->synth)) { lv2_log_note(&self->logger, "[sfizz] File %s seems to have been updated, reloading.\n", self->sfz_file_path); if (sfizz_load_file(self->synth, self->sfz_file_path)) diff --git a/src/sfizz.h b/src/sfizz.h index acc6c61a..0ad610d1 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -344,6 +344,19 @@ void sfizz_disable_freewheeling(sfizz_synth_t* synth); * @return char* */ char* sfizz_get_unknown_opcodes(sfizz_synth_t* synth); + +/** + * @brief Check if the SFZ should be reloaded. + * + * Depending on the platform this can create file descriptors. + * + * @param synth + * @return true if any included files (including the root file) have + * been modified since the sfz file was loaded. + * @return false + */ +bool sfizz_should_reload_file(sfizz_synth_t* synth); + #ifdef __cplusplus } #endif diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 8bee185c..5b408aca 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -147,6 +147,7 @@ void sfz::Synth::clear() masterOpcodes.clear(); groupOpcodes.clear(); unknownOpcodes.clear(); + modificationTime = fs::file_time_type::min(); } void sfz::Synth::handleGlobalOpcodes(const std::vector& members) @@ -289,6 +290,7 @@ bool sfz::Synth::loadSfzFile(const fs::path& filename) DBG("Removed " << regions.size() - std::distance(regions.begin(), lastRegion) - 1 << " out of " << regions.size() << " regions."); regions.resize(std::distance(regions.begin(), lastRegion) + 1); + modificationTime = checkModificationTime(); return parserReturned; } @@ -633,3 +635,19 @@ void sfz::Synth::resetAllControllers(int delay) noexcept region->registerCC(cc, 0); } } + +fs::file_time_type sfz::Synth::checkModificationTime() +{ + auto returnedTime = modificationTime; + for (auto file: getIncludedFiles()) { + const auto fileTime = fs::last_write_time(file); + if (returnedTime < fileTime) + returnedTime = fileTime; + } + return returnedTime; +} + +bool sfz::Synth::shouldReloadFile() +{ + return (checkModificationTime() > modificationTime); +} diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 1ef07d09..b9f25bfd 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -342,6 +342,17 @@ public: void disableFreeWheeling() noexcept; const MidiState& getMidiState() const noexcept { return midiState; } + + /** + * @brief Check if the SFZ should be reloaded. + * + * Depending on the platform this can create file descriptors. + * + * @return true if any included files (including the root file) have + * been modified since the sfz file was loaded. + * @return false + */ + bool shouldReloadFile(); protected: /** * @brief The parser callback; this is called by the parent object each time @@ -400,6 +411,8 @@ private: */ void buildRegion(const std::vector& regionOpcodes); + fs::file_time_type checkModificationTime(); + // Opcode memory; these are used to build regions, as a new region // will integrate opcodes from the group, master and global block std::vector globalOpcodes; @@ -454,6 +467,8 @@ private: int noteOffset { 0 }; int octaveOffset { 0 }; + fs::file_time_type modificationTime { }; + LEAK_DETECTOR(Synth); }; diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 0423e8ca..cdf2904f 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -239,6 +239,12 @@ char* sfizz_get_unknown_opcodes(sfizz_synth_t* synth) return opcodeList; } +bool sfizz_should_reload_file(sfizz_synth_t* synth) +{ + auto self = reinterpret_cast(synth); + return self->shouldReloadFile(); +} + #ifdef __cplusplus } #endif