diff --git a/.gitignore b/.gitignore index fdafa3d3..8f4dc499 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ node_modules/ *.lock *.sublime-* *.code-* +.kak.tags.namecache +.clangd diff --git a/lv2/sfizz.c b/lv2/sfizz.c index a4488941..89529d09 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -534,23 +534,41 @@ sfizz_lv2_status_log(sfizz_plugin_t *self) // lv2_log_note(&self->logger, "[sfizz] Active voices: %d\n", sfizz_get_num_active_voices(self->synth)); } +static int next_pow_2(int v) +{ + if (v < 1) + return 1; + + // Bit twiddling hack + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + static void sfizz_lv2_check_oversampling(sfizz_plugin_t* self) { - sfizz_oversampling_factor_t oversampling = (sfizz_oversampling_factor_t)*self->oversampling_port; - if (oversampling != self->oversampling) + int port_value = next_pow_2((int)*self->oversampling_port); + if (port_value == (int)self->oversampling) + return; + + self->oversampling = (sfizz_oversampling_factor_t)port_value; + + LV2_Atom_Int atom = { + .atom.type = self->sfizz_oversampling_uri, + .atom.size = sizeof(int), + .body = self->oversampling + }; + if (self->worker->schedule_work(self->worker->handle, + lv2_atom_total_size((LV2_Atom *)&atom), + &atom) != LV2_WORKER_SUCCESS) { - LV2_Atom_Int atom; - atom.atom.type = self->sfizz_oversampling_uri; - atom.atom.size = sizeof(int); - atom.body = oversampling; - if (self->worker->schedule_work(self->worker->handle, - lv2_atom_total_size((LV2_Atom *)&atom), - &atom) != LV2_WORKER_SUCCESS) - { - lv2_log_error(&self->logger, "[sfizz] There was an issue changing the oversampling factor\n"); - } - self->oversampling = oversampling; + lv2_log_error(&self->logger, "[sfizz] There was an issue changing the oversampling factor\n"); } } @@ -560,10 +578,11 @@ sfizz_lv2_check_preload_size(sfizz_plugin_t* self) unsigned int preload_size = (int)*self->preload_port; if (preload_size != self->preload_size) { - LV2_Atom_Int atom; - atom.atom.type = self->sfizz_preload_size_uri; - atom.atom.size = sizeof(int); - atom.body = preload_size; + LV2_Atom_Int atom = { + .atom.type = self->sfizz_preload_size_uri, + .atom.size = sizeof(int), + .body = preload_size + }; if (self->worker->schedule_work(self->worker->handle, lv2_atom_total_size((LV2_Atom *)&atom), &atom) != LV2_WORKER_SUCCESS) @@ -580,13 +599,14 @@ sfizz_lv2_check_num_voices(sfizz_plugin_t* self) int num_voices = (int)*self->polyphony_port; if (num_voices != self->num_voices) { - LV2_Atom_Int num_voices_atom; - num_voices_atom.atom.type = self->sfizz_num_voices_uri; - num_voices_atom.atom.size = sizeof(int); - num_voices_atom.body = num_voices; + LV2_Atom_Int atom = { + .atom.type = self->sfizz_num_voices_uri, + .atom.size = sizeof(int), + .body = num_voices + }; if (self->worker->schedule_work(self->worker->handle, - lv2_atom_total_size((LV2_Atom *)&num_voices_atom), - &num_voices_atom) != LV2_WORKER_SUCCESS) + lv2_atom_total_size((LV2_Atom *)&atom), + &atom) != LV2_WORKER_SUCCESS) { lv2_log_error(&self->logger, "[sfizz] There was an issue changing the number of voices\n"); } @@ -926,18 +946,15 @@ work(LV2_Handle instance, } // Reactivate checking for file changes - LV2_Atom check_modification_atom; - check_modification_atom.size = 0; - check_modification_atom.type = self->sfizz_check_modification_uri; + LV2_Atom check_modification_atom = { + .size = 0, + .type = self->sfizz_check_modification_uri + }; respond(handle, lv2_atom_total_size(&check_modification_atom), &check_modification_atom); } else if (atom->type == self->sfizz_num_voices_uri) { const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom); - if (sfizz_get_num_voices(self->synth) == num_voices) { - return LV2_WORKER_SUCCESS; // Nothing to do - } - sfizz_set_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); @@ -948,9 +965,6 @@ 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); - if (sfizz_get_preload_size(self->synth) == preload_size) - return LV2_WORKER_SUCCESS; // Nothing to do - sfizz_set_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); @@ -962,10 +976,6 @@ work(LV2_Handle instance, { const sfizz_oversampling_factor_t oversampling = *(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom); - if (sfizz_get_oversampling_factor(self->synth) == oversampling) { - return LV2_WORKER_SUCCESS; // Nothing to do - } - sfizz_set_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); diff --git a/src/sfizz.h b/src/sfizz.h index 69be1a4a..13432f5d 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -247,7 +247,10 @@ SFIZZ_EXPORTED_API unsigned int sfizz_get_preload_size(sfizz_synth_t* synth); /** * @brief Set the size of the preloaded data in number of floats (not * bytes). This will disable the callbacks for the duration of the - * load. + * load. This function takes a lock ; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new preload size is the same as the current one, it will + * release the lock immediately and exit. * * @param synth The synth. * @param[in] preload_size The preload size. @@ -277,6 +280,11 @@ SFIZZ_EXPORTED_API sfizz_oversampling_factor_t sfizz_get_oversampling_factor(sfi * to compensate for the memory increase, but the full loading will * need to take place anyway. * + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new oversampling factor is the same as the current one, it will + * release the lock immediately and exit. + * * @param synth The synth. * @param[in] oversampling The oversampling factor. * @@ -301,6 +309,10 @@ SFIZZ_EXPORTED_API float sfizz_get_volume(sfizz_synth_t* synth); /** * @brief Set the number of voices used by the synth. + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new number of voices is the same as the current one, it will + * release the lock immediately and exit. * * @param synth The synth. * @param num_voices The number of voices. diff --git a/src/sfizz.hpp b/src/sfizz.hpp index 4c58fe81..63bd8173 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -214,15 +214,34 @@ public: /** * @brief Change the number of voices (the polyphony). + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new number of voices is the same as the current one, it will + * release the lock immediately and exit. * * @param numVoices The number of voices. */ void setNumVoices(int numVoices) noexcept; /** - * @brief Set the oversampling factor to a new value. This will disable all callbacks - * kill all the voices, and trigger a reloading of every file in the FilePool under - * the new oversampling. + * @brief Set the oversampling factor to a new value. + * It will kill all the voices, and trigger a reloading of every file in + * the FilePool under the new oversampling. + * + * Increasing this value (up to x8 oversampling) improves the + * quality of the output at the expense of memory consumption and + * background loading speed. The main render path still uses the + * same linear interpolation algorithm and should not see its + * performance decrease, but the files are oversampled upon loading + * which increases the stress on the background loader and reduce + * the loading speed. You can tweak the size of the preloaded data + * to compensate for the memory increase, but the full loading will + * need to take place anyway. + * + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new oversampling factor is the same as the current one, it will + * release the lock immediately and exit. * * @param factor The oversampling factor. * @@ -236,7 +255,11 @@ public: int getOversamplingFactor() const noexcept; /** - * @brief Set the preloaded file size. This will disable the callback. + * @brief Set the preloaded file size. + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new preload size is the same as the current one, it will + * release the lock immediately and exit. * * @param preloadSize The preload size. */ diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index f3c9e2cf..7267a1c1 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1054,6 +1054,11 @@ void sfz::Synth::setNumVoices(int numVoices) noexcept { ASSERT(numVoices > 0); const std::lock_guard disableCallback { callbackGuard }; + + // fast path + if (numVoices == this->numVoices) + return; + resetVoices(numVoices); } @@ -1077,6 +1082,10 @@ void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept { const std::lock_guard disableCallback { callbackGuard }; + // fast path + if (factor == oversamplingFactor) + return; + for (auto& voice : voices) voice->reset(); @@ -1094,6 +1103,10 @@ void sfz::Synth::setPreloadSize(uint32_t preloadSize) noexcept { const std::lock_guard disableCallback { callbackGuard }; + // fast path + if (preloadSize == resources.filePool.getPreloadSize()) + return; + resources.filePool.setPreloadSize(preloadSize); } diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index bc73dc46..5cbeb455 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -286,7 +286,11 @@ public: */ int getNumVoices() const noexcept; /** - * @brief Change the number of voices (the polyphony) + * @brief Change the number of voices (the polyphony). + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new number of voices is the same as the current one, it will + * release the lock immediately and exit. * * @param numVoices */ @@ -302,9 +306,13 @@ public: void garbageCollect() noexcept; /** - * @brief Set the oversampling factor to a new value. This will disable all callbacks - * kill all the voices, and trigger a reloading of every file in the FilePool under - * the new oversampling. + * @brief Set the oversampling factor to a new value. + * It will kill all the voices, and trigger a reloading of every file in + * the FilePool under the new oversampling. + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new oversampling factor is the same as the current one, it will + * release the lock immediately and exit. * * @param factor */ @@ -318,7 +326,11 @@ public: Oversampling getOversamplingFactor() const noexcept; /** - * @brief Set the preloaded file size. This will disable the callback. + * @brief Set the preloaded file size. + * This function takes a lock and disables the callback; prefer calling + * it out of the RT thread. It can also take a long time to return. + * If the new preload size is the same as the current one, it will + * release the lock immediately and exit. * * @param factor */