From cced1034794a61049c06bf2bbbb3f458753ec06d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 15:11:50 +0200 Subject: [PATCH 1/6] Convert the oversampling to next power of 2 --- .gitignore | 2 ++ lv2/sfizz.c | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 7abb4c40..0c06dff6 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ node_modules/ *.lock *.sublime-* *.code-* +.kak.tags.namecache +.clangd diff --git a/lv2/sfizz.c b/lv2/sfizz.c index a4488941..c5d0c3c3 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -534,23 +534,39 @@ 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 uint32_t next_pow_2(uint32_t v) +{ + // 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) + if (*self->oversampling_port < 0) + return; + + uint32_t port_value = (uint32_t)*self->oversampling_port; + if (port_value == (uint32_t)self->oversampling) + return; + self->oversampling = (sfizz_oversampling_factor_t)next_pow_2(port_value); + + LV2_Atom_Int atom; + atom.atom.type = self->sfizz_oversampling_uri; + atom.atom.size = sizeof(int); + atom.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"); } } From 7d98349e1606190344a03a97e98d540ef433b544 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 15:17:03 +0200 Subject: [PATCH 2/6] Internally check that a change is needed or not --- lv2/sfizz.c | 11 ----------- src/sfizz/Synth.cpp | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index c5d0c3c3..59f5b1a8 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -950,10 +950,6 @@ work(LV2_Handle instance, 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); @@ -964,9 +960,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); @@ -978,10 +971,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/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); } From 2c5cc017cd18c50c86155fea64a1ac7e105ec05b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 21:56:22 +0200 Subject: [PATCH 3/6] use C struct init --- lv2/sfizz.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 59f5b1a8..493c1fed 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -558,10 +558,11 @@ sfizz_lv2_check_oversampling(sfizz_plugin_t* self) return; self->oversampling = (sfizz_oversampling_factor_t)next_pow_2(port_value); - LV2_Atom_Int atom; - atom.atom.type = self->sfizz_oversampling_uri; - atom.atom.size = sizeof(int); - atom.body = self->oversampling; + 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) @@ -576,10 +577,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) @@ -596,13 +598,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"); } @@ -942,9 +945,10 @@ 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) From 2e8b637f09e47518248f9b6c0dc5529039963b15 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 22:10:02 +0200 Subject: [PATCH 4/6] Update docs --- src/sfizz.h | 14 +++++++++++++- src/sfizz.hpp | 31 +++++++++++++++++++++++++++---- src/sfizz/Synth.h | 22 +++++++++++++++++----- 3 files changed, 57 insertions(+), 10 deletions(-) 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.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 */ From ff5a218f877aa95a3ee08919fea1eb187fd8043d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 22:13:30 +0200 Subject: [PATCH 5/6] Use int on oversampling to match the current api --- lv2/sfizz.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 493c1fed..3715cab7 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -534,8 +534,11 @@ 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 uint32_t next_pow_2(uint32_t v) +static int next_pow_2(int v) { + if (v < 1) + return 1; + // Bit twiddling hack v--; v |= v >> 1; @@ -553,8 +556,8 @@ sfizz_lv2_check_oversampling(sfizz_plugin_t* self) if (*self->oversampling_port < 0) return; - uint32_t port_value = (uint32_t)*self->oversampling_port; - if (port_value == (uint32_t)self->oversampling) + int port_value = (int)*self->oversampling_port; + if (port_value == (int)self->oversampling) return; self->oversampling = (sfizz_oversampling_factor_t)next_pow_2(port_value); From 893a9b312d23338acade840363fac18267f9f6b9 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 13 May 2020 23:28:21 +0200 Subject: [PATCH 6/6] Simplify the checks --- lv2/sfizz.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 3715cab7..89529d09 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -553,13 +553,11 @@ static int next_pow_2(int v) static void sfizz_lv2_check_oversampling(sfizz_plugin_t* self) { - if (*self->oversampling_port < 0) - return; - - int port_value = (int)*self->oversampling_port; + int port_value = next_pow_2((int)*self->oversampling_port); if (port_value == (int)self->oversampling) return; - self->oversampling = (sfizz_oversampling_factor_t)next_pow_2(port_value); + + self->oversampling = (sfizz_oversampling_factor_t)port_value; LV2_Atom_Int atom = { .atom.type = self->sfizz_oversampling_uri,