From 52949ea2bcb0ae2633b185190d0cb59f65e55c80 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 19 Dec 2021 21:57:02 +0100 Subject: [PATCH 1/4] Default to plugin-side automation Make each mode very separate (i.e. no PSA = midi ignored) --- cmake/LV2Config.cmake | 6 +++++- cmake/SfizzConfig.cmake | 1 + plugins/lv2/sfizz.cpp | 33 --------------------------------- plugins/lv2/sfizz_lv2_plugin.h | 4 ---- plugins/lv2/sfizz_ui.cpp | 11 +++++++++++ 5 files changed, 17 insertions(+), 38 deletions(-) diff --git a/cmake/LV2Config.cmake b/cmake/LV2Config.cmake index da2bd40ff..1d66df7a6 100644 --- a/cmake/LV2Config.cmake +++ b/cmake/LV2Config.cmake @@ -1,5 +1,5 @@ # This option is for MIDI CC support in absence of host midi:binding support -option(SFIZZ_LV2_PSA "Enable plugin-side MIDI automations" OFF) +option(SFIZZ_LV2_PSA "Enable plugin-side MIDI automations" ON) # Configuration for this plugin # TODO: generate version from git @@ -57,6 +57,10 @@ function(sfizz_lv2_generate_controllers_ttl FILE) ") math(EXPR _j "${SFIZZ_NUM_CCS}-1") foreach(_i RANGE "${_j}") + if(_i LESS 128 AND SFIZZ_LV2_PSA) + continue() # Don't generate automation parameters for CCs with plugin-side automation + endif() + string_left_pad(_i "${_i}" 3 0) file(APPEND "${FILE}" " sfizz:cc${_i} diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 74c0e6a9c..e1163fb00 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -159,6 +159,7 @@ Release asserts: ${SFIZZ_RELEASE_ASSERTS} Install prefix: ${CMAKE_INSTALL_PREFIX} LV2 destination directory: ${LV2PLUGIN_INSTALL_DIR} +LV2 plugin-side CC automation ${SFIZZ_LV2_PSA} Compiler CXX debug flags: ${CMAKE_CXX_FLAGS_DEBUG} Compiler CXX release flags: ${CMAKE_CXX_FLAGS_RELEASE} diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 03321b922..3998c0646 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -644,7 +644,6 @@ instantiate(const LV2_Descriptor *descriptor, self->ccmap = sfizz_lv2_ccmap_create(self->map); self->cc_current = new float[sfz::config::numCCs](); - self->ccauto = new absl::optional[sfz::config::numCCs]; self->synth = sfizz_create_synth(); self->client = sfizz_create_client(self); @@ -678,7 +677,6 @@ cleanup(LV2_Handle instance) spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); - delete[] self->ccauto; delete[] self->cc_current; sfizz_lv2_ccmap_free(self->ccmap); delete self; @@ -806,7 +804,6 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Obj float value = *(const float *)LV2_ATOM_BODY_CONST(atom); sfizz_automate_hdcc(self->synth, delay, cc, value); self->cc_current[cc] = value; - self->ccauto[cc] = absl::nullopt; } } else if (key == self->sfizz_sfz_file_uri) @@ -874,15 +871,6 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev) unsigned cc = msg[1]; float value = float(msg[2]) * (1.0f / 127.0f); - // Send - if (sfizz_is_sustain_or_sostenuto(self, cc)) { - sfizz_automate_hdcc(self->synth, - (int)ev->time.frames, - (int)cc, - value); - break; - } - // Note(jpc) CC must be mapped by host, not handled here. // See LV2 midi:binding. #if defined(SFIZZ_LV2_PSA) @@ -894,9 +882,6 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev) (int)ev->time.frames, (int)cc, value); - self->cc_current[cc] = value; - self->ccauto[cc] = value; - self->have_ccauto = true; } break; case LV2_MIDI_CTL_ALL_NOTES_OFF: @@ -1249,18 +1234,6 @@ run(LV2_Handle instance, uint32_t sample_count) self->midnam->update(self->midnam->handle); } - if (self->have_ccauto) - { - for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { - absl::optional value = self->ccauto[cc]; - if (value) { - sfizz_lv2_send_controller(self, self->patch_set_uri, cc, *value); - self->ccauto[cc] = absl::nullopt; - } - } - self->have_ccauto = false; - } - spin_mutex_unlock(self->synth_mutex); #if defined(SFIZZ_LV2_UI) @@ -1408,9 +1381,6 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self) const InstrumentDescription desc = parseDescriptionBlob(blob); for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { if (desc.ccUsed.test(cc) && !desc.sustainOrSostenuto.test(cc)) { - // Mark all the used CCs for automation with default values - self->ccauto[cc] = desc.ccValue[cc]; - self->have_ccauto = true; // Update the current CCs self->cc_current[cc] = desc.ccValue[cc]; } @@ -1579,9 +1549,6 @@ restore(LV2_Handle instance, if (value) { // Set CC in the synth sfizz_automate_hdcc(self->synth, 0, int(cc), *value); - // Mark CCs for automation with state values - self->ccauto[cc] = *value; - self->have_ccauto = true; // Update the current CCs self->cc_current[cc] = *value; } diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 26119138a..4e987e68e 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -140,10 +140,6 @@ struct sfizz_plugin_t // updated by hdcc or file load float *cc_current {}; - // CC queued for automation on next run(). (synchronized by `synth_mutex`) - absl::optional* ccauto {}; - volatile bool have_ccauto {}; - // Timing data int bar {}; double bar_beat {}; diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index cd25d2881..eb3045e24 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -761,6 +761,17 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) default: if (editIdIsCC(id)) { int cc = ccForEditId(id); +#if defined(SFIZZ_LV2_PSA) + if (cc >= 0 && cc < 128) { + // Send MIDI message + uint8_t msg[3]; + msg[0] = 0xB0; + msg[1] = static_cast(cc); + msg[2] = static_cast(v.to_float() * 127); + uiSendMIDI(msg, 3); + break; + } +#endif LV2_URID urid = sfizz_lv2_ccmap_map(ccmap.get(), cc); sendController(urid, v.to_float()); } From 5743c10631fc6569b1eb0960ff24ee5ad2917531 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 19 Dec 2021 22:33:57 +0100 Subject: [PATCH 2/4] Retrigger a note only if the cc value changed This won't remove the need for polyphony opcodes when using high-res CC, but at least it should help with automation lanes. Note: this is not what Sforzando does. --- src/sfizz/Layer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sfizz/Layer.cpp b/src/sfizz/Layer.cpp index 5d5f03b0f..f59976be9 100644 --- a/src/sfizz/Layer.cpp +++ b/src/sfizz/Layer.cpp @@ -179,7 +179,8 @@ bool Layer::registerCC(int ccNumber, float ccValue, float randValue) noexcept sequenceSwitched_ = ((sequenceCounter_++ % region.sequenceLength) == region.sequencePosition - 1); - if (isSwitchedOn()) + + if (isSwitchedOn() && (ccValue != midiState_.getCCValue(ccNumber))) return true; } From e378105fd0193b3db03ec0b3b2787327c4346354 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 19 Dec 2021 22:36:45 +0100 Subject: [PATCH 3/4] add PSA to the UI if we actually build the UI --- plugins/lv2/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt index 4bf680516..48924d789 100644 --- a/plugins/lv2/CMakeLists.txt +++ b/plugins/lv2/CMakeLists.txt @@ -35,7 +35,9 @@ endif() if(SFIZZ_LV2_PSA) target_compile_definitions(${LV2PLUGIN_PRJ_NAME} PRIVATE "SFIZZ_LV2_PSA=1") - target_compile_definitions(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "SFIZZ_LV2_PSA=1") + if(SFIZZ_LV2_UI) + target_compile_definitions(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "SFIZZ_LV2_PSA=1") + endif() endif() # Explicitely strip all symbols on Linux but lv2_descriptor() From a0b2542ea9fbf4c588a16f8be7c4ffb974edff09 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 19 Dec 2021 23:21:04 +0100 Subject: [PATCH 4/4] Change a test --- tests/SynthT.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 4974be3d9..e071b2c3a 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -1983,10 +1983,10 @@ TEST_CASE("[Synth] Sequences also work on cc triggers") synth.cc(0, 61, 20); synth.renderBlock(buffer); REQUIRE( playingSamples(synth) == std::vector { "*sine", "*saw" } ); - synth.cc(0, 61, 20); + synth.cc(0, 61, 21); synth.renderBlock(buffer); REQUIRE( playingSamples(synth) == std::vector { "*sine", "*saw" } ); - synth.cc(0, 61, 20); + synth.cc(0, 61, 22); synth.renderBlock(buffer); REQUIRE( playingSamples(synth) == std::vector { "*sine", "*saw", "*sine" } ); }