From 1c3104800a4a413dd25c91d960437437d0549e69 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 4 Apr 2021 16:28:08 +0200 Subject: [PATCH 01/17] CC as parameters for LV2 --- cmake/LV2Config.cmake | 43 ++++++++++++++++++++ cmake/StringUtility.cmake | 11 +++++ plugins/lv2/CMakeLists.txt | 3 ++ plugins/lv2/manifest.ttl.in | 2 +- plugins/lv2/sfizz.cpp | 73 +++++++++++++++++++++++++++++++++- plugins/lv2/sfizz.ttl.in | 4 +- plugins/lv2/sfizz_lv2_plugin.h | 6 +++ 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 cmake/StringUtility.cmake diff --git a/cmake/LV2Config.cmake b/cmake/LV2Config.cmake index ab7a1652..b9bd2791 100644 --- a/cmake/LV2Config.cmake +++ b/cmake/LV2Config.cmake @@ -40,3 +40,46 @@ else() set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING "Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/lv2]") endif() + +include(StringUtility) + +function(sfizz_lv2_generate_controllers_ttl FILE) + file(WRITE "${FILE}" "# LV2 parameters for SFZ controllers +@prefix atom: . +@prefix lv2: . +@prefix patch: . +@prefix rdfs: . +@prefix sfizz: <${LV2PLUGIN_URI}#> . +") + math(EXPR _j "${SFIZZ_NUM_CCS}-1") + foreach(_i RANGE "${_j}") + string_left_pad(_i "${_i}" 3 0) + file(APPEND "${FILE}" " +sfizz:cc${_i} + a lv2:Parameter ; + rdfs:label \"Controller ${_i}\" ; + rdfs:range atom:Float . +") + endforeach() + + file(APPEND "${FILE}" " +<${LV2PLUGIN_URI}> + a lv2:Plugin ; +") + + file(APPEND "${FILE}" " patch:readable sfizz:cc000") + foreach(_i RANGE 1 "${_j}") + string_left_pad(_i "${_i}" 3 0) + file(APPEND "${FILE}" ", sfizz:cc${_i}") + endforeach() + file(APPEND "${FILE}" " ; +") + + file(APPEND "${FILE}" " patch:writable sfizz:cc000") + foreach(_i RANGE 1 "${_j}") + string_left_pad(_i "${_i}" 3 0) + file(APPEND "${FILE}" ", sfizz:cc${_i}") + endforeach() + file(APPEND "${FILE}" " . +") +endfunction() diff --git a/cmake/StringUtility.cmake b/cmake/StringUtility.cmake new file mode 100644 index 00000000..3e8b4614 --- /dev/null +++ b/cmake/StringUtility.cmake @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-2-Clause + +function(string_left_pad VAR INPUT LENGTH FILLCHAR) + set(_output "${INPUT}") + string(LENGTH "${_output}" _length) + while(_length LESS "${LENGTH}") + string(PREPEND _output "${FILLCHAR}") + string(LENGTH "${_output}" _length) + endwhile() + set("${VAR}" "${_output}" PARENT_SCOPE) +endfunction() diff --git a/plugins/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt index 3f9a7247..2417e263 100644 --- a/plugins/lv2/CMakeLists.txt +++ b/plugins/lv2/CMakeLists.txt @@ -82,6 +82,9 @@ if(SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR}) endif() +# Generate controllers.ttl +sfizz_lv2_generate_controllers_ttl("${PROJECT_BINARY_DIR}/controllers.ttl") + # Copy resource files into the bundle set(LV2_RESOURCES DefaultInstrument.sfz diff --git a/plugins/lv2/manifest.ttl.in b/plugins/lv2/manifest.ttl.in index ab407d33..3c5a130c 100644 --- a/plugins/lv2/manifest.ttl.in +++ b/plugins/lv2/manifest.ttl.in @@ -5,7 +5,7 @@ <@LV2PLUGIN_URI@> a lv2:Plugin ; lv2:binary ; - rdfs:seeAlso <@PROJECT_NAME@.ttl> . + rdfs:seeAlso <@PROJECT_NAME@.ttl>, . @LV2PLUGIN_IF_ENABLE_UI@<@LV2PLUGIN_URI@#ui> @LV2PLUGIN_IF_ENABLE_UI@ a ui:@LV2_UI_TYPE@ ; diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index a0c94a0b..deb6ee73 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -329,6 +329,65 @@ sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* s (void)write_ok; } +static void +sfizz_lv2_setup_cc_parameters(sfizz_plugin_t* self) +{ + // store the associations between CC number and parameter URID + // construct it trivially in the form of a tabulated perfect hash function + + LV2_URID* cc_to_urid = new LV2_URID[sfz::config::numCCs]; + int* urid_to_cc; + int urid_to_cc_size; + + LV2_URID min_cc_urid {}; + LV2_URID max_cc_urid {}; + for (int cc = 0; cc < sfz::config::numCCs; ++cc) { + char name[256]; + sprintf(name, SFIZZ_URI "#cc%03d", cc); + LV2_URID urid = self->map->map(self->map->handle, name); + if (cc == 0) { + min_cc_urid = urid; + max_cc_urid = urid; + } + else { + min_cc_urid = (urid < min_cc_urid) ? urid : min_cc_urid; + max_cc_urid = (urid > max_cc_urid) ? urid : max_cc_urid; + } + cc_to_urid[cc] = urid; + } + + urid_to_cc_size = max_cc_urid - min_cc_urid + 1; + urid_to_cc = new int[urid_to_cc_size]; + + for (int i = 0; i < urid_to_cc_size; ++i) + urid_to_cc[i] = -1; + + for (int cc = 0; cc < sfz::config::numCCs; ++cc) { + LV2_URID urid = cc_to_urid[cc]; + urid_to_cc[urid - min_cc_urid] = cc; + } + + self->cc_to_urid = cc_to_urid; + self->urid_to_cc = urid_to_cc; + self->min_cc_urid = min_cc_urid; + self->max_cc_urid = max_cc_urid; +} + +static int +sfizz_lv2_get_cc_from_parameter_urid(const sfizz_plugin_t* self, LV2_URID urid) +{ + int cc = -1; + if (urid >= self->min_cc_urid && urid <= self->max_cc_urid) + cc = self->urid_to_cc[urid - self->min_cc_urid]; + return cc; +} + +static LV2_URID +sfizz_lv2_get_parameter_urid_from_cc(const sfizz_plugin_t* self, int cc) +{ + return self->cc_to_urid[cc]; +} + static LV2_Handle instantiate(const LV2_Descriptor *descriptor, double rate, @@ -476,6 +535,8 @@ instantiate(const LV2_Descriptor *descriptor, return NULL; } + sfizz_lv2_setup_cc_parameters(self); + self->synth = sfizz_create_synth(); self->client = sfizz_create_client(self); self->synth_mutex = spin_mutex_create(); @@ -501,6 +562,8 @@ cleanup(LV2_Handle instance) spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); + delete[] self->cc_to_urid; + delete[] self->urid_to_cc; delete self; } @@ -575,7 +638,14 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) char body[MAX_PATH_SIZE]; } sfizz_path_atom_buffer_t; - if (key == self->sfizz_sfz_file_uri) + int cc = sfizz_lv2_get_cc_from_parameter_urid(self, key); + if (cc != -1) { + if (atom->type == self->atom_float_uri && atom->size == sizeof(float)) { + float value = *(const float *)LV2_ATOM_BODY_CONST(atom); + // TODO: CC parameter arrived + } + } + else if (key == self->sfizz_sfz_file_uri) { LV2_Atom_Forge *forge = &self->forge_secondary; sfizz_path_atom_buffer_t buffer; @@ -796,6 +866,7 @@ run(LV2_Handle instance, uint32_t sample_count) if (ev->body.type == self->atom_object_uri || ev->body.type == self->atom_blank_uri) { const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + if (obj->body.otype == self->patch_set_uri) { sfizz_lv2_handle_atom_object(self, obj); diff --git a/plugins/lv2/sfizz.ttl.in b/plugins/lv2/sfizz.ttl.in index 45494016..38e67814 100644 --- a/plugins/lv2/sfizz.ttl.in +++ b/plugins/lv2/sfizz.ttl.in @@ -371,4 +371,6 @@ midnam:update a lv2:Feature . lv2:default 0 ; lv2:minimum 0 ; lv2:maximum 65535 ; - ] . + ] ; + + rdfs:seeAlso . diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 0d05a00b..638fb106 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -92,6 +92,12 @@ struct sfizz_plugin_t LV2_URID time_beats_per_minute_uri {}; LV2_URID time_speed_uri {}; + // CC parameters + LV2_URID* cc_to_urid {}; + int* urid_to_cc {}; + LV2_URID min_cc_urid {}; + LV2_URID max_cc_urid {}; + // Sfizz related data sfizz_synth_t *synth {}; sfizz_client_t *client {}; From f827f86a25572a05db3e86372b78c30a5b5d03b5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 00:39:10 +0200 Subject: [PATCH 02/17] Generate LV2 MIDI binding for CC 0 to 127 --- cmake/LV2Config.cmake | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmake/LV2Config.cmake b/cmake/LV2Config.cmake index b9bd2791..11330812 100644 --- a/cmake/LV2Config.cmake +++ b/cmake/LV2Config.cmake @@ -47,6 +47,7 @@ function(sfizz_lv2_generate_controllers_ttl FILE) file(WRITE "${FILE}" "# LV2 parameters for SFZ controllers @prefix atom: . @prefix lv2: . +@prefix midi: . @prefix patch: . @prefix rdfs: . @prefix sfizz: <${LV2PLUGIN_URI}#> . @@ -58,8 +59,20 @@ function(sfizz_lv2_generate_controllers_ttl FILE) sfizz:cc${_i} a lv2:Parameter ; rdfs:label \"Controller ${_i}\" ; - rdfs:range atom:Float . + rdfs:range atom:Float") + + if(_i LESS 128) + math(EXPR _digit1 "${_i}>>4") + math(EXPR _digit2 "${_i}&15") + string(SUBSTRING "0123456789ABCDEF" "${_digit1}" 1 _digit1) + string(SUBSTRING "0123456789ABCDEF" "${_digit2}" 1 _digit2) + file(APPEND "${FILE}" " ; + midi:binding \"B0${_digit1}${_digit2}00\"^^midi:MidiEvent . ") + else() + file(APPEND "${FILE}" " . +") + endif() endforeach() file(APPEND "${FILE}" " From 67b08f666392146574b443e7b2f448e4ddad2f19 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:31:46 +0200 Subject: [PATCH 03/17] Move ccmap in common LV2 --- plugins/lv2/sfizz.cpp | 66 ++------------------------ plugins/lv2/sfizz_lv2.h | 7 +++ plugins/lv2/sfizz_lv2_common.cpp | 79 ++++++++++++++++++++++++++++++++ plugins/lv2/sfizz_lv2_plugin.h | 5 +- 4 files changed, 90 insertions(+), 67 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index deb6ee73..5c159587 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -329,65 +329,6 @@ sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* s (void)write_ok; } -static void -sfizz_lv2_setup_cc_parameters(sfizz_plugin_t* self) -{ - // store the associations between CC number and parameter URID - // construct it trivially in the form of a tabulated perfect hash function - - LV2_URID* cc_to_urid = new LV2_URID[sfz::config::numCCs]; - int* urid_to_cc; - int urid_to_cc_size; - - LV2_URID min_cc_urid {}; - LV2_URID max_cc_urid {}; - for (int cc = 0; cc < sfz::config::numCCs; ++cc) { - char name[256]; - sprintf(name, SFIZZ_URI "#cc%03d", cc); - LV2_URID urid = self->map->map(self->map->handle, name); - if (cc == 0) { - min_cc_urid = urid; - max_cc_urid = urid; - } - else { - min_cc_urid = (urid < min_cc_urid) ? urid : min_cc_urid; - max_cc_urid = (urid > max_cc_urid) ? urid : max_cc_urid; - } - cc_to_urid[cc] = urid; - } - - urid_to_cc_size = max_cc_urid - min_cc_urid + 1; - urid_to_cc = new int[urid_to_cc_size]; - - for (int i = 0; i < urid_to_cc_size; ++i) - urid_to_cc[i] = -1; - - for (int cc = 0; cc < sfz::config::numCCs; ++cc) { - LV2_URID urid = cc_to_urid[cc]; - urid_to_cc[urid - min_cc_urid] = cc; - } - - self->cc_to_urid = cc_to_urid; - self->urid_to_cc = urid_to_cc; - self->min_cc_urid = min_cc_urid; - self->max_cc_urid = max_cc_urid; -} - -static int -sfizz_lv2_get_cc_from_parameter_urid(const sfizz_plugin_t* self, LV2_URID urid) -{ - int cc = -1; - if (urid >= self->min_cc_urid && urid <= self->max_cc_urid) - cc = self->urid_to_cc[urid - self->min_cc_urid]; - return cc; -} - -static LV2_URID -sfizz_lv2_get_parameter_urid_from_cc(const sfizz_plugin_t* self, int cc) -{ - return self->cc_to_urid[cc]; -} - static LV2_Handle instantiate(const LV2_Descriptor *descriptor, double rate, @@ -535,7 +476,7 @@ instantiate(const LV2_Descriptor *descriptor, return NULL; } - sfizz_lv2_setup_cc_parameters(self); + self->ccmap = sfizz_lv2_ccmap_create(self->map); self->synth = sfizz_create_synth(); self->client = sfizz_create_client(self); @@ -562,8 +503,7 @@ cleanup(LV2_Handle instance) spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); - delete[] self->cc_to_urid; - delete[] self->urid_to_cc; + sfizz_lv2_ccmap_free(self->ccmap); delete self; } @@ -638,7 +578,7 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) char body[MAX_PATH_SIZE]; } sfizz_path_atom_buffer_t; - int cc = sfizz_lv2_get_cc_from_parameter_urid(self, key); + int cc = sfizz_lv2_ccmap_unmap(self->ccmap, key); if (cc != -1) { if (atom->type == self->atom_float_uri && atom->size == sizeof(float)) { float value = *(const float *)LV2_ATOM_BODY_CONST(atom); diff --git a/plugins/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h index 68cb03be..5d82be52 100644 --- a/plugins/lv2/sfizz_lv2.h +++ b/plugins/lv2/sfizz_lv2.h @@ -85,3 +85,10 @@ struct sfizz_plugin_t; bool sfizz_lv2_fetch_description( sfizz_plugin_t *self, const int *serial, uint8_t **descp, uint32_t *sizep, int *serialp); + +// Mapping URID to CC and vice-versa +struct sfizz_lv2_ccmap; +sfizz_lv2_ccmap *sfizz_lv2_ccmap_create(LV2_URID_Map* map); +void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap); +LV2_URID sfizz_lv2_ccmap_map(const sfizz_lv2_ccmap *ccmap, int cc); +int sfizz_lv2_ccmap_unmap(const sfizz_lv2_ccmap *ccmap, LV2_URID urid); diff --git a/plugins/lv2/sfizz_lv2_common.cpp b/plugins/lv2/sfizz_lv2_common.cpp index ea6562bb..702557b7 100644 --- a/plugins/lv2/sfizz_lv2_common.cpp +++ b/plugins/lv2/sfizz_lv2_common.cpp @@ -6,6 +6,7 @@ #include "sfizz_lv2.h" #include "sfizz_lv2_plugin.h" +#include "sfizz/Config.h" bool sfizz_lv2_fetch_description( sfizz_plugin_t *self, const int *serial, @@ -29,3 +30,81 @@ bool sfizz_lv2_fetch_description( return true; } + +struct sfizz_lv2_ccmap { + LV2_URID *cc_to_urid; + int *urid_to_cc; + LV2_URID min_cc_urid; + LV2_URID max_cc_urid; +}; + +sfizz_lv2_ccmap * +sfizz_lv2_ccmap_create(LV2_URID_Map* map) +{ + // store the associations between CC number and parameter URID + // construct it trivially in the form of a tabulated perfect hash function + + LV2_URID* cc_to_urid = new LV2_URID[sfz::config::numCCs]; + int* urid_to_cc; + int urid_to_cc_size; + + LV2_URID min_cc_urid {}; + LV2_URID max_cc_urid {}; + for (int cc = 0; cc < sfz::config::numCCs; ++cc) { + char name[256]; + sprintf(name, SFIZZ_URI "#cc%03d", cc); + LV2_URID urid = map->map(map->handle, name); + if (cc == 0) { + min_cc_urid = urid; + max_cc_urid = urid; + } + else { + min_cc_urid = (urid < min_cc_urid) ? urid : min_cc_urid; + max_cc_urid = (urid > max_cc_urid) ? urid : max_cc_urid; + } + cc_to_urid[cc] = urid; + } + + urid_to_cc_size = max_cc_urid - min_cc_urid + 1; + urid_to_cc = new int[urid_to_cc_size]; + + for (int i = 0; i < urid_to_cc_size; ++i) + urid_to_cc[i] = -1; + + for (int cc = 0; cc < sfz::config::numCCs; ++cc) { + LV2_URID urid = cc_to_urid[cc]; + urid_to_cc[urid - min_cc_urid] = cc; + } + + sfizz_lv2_ccmap *self = new sfizz_lv2_ccmap; + self->cc_to_urid = cc_to_urid; + self->urid_to_cc = urid_to_cc; + self->min_cc_urid = min_cc_urid; + self->max_cc_urid = max_cc_urid; + return self; +} + +void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap) +{ + if (ccmap) { + delete[] ccmap->cc_to_urid; + delete[] ccmap->urid_to_cc; + delete ccmap; + } +} + +LV2_URID sfizz_lv2_ccmap_map(sfizz_lv2_ccmap *ccmap, int cc) +{ + LV2_URID urid = 0; + if (cc >= 0 && cc < sfz::config::numCCs) + urid = ccmap->cc_to_urid[cc]; + return urid; +} + +int sfizz_lv2_ccmap_unmap(const sfizz_lv2_ccmap *ccmap, LV2_URID urid) +{ + int cc = -1; + if (urid >= ccmap->min_cc_urid && urid <= ccmap->max_cc_urid) + cc = ccmap->urid_to_cc[urid - ccmap->min_cc_urid]; + return cc; +} diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 638fb106..ff4fd23b 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -93,10 +93,7 @@ struct sfizz_plugin_t LV2_URID time_speed_uri {}; // CC parameters - LV2_URID* cc_to_urid {}; - int* urid_to_cc {}; - LV2_URID min_cc_urid {}; - LV2_URID max_cc_urid {}; + sfizz_lv2_ccmap* ccmap {}; // Sfizz related data sfizz_synth_t *synth {}; From ccdbd4a61a97744197f37b4e4aa3fa7a1511db18 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:36:18 +0200 Subject: [PATCH 04/17] Instantiate ccmap on UI side --- plugins/lv2/sfizz_lv2.h | 4 ++++ plugins/lv2/sfizz_ui.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/plugins/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h index 5d82be52..06c078a7 100644 --- a/plugins/lv2/sfizz_lv2.h +++ b/plugins/lv2/sfizz_lv2.h @@ -92,3 +92,7 @@ sfizz_lv2_ccmap *sfizz_lv2_ccmap_create(LV2_URID_Map* map); void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap); LV2_URID sfizz_lv2_ccmap_map(const sfizz_lv2_ccmap *ccmap, int cc); int sfizz_lv2_ccmap_unmap(const sfizz_lv2_ccmap *ccmap, LV2_URID urid); + +struct sfizz_lv2_ccmap_delete { + void operator()(sfizz_lv2_ccmap* ccmap) const noexcept { sfizz_lv2_ccmap_free(ccmap); } +}; diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index d6073939..3986b41a 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -112,6 +112,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { LV2_URID sfizz_sfz_file_uri; LV2_URID sfizz_scala_file_uri; LV2_URID sfizz_osc_blob_uri; + std::unique_ptr ccmap; uint8_t osc_temp[OSC_TEMP_SIZE]; alignas(LV2_Atom) uint8_t atom_temp[ATOM_TEMP_SIZE]; @@ -211,6 +212,7 @@ instantiate(const LV2UI_Descriptor *descriptor, self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile); self->sfizz_scala_file_uri = map->map(map->handle, SFIZZ__tuningfile); self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob); + self->ccmap.reset(sfizz_lv2_ccmap_create(map)); // set up the resource path // * on Linux, this is determined by going 2 folders back from the SO path From c7db9656a2949973e8f12750cdc25c380075e1bc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:38:15 +0200 Subject: [PATCH 05/17] lv2: process CC by parameters in and out --- plugins/lv2/sfizz.cpp | 55 ++++++++++++++++++++++++++++++---- plugins/lv2/sfizz_lv2_plugin.h | 6 ++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 5c159587..244c368b 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -485,6 +485,7 @@ instantiate(const LV2_Descriptor *descriptor, sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); self->sfz_blob_mutex = new std::mutex; + self->sfz_desc_mutex = new std::mutex; sfizz_lv2_load_file(self, self->sfz_file_path); sfizz_lv2_load_scala_file(self, self->scala_file_path); @@ -500,6 +501,8 @@ cleanup(LV2_Handle instance) sfizz_plugin_t *self = (sfizz_plugin_t *)instance; delete[] self->sfz_blob_data; delete self->sfz_blob_mutex; + delete self->sfz_desc; + delete self->sfz_desc_mutex; spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); @@ -541,7 +544,25 @@ sfizz_lv2_send_file_path(sfizz_plugin_t *self, LV2_URID urid, const char *path) } static void -sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) +sfizz_lv2_send_controller(sfizz_plugin_t *self, unsigned cc, float value) +{ + LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); + LV2_Atom_Forge_Frame frame; + + bool write_ok = + lv2_atom_forge_frame_time(&self->forge, 0) && + lv2_atom_forge_object(&self->forge, &frame, 0, self->patch_set_uri) && + lv2_atom_forge_key(&self->forge, self->patch_property_uri) && + lv2_atom_forge_urid(&self->forge, urid) && + lv2_atom_forge_key(&self->forge, self->patch_value_uri) && + lv2_atom_forge_float(&self->forge, value); + + if (write_ok) + lv2_atom_forge_pop(&self->forge, &frame); +} + +static void +sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Object *obj) { const LV2_Atom *property = NULL; lv2_atom_object_get(obj, self->patch_property_uri, &property, 0); @@ -582,7 +603,7 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) if (cc != -1) { if (atom->type == self->atom_float_uri && atom->size == sizeof(float)) { float value = *(const float *)LV2_ATOM_BODY_CONST(atom); - // TODO: CC parameter arrived + sfizz_send_hdcc(self->synth, delay, cc, value); } } else if (key == self->sfizz_sfz_file_uri) @@ -639,12 +660,14 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev) (int)msg[1], msg[2]); break; - case LV2_MIDI_MSG_CONTROLLER: + // Note(jpc) CC must be mapped by host, not handled here. + // See LV2 midi:binding. + /*case LV2_MIDI_MSG_CONTROLLER: sfizz_send_cc(self->synth, (int)ev->time.frames, (int)msg[1], msg[2]); - break; + break;*/ case LV2_MIDI_MSG_CHANNEL_PRESSURE: sfizz_send_aftertouch(self->synth, (int)ev->time.frames, @@ -809,7 +832,7 @@ run(LV2_Handle instance, uint32_t sample_count) if (obj->body.otype == self->patch_set_uri) { - sfizz_lv2_handle_atom_object(self, obj); + sfizz_lv2_handle_atom_object(self, delay, obj); } else if (obj->body.otype == self->patch_get_uri) { @@ -970,6 +993,19 @@ run(LV2_Handle instance, uint32_t sample_count) self->midnam->update(self->midnam->handle); } + if (self->must_automate_cc && self->sfz_desc_mutex->try_lock()) + { + if (self->must_automate_cc) { + const InstrumentDescription* desc = self->sfz_desc; + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + if (desc->ccUsed.test(cc)) + sfizz_lv2_send_controller(self, cc, desc->ccDefault[cc]); + } + self->must_automate_cc = false; + } + self->sfz_desc_mutex->unlock(); + } + lv2_atom_forge_pop(&self->forge, ¬ify_frame); } @@ -1074,6 +1110,7 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self) { const std::string blob = getDescriptionBlob(self->synth); + // Update description blob that UI can fetch, thread-safely uint32_t size = uint32_t(blob.size()); uint8_t *data = new uint8_t[size]; memcpy(data, blob.data(), size); @@ -1086,6 +1123,14 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self) self->sfz_blob_mutex->unlock(); delete[] old_data; + + // Keep a copy of the instrument description + const InstrumentDescription* desc = new InstrumentDescription(parseDescriptionBlob(blob)); + self->sfz_desc_mutex->lock(); + delete self->sfz_desc; + self->sfz_desc = desc; + self->must_automate_cc = true; // mark all CC for automation + self->sfz_desc_mutex->unlock(); } static bool diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index ff4fd23b..179b95bc 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -14,6 +14,8 @@ #include #include +struct InstrumentDescription; + #define DEFAULT_SCALA_FILE "Contents/Resources/DefaultScale.scl" #define DEFAULT_SFZ_FILE "Contents/Resources/DefaultInstrument.sfz" // This assumes that the longest path is the default sfz file; if not, change it @@ -111,6 +113,7 @@ struct sfizz_plugin_t int sample_counter {}; float sample_rate {}; std::atomic must_update_midnam {}; + volatile bool must_automate_cc {}; // Current instrument description std::mutex *sfz_blob_mutex {}; @@ -118,6 +121,9 @@ struct sfizz_plugin_t const uint8_t *volatile sfz_blob_data {}; volatile uint32_t sfz_blob_size {}; + std::mutex *sfz_desc_mutex {}; + const InstrumentDescription* sfz_desc {}; + // Timing data int bar {}; double bar_beat {}; From b40e8f44762c5a6b04c099246299bf727af9242b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:47:21 +0200 Subject: [PATCH 06/17] Fix mismatched function signature --- plugins/lv2/sfizz_lv2_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lv2/sfizz_lv2_common.cpp b/plugins/lv2/sfizz_lv2_common.cpp index 702557b7..7881db1d 100644 --- a/plugins/lv2/sfizz_lv2_common.cpp +++ b/plugins/lv2/sfizz_lv2_common.cpp @@ -93,7 +93,7 @@ void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap) } } -LV2_URID sfizz_lv2_ccmap_map(sfizz_lv2_ccmap *ccmap, int cc) +LV2_URID sfizz_lv2_ccmap_map(const sfizz_lv2_ccmap *ccmap, int cc) { LV2_URID urid = 0; if (cc >= 0 && cc < sfz::config::numCCs) From 803c4f296e425e4f87b7b7e3ae5cc200cae90bf8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:51:40 +0200 Subject: [PATCH 07/17] Have UI receive CC by parameter --- plugins/lv2/sfizz.cpp | 1 - plugins/lv2/sfizz_ui.cpp | 12 +++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 244c368b..53647a28 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -983,7 +983,6 @@ run(LV2_Handle instance, uint32_t sample_count) sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count); // Request OSC updates - sfizz_send_message(self->synth, self->client, 0, "/cc/changed~", "", nullptr); sfizz_send_message(self->synth, self->client, 0, "/sw/last/current", "", nullptr); spin_mutex_unlock(self->synth_mutex); diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index 3986b41a..db91b4e0 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -102,6 +102,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { LV2_Atom_Forge atom_forge; LV2_URID atom_event_transfer_uri; LV2_URID atom_object_uri; + LV2_URID atom_float_uri; LV2_URID atom_path_uri; LV2_URID atom_urid_uri; LV2_URID midi_event_uri; @@ -202,6 +203,7 @@ instantiate(const LV2UI_Descriptor *descriptor, lv2_atom_forge_init(forge, map); self->atom_event_transfer_uri = map->map(map->handle, LV2_ATOM__eventTransfer); self->atom_object_uri = map->map(map->handle, LV2_ATOM__Object); + self->atom_float_uri = map->map(map->handle, LV2_ATOM__Float); self->atom_path_uri = map->map(map->handle, LV2_ATOM__Path); self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID); self->midi_event_uri = map->map(map->handle, LV2_MIDI__MidiEvent); @@ -350,7 +352,15 @@ port_event(LV2UI_Handle ui, const LV2_URID prop_uri = reinterpret_cast(prop)->body; auto *value_body = reinterpret_cast(LV2_ATOM_BODY_CONST(value)); - if (prop_uri == self->sfizz_sfz_file_uri && value->type == self->atom_path_uri) { + int cc = sfizz_lv2_ccmap_unmap(self->ccmap.get(), prop_uri); + + if (cc != -1) { + if (value->type == self->atom_float_uri) { + float ccvalue = *reinterpret_cast(value_body); + self->uiReceiveValue(editIdForCC(cc), ccvalue); + } + } + else if (prop_uri == self->sfizz_sfz_file_uri && value->type == self->atom_path_uri) { std::string path(value_body, strnlen(value_body, value->size)); self->uiReceiveValue(EditId::SfzFile, path); } From 62919343c3fb15c2ca1fcc8dd7968735a43704a6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 02:55:53 +0200 Subject: [PATCH 08/17] Have editor respond to 'CC' EditId --- plugins/editor/src/editor/Editor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index e8bcf7b7..0dfb875b 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -476,6 +476,9 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) else if (editIdIsKeyswitchLabel(id)) { updateSWLastLabel(keyswitchLabelForEditId(id), v.to_string().c_str()); } + else if (editIdIsCC(id)) { + updateCCValue(unsigned(ccForEditId(id)), v.to_float()); + } else if (editIdIsCCUsed(id)) { updateCCUsed(ccUsedForEditId(id), v.to_float() != 0); // TODO(jpc) remove value requests, when implementing CC automation From 308eb788e67ed6a521818ef26a8cd8638442d06b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 03:10:00 +0200 Subject: [PATCH 09/17] Allow the script to work in older cmake --- cmake/StringUtility.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/StringUtility.cmake b/cmake/StringUtility.cmake index 3e8b4614..00c5ba5c 100644 --- a/cmake/StringUtility.cmake +++ b/cmake/StringUtility.cmake @@ -4,7 +4,7 @@ function(string_left_pad VAR INPUT LENGTH FILLCHAR) set(_output "${INPUT}") string(LENGTH "${_output}" _length) while(_length LESS "${LENGTH}") - string(PREPEND _output "${FILLCHAR}") + set(_output "${FILLCHAR}${_output}") string(LENGTH "${_output}" _length) endwhile() set("${VAR}" "${_output}" PARENT_SCOPE) From 2436414ad8c56829354350cdc935329b023daa3d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 17:06:17 +0200 Subject: [PATCH 10/17] Allow UI to send value by controller --- plugins/editor/src/editor/Editor.cpp | 15 ++++++++------- plugins/editor/src/editor/Editor.h | 4 ++++ plugins/lv2/sfizz_ui.cpp | 21 +++++++++++++++++++++ plugins/vst/SfizzVstEditor.cpp | 13 ++++++++++++- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 0dfb875b..d91e20cc 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -306,6 +306,12 @@ void Editor::close() } } +void Editor::sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args) +{ + Impl& impl = *impl_; + impl.sendQueuedOSC(path, sig, args); +} + void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) { switch (id) { @@ -1613,13 +1619,8 @@ void Editor::Impl::updateMemoryUsed(uint64_t mem) void Editor::Impl::performCCValueChange(unsigned cc, float value) { - // TODO(jpc) CC as parameters and automation - - char pathBuf[256]; - sprintf(pathBuf, "/cc%u/value", cc); - sfizz_arg_t args[1]; - args[0].f = value; - sendQueuedOSC(pathBuf, "f", args); + EditorController& ctrl = *ctrl_; + ctrl.uiSendValue(editIdForCC(int(cc)), value); } void Editor::Impl::performCCBeginEdit(unsigned cc) diff --git a/plugins/editor/src/editor/Editor.h b/plugins/editor/src/editor/Editor.h index 0c0ae1de..4345426c 100644 --- a/plugins/editor/src/editor/Editor.h +++ b/plugins/editor/src/editor/Editor.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include #include class EditorController; @@ -24,6 +25,9 @@ public: void open(CFrame& frame); void close(); + // TODO(jpc) remove me after doing parameter automations + void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args); + private: struct Impl; std::unique_ptr impl_; diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index db91b4e0..581f373f 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -537,6 +537,22 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) } }; + auto sendController = [this](LV2_URID property, float value) { + LV2_Atom_Forge *forge = &atom_forge; + LV2_Atom_Forge_Frame frame; + auto *atom = reinterpret_cast(atom_temp); + lv2_atom_forge_set_buffer(forge, atom_temp, sizeof(atom_temp)); + if (lv2_atom_forge_object(forge, &frame, 0, patch_set_uri) && + lv2_atom_forge_key(forge, patch_property_uri) && + lv2_atom_forge_urid(forge, property) && + lv2_atom_forge_key(forge, patch_value_uri) && + lv2_atom_forge_float(forge, value)) + { + lv2_atom_forge_pop(forge, &frame); + write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom); + } + }; + switch (id) { case EditId::Volume: sendFloat(SFIZZ_VOLUME, v.to_float()); @@ -566,6 +582,11 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) sendPath(sfizz_scala_file_uri, v.to_string()); break; default: + if (editIdIsCC(id)) { + int cc = ccForEditId(id); + LV2_URID urid = sfizz_lv2_ccmap_map(ccmap.get(), cc); + sendController(urid, v.to_float()); + } break; } } diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index decc6f43..eff7462f 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -329,7 +329,18 @@ void SfizzVstEditor::processNoteEventQueue() /// void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) { - if (id == EditId::SfzFile) + if (editIdIsCC(id)) { + int cc = ccForEditId(id); + // TODO(jpc) CC as parameters and automation + if (Editor* editor = editor_.get()) { + char pathBuf[256]; + sprintf(pathBuf, "/cc%u/value", cc); + sfizz_arg_t args[1]; + args[0].f = v.to_float(); + editor->sendQueuedOSC(pathBuf, "f", args); + } + } + else if (id == EditId::SfzFile) loadSfzFile(v.to_string()); else if (id == EditId::ScalaFile) loadScalaFile(v.to_string()); From d2d01b73b37a915d48f174f32aab755566bbb315 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 19:01:36 +0200 Subject: [PATCH 11/17] Structure for storage of CC automation --- plugins/lv2/sfizz.cpp | 40 +++++++++++++++++----------------- plugins/lv2/sfizz_lv2_plugin.h | 8 +++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 53647a28..d9e278dc 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -478,6 +478,8 @@ instantiate(const LV2_Descriptor *descriptor, self->ccmap = sfizz_lv2_ccmap_create(self->map); + self->ccauto = new absl::optional[sfz::config::numCCs]; + self->synth = sfizz_create_synth(); self->client = sfizz_create_client(self); self->synth_mutex = spin_mutex_create(); @@ -485,7 +487,6 @@ instantiate(const LV2_Descriptor *descriptor, sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); self->sfz_blob_mutex = new std::mutex; - self->sfz_desc_mutex = new std::mutex; sfizz_lv2_load_file(self, self->sfz_file_path); sfizz_lv2_load_scala_file(self, self->scala_file_path); @@ -501,11 +502,10 @@ cleanup(LV2_Handle instance) sfizz_plugin_t *self = (sfizz_plugin_t *)instance; delete[] self->sfz_blob_data; delete self->sfz_blob_mutex; - delete self->sfz_desc; - delete self->sfz_desc_mutex; spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); + delete[] self->ccauto; sfizz_lv2_ccmap_free(self->ccmap); delete self; } @@ -985,26 +985,25 @@ run(LV2_Handle instance, uint32_t sample_count) // Request OSC updates sfizz_send_message(self->synth, self->client, 0, "/sw/last/current", "", nullptr); - spin_mutex_unlock(self->synth_mutex); - if (self->midnam && self->must_update_midnam.exchange(0)) { self->midnam->update(self->midnam->handle); } - if (self->must_automate_cc && self->sfz_desc_mutex->try_lock()) + if (self->have_ccauto) { - if (self->must_automate_cc) { - const InstrumentDescription* desc = self->sfz_desc; - for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { - if (desc->ccUsed.test(cc)) - sfizz_lv2_send_controller(self, cc, desc->ccDefault[cc]); + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + absl::optional value = self->ccauto[cc]; + if (value) { + sfizz_lv2_send_controller(self, cc, *value); + self->ccauto[cc] = absl::nullopt; } - self->must_automate_cc = false; } - self->sfz_desc_mutex->unlock(); + self->have_ccauto = false; } + spin_mutex_unlock(self->synth_mutex); + lv2_atom_forge_pop(&self->forge, ¬ify_frame); } @@ -1123,13 +1122,14 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self) delete[] old_data; - // Keep a copy of the instrument description - const InstrumentDescription* desc = new InstrumentDescription(parseDescriptionBlob(blob)); - self->sfz_desc_mutex->lock(); - delete self->sfz_desc; - self->sfz_desc = desc; - self->must_automate_cc = true; // mark all CC for automation - self->sfz_desc_mutex->unlock(); + // Mark all the used CCs for automation with default values + const InstrumentDescription desc = parseDescriptionBlob(blob); + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + if (desc.ccUsed.test(cc)) { + self->ccauto[cc] = desc.ccDefault[cc]; + self->have_ccauto = true; + } + } } static bool diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 179b95bc..c7487f47 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -11,11 +11,10 @@ #include #include #include +#include #include #include -struct InstrumentDescription; - #define DEFAULT_SCALA_FILE "Contents/Resources/DefaultScale.scl" #define DEFAULT_SFZ_FILE "Contents/Resources/DefaultInstrument.sfz" // This assumes that the longest path is the default sfz file; if not, change it @@ -121,8 +120,9 @@ struct sfizz_plugin_t const uint8_t *volatile sfz_blob_data {}; volatile uint32_t sfz_blob_size {}; - std::mutex *sfz_desc_mutex {}; - const InstrumentDescription* sfz_desc {}; + // CC queued for automation on next run(). (synchronized by `synth_mutex`) + absl::optional* ccauto {}; + volatile bool have_ccauto {}; // Timing data int bar {}; From 1daffe137858ea72f7fccc11901705abdc13437d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 5 Apr 2021 21:20:10 +0200 Subject: [PATCH 12/17] WIP CC save and load --- plugins/lv2/sfizz.cpp | 66 +++++++++++++++++++++++++++++++--- plugins/lv2/sfizz_lv2_plugin.h | 4 +++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index d9e278dc..85f6917c 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -42,6 +42,8 @@ #include #include +#include + #define CHANNEL_MASK 0x0F #define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK) #define MIDI_STATUS(byte) (byte & ~CHANNEL_MASK) @@ -477,7 +479,7 @@ 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(); @@ -506,6 +508,7 @@ cleanup(LV2_Handle instance) sfizz_delete_client(self->client); sfizz_free(self->synth); delete[] self->ccauto; + delete[] self->cc_current; sfizz_lv2_ccmap_free(self->ccmap); delete self; } @@ -604,6 +607,7 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Obj if (atom->type == self->atom_float_uri && atom->size == sizeof(float)) { float value = *(const float *)LV2_ATOM_BODY_CONST(atom); sfizz_send_hdcc(self->synth, delay, cc, value); + self->cc_current[cc] = value; } } else if (key == self->sfizz_sfz_file_uri) @@ -842,6 +846,11 @@ run(LV2_Handle instance, uint32_t sample_count) { sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path); sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path); + + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); + sfizz_lv2_send_controller(self, urid, self->cc_current[cc]); + } } else if (property->body == self->sfizz_sfz_file_uri) { @@ -851,6 +860,12 @@ run(LV2_Handle instance, uint32_t sample_count) { sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path); } + else + { + int cc = sfizz_lv2_ccmap_unmap(self->ccmap, property->body); + if (cc != -1) + sfizz_lv2_send_controller(self, property->body, self->cc_current[cc]); + } } else if (obj->body.otype == self->time_position_uri) { @@ -1122,12 +1137,15 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self) delete[] old_data; - // Mark all the used CCs for automation with default values + // const InstrumentDescription desc = parseDescriptionBlob(blob); for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { if (desc.ccUsed.test(cc)) { + // Mark all the used CCs for automation with default values self->ccauto[cc] = desc.ccDefault[cc]; self->have_ccauto = true; + // Update the current CCs + self->cc_current[cc] = desc.ccDefault[cc]; } } } @@ -1275,6 +1293,17 @@ restore(LV2_Handle instance, self->oversampling = oversampling; } + // Collect all CC values present in the state + std::unique_ptr[]> cc_values( + new absl::optional[sfz::config::numCCs]); + + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); + value = retrieve(handle, urid, &size, &type, &val_flags); + if (value && type == self->atom_float_uri) + cc_values[cc] = *(const float *)value; + } + // Sync the parameters to the synth spin_mutex_lock(self->synth_mutex); @@ -1313,6 +1342,15 @@ restore(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling); sfizz_set_oversampling_factor(self->synth, self->oversampling); + // Override default automation values with these from the state file + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + absl::optional value = cc_values[cc]; + if (value) { + self->ccauto[cc] = *value; + self->have_ccauto = true; + } + } + spin_mutex_unlock(self->synth_mutex); return status; @@ -1382,7 +1420,7 @@ save(LV2_Handle instance, &self->num_voices, sizeof(int), self->atom_int_uri, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + LV2_STATE_IS_POD); // Save the preload size store(handle, @@ -1390,7 +1428,7 @@ save(LV2_Handle instance, &self->preload_size, sizeof(unsigned int), self->atom_int_uri, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + LV2_STATE_IS_POD); // Save the preload size store(handle, @@ -1398,7 +1436,25 @@ save(LV2_Handle instance, &self->oversampling, sizeof(int), self->atom_int_uri, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + LV2_STATE_IS_POD); + + // Save the CCs (used only) + self->sfz_blob_mutex->lock(); + const InstrumentDescription desc = parseDescriptionBlob( + absl::string_view((const char*)self->sfz_blob_data, self->sfz_blob_size)); + self->sfz_blob_mutex->unlock(); + + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { + if (desc.ccUsed.test(cc)) { + LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); + store(handle, + urid, + &self->cc_current[cc], + sizeof(float), + self->atom_float_uri, + LV2_STATE_IS_POD); + } + } return LV2_STATE_SUCCESS; } diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index c7487f47..5555d994 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -120,6 +120,10 @@ struct sfizz_plugin_t const uint8_t *volatile sfz_blob_data {}; volatile uint32_t sfz_blob_size {}; + // Current CC values in the synth (synchronized by `synth_mutex`) + // 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 {}; From a92c4fde3c1b91a81a70ded26675fa8ded7e3160 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 6 Apr 2021 00:18:25 +0200 Subject: [PATCH 13/17] Fix an error where controller is wrongly addressed --- plugins/lv2/sfizz.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 85f6917c..e5afaa05 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -847,10 +847,8 @@ run(LV2_Handle instance, uint32_t sample_count) sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path); sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path); - for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { - LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); - sfizz_lv2_send_controller(self, urid, self->cc_current[cc]); - } + for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) + sfizz_lv2_send_controller(self, cc, self->cc_current[cc]); } else if (property->body == self->sfizz_sfz_file_uri) { @@ -864,7 +862,7 @@ run(LV2_Handle instance, uint32_t sample_count) { int cc = sfizz_lv2_ccmap_unmap(self->ccmap, property->body); if (cc != -1) - sfizz_lv2_send_controller(self, property->body, self->cc_current[cc]); + sfizz_lv2_send_controller(self, unsigned(cc), self->cc_current[cc]); } } else if (obj->body.otype == self->time_position_uri) From 2cca5c31f3233037483a6e7ba0fded7f458a4517 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 6 Apr 2021 00:22:25 +0200 Subject: [PATCH 14/17] Have distinct output port for notifying and automating --- plugins/lv2/sfizz.cpp | 79 +++++++++++++++++++--------------- plugins/lv2/sfizz.ttl.in | 43 ++++++++++-------- plugins/lv2/sfizz_lv2.h | 33 +++++++------- plugins/lv2/sfizz_lv2_plugin.h | 4 +- 4 files changed, 91 insertions(+), 68 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index e5afaa05..ed335d0b 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -203,6 +203,9 @@ connect_port(LV2_Handle instance, case SFIZZ_NOTIFY: self->notify_port = (LV2_Atom_Sequence *)data; break; + case SFIZZ_AUTOMATE: + self->automate_port = (LV2_Atom_Sequence *)data; + break; case SFIZZ_LEFT: self->output_buffers[0] = (float *)data; break; @@ -322,11 +325,12 @@ sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* s if (osc_size > OSC_TEMP_SIZE) return; + LV2_Atom_Forge* forge = &self->forge_notify; bool write_ok = - lv2_atom_forge_frame_time(&self->forge, 0) && - lv2_atom_forge_atom(&self->forge, osc_size, self->sfizz_osc_blob_uri) && - lv2_atom_forge_raw(&self->forge, osc_temp, osc_size); - lv2_atom_forge_pad(&self->forge, osc_size); + lv2_atom_forge_frame_time(forge, 0) && + lv2_atom_forge_atom(forge, osc_size, self->sfizz_osc_blob_uri) && + lv2_atom_forge_raw(forge, osc_temp, osc_size); + lv2_atom_forge_pad(forge, osc_size); (void)write_ok; } @@ -428,7 +432,8 @@ instantiate(const LV2_Descriptor *descriptor, sfizz_lv2_map_required_uris(self); // Initialize the forge - lv2_atom_forge_init(&self->forge, self->map); + lv2_atom_forge_init(&self->forge_notify, self->map); + lv2_atom_forge_init(&self->forge_automate, self->map); lv2_atom_forge_init(&self->forge_secondary, self->map); // Check the options for the block size and sample rate parameters @@ -530,38 +535,38 @@ deactivate(LV2_Handle instance) } static void -sfizz_lv2_send_file_path(sfizz_plugin_t *self, LV2_URID urid, const char *path) +sfizz_lv2_send_file_path(sfizz_plugin_t *self, LV2_Atom_Forge* forge, LV2_URID urid, const char *path) { LV2_Atom_Forge_Frame frame; bool write_ok = - lv2_atom_forge_frame_time(&self->forge, 0) && - lv2_atom_forge_object(&self->forge, &frame, 0, self->patch_set_uri) && - lv2_atom_forge_key(&self->forge, self->patch_property_uri) && - lv2_atom_forge_urid(&self->forge, urid) && - lv2_atom_forge_key(&self->forge, self->patch_value_uri) && - lv2_atom_forge_path(&self->forge, path, (uint32_t)strlen(path)); + lv2_atom_forge_frame_time(forge, 0) && + lv2_atom_forge_object(forge, &frame, 0, self->patch_set_uri) && + lv2_atom_forge_key(forge, self->patch_property_uri) && + lv2_atom_forge_urid(forge, urid) && + lv2_atom_forge_key(forge, self->patch_value_uri) && + lv2_atom_forge_path(forge, path, (uint32_t)strlen(path)); if (write_ok) - lv2_atom_forge_pop(&self->forge, &frame); + lv2_atom_forge_pop(forge, &frame); } static void -sfizz_lv2_send_controller(sfizz_plugin_t *self, unsigned cc, float value) +sfizz_lv2_send_controller(sfizz_plugin_t *self, LV2_Atom_Forge* forge, unsigned cc, float value) { LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc)); LV2_Atom_Forge_Frame frame; bool write_ok = - lv2_atom_forge_frame_time(&self->forge, 0) && - lv2_atom_forge_object(&self->forge, &frame, 0, self->patch_set_uri) && - lv2_atom_forge_key(&self->forge, self->patch_property_uri) && - lv2_atom_forge_urid(&self->forge, urid) && - lv2_atom_forge_key(&self->forge, self->patch_value_uri) && - lv2_atom_forge_float(&self->forge, value); + lv2_atom_forge_frame_time(forge, 0) && + lv2_atom_forge_object(forge, &frame, 0, self->patch_set_uri) && + lv2_atom_forge_key(forge, self->patch_property_uri) && + lv2_atom_forge_urid(forge, urid) && + lv2_atom_forge_key(forge, self->patch_value_uri) && + lv2_atom_forge_float(forge, value); if (write_ok) - lv2_atom_forge_pop(&self->forge, &frame); + lv2_atom_forge_pop(forge, &frame); } static void @@ -807,7 +812,7 @@ static void run(LV2_Handle instance, uint32_t sample_count) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; - assert(self->control_port && self->notify_port); + assert(self->control_port && self->notify_port && self->automate_port); if (!spin_mutex_trylock(self->synth_mutex)) { @@ -816,13 +821,18 @@ run(LV2_Handle instance, uint32_t sample_count) return; } - // Set up forge to write directly to notify output port. + // Set up dedicated forges to write on their respective ports. const size_t notify_capacity = self->notify_port->atom.size; - lv2_atom_forge_set_buffer(&self->forge, (uint8_t *)self->notify_port, notify_capacity); + lv2_atom_forge_set_buffer(&self->forge_notify, (uint8_t *)self->notify_port, notify_capacity); + const size_t automate_capacity = self->automate_port->atom.size; + lv2_atom_forge_set_buffer(&self->forge_automate, (uint8_t *)self->automate_port, automate_capacity); - // Start a sequence in the notify output port. + // Start sequences in the respective output ports. LV2_Atom_Forge_Frame notify_frame; - if (!lv2_atom_forge_sequence_head(&self->forge, ¬ify_frame, 0)) + if (!lv2_atom_forge_sequence_head(&self->forge_notify, ¬ify_frame, 0)) + assert(false); + LV2_Atom_Forge_Frame automate_frame; + if (!lv2_atom_forge_sequence_head(&self->forge_automate, &automate_frame, 0)) assert(false); LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev) @@ -844,25 +854,25 @@ run(LV2_Handle instance, uint32_t sample_count) lv2_atom_object_get(obj, self->patch_property_uri, &property, 0); if (!property) // Send the full state { - sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path); - sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path); + sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_sfz_file_uri, self->sfz_file_path); + sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_scala_file_uri, self->scala_file_path); for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) - sfizz_lv2_send_controller(self, cc, self->cc_current[cc]); + sfizz_lv2_send_controller(self, &self->forge_notify, cc, self->cc_current[cc]); } else if (property->body == self->sfizz_sfz_file_uri) { - sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path); + sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_sfz_file_uri, self->sfz_file_path); } else if (property->body == self->sfizz_scala_file_uri) { - sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path); + sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_scala_file_uri, self->scala_file_path); } else { int cc = sfizz_lv2_ccmap_unmap(self->ccmap, property->body); if (cc != -1) - sfizz_lv2_send_controller(self, unsigned(cc), self->cc_current[cc]); + sfizz_lv2_send_controller(self, &self->forge_notify, unsigned(cc), self->cc_current[cc]); } } else if (obj->body.otype == self->time_position_uri) @@ -1008,7 +1018,7 @@ run(LV2_Handle instance, uint32_t sample_count) for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { absl::optional value = self->ccauto[cc]; if (value) { - sfizz_lv2_send_controller(self, cc, *value); + sfizz_lv2_send_controller(self, &self->forge_automate, cc, *value); self->ccauto[cc] = absl::nullopt; } } @@ -1017,7 +1027,8 @@ run(LV2_Handle instance, uint32_t sample_count) spin_mutex_unlock(self->synth_mutex); - lv2_atom_forge_pop(&self->forge, ¬ify_frame); + lv2_atom_forge_pop(&self->forge_notify, ¬ify_frame); + lv2_atom_forge_pop(&self->forge_automate, &automate_frame); } static uint32_t diff --git a/plugins/lv2/sfizz.ttl.in b/plugins/lv2/sfizz.ttl.in index 38e67814..112a970c 100644 --- a/plugins/lv2/sfizz.ttl.in +++ b/plugins/lv2/sfizz.ttl.in @@ -104,29 +104,38 @@ midnam:update a lv2:Feature . a lv2:OutputPort, atom:AtomPort ; atom:bufferType atom:Sequence ; atom:supports patch:Message, <@LV2PLUGIN_URI@:OSCBlob> ; - lv2:designation lv2:control ; lv2:index 1 ; lv2:symbol "notify" ; lv2:name "Notify", "Notification"@fr ; rsz:minimumSize 65536 ; ] , [ - a lv2:AudioPort, lv2:OutputPort ; + a lv2:OutputPort, atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports patch:Message ; + lv2:designation lv2:control ; lv2:index 2 ; + lv2:symbol "automate" ; + lv2:name "Automate", + "Automatisation"@fr ; + rsz:minimumSize 65536 ; + ] , [ + a lv2:AudioPort, lv2:OutputPort ; + lv2:index 3 ; lv2:symbol "out_left" ; lv2:name "Left Output", "Sortie gauche"@fr , "Uscita Sinistra"@it ] , [ a lv2:AudioPort, lv2:OutputPort ; - lv2:index 3 ; + lv2:index 4 ; lv2:symbol "out_right" ; lv2:name "Right Output", "Sortie droite"@fr , "Uscita Destra"@it ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 4 ; + lv2:index 5 ; lv2:symbol "volume" ; lv2:name "Volume" ; lv2:default 0.0 ; @@ -135,7 +144,7 @@ midnam:update a lv2:Feature . units:unit units:db ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 5 ; + lv2:index 6 ; lv2:symbol "num_voices" ; lv2:name "Polyphony", "Polyphonie"@fr , @@ -180,7 +189,7 @@ midnam:update a lv2:Feature . ] ; ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 6 ; + lv2:index 7 ; lv2:symbol "oversampling" ; lv2:name "Internal oversampling factor", "Facteur de suréchantillonnage interne"@fr , @@ -215,7 +224,7 @@ midnam:update a lv2:Feature . ] ; ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 7 ; + lv2:index 8 ; lv2:symbol "preload_size" ; lv2:name "Preload size", "Taille préchargée"@fr , @@ -258,7 +267,7 @@ midnam:update a lv2:Feature . ] ; ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 8 ; + lv2:index 9 ; lv2:symbol "freewheeling" ; lv2:name "Freewheeling", "En roue libre (freewheeling)"@fr , @@ -270,7 +279,7 @@ midnam:update a lv2:Feature . lv2:maximum 1 ; ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 9 ; + lv2:index 10 ; lv2:symbol "scala_root_key" ; lv2:name "Scala root key", "Tonalité de base Scala"@fr , @@ -283,7 +292,7 @@ midnam:update a lv2:Feature . units:unit units:midiNote ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 10 ; + lv2:index 11 ; lv2:symbol "tuning_frequency" ; lv2:name "Tuning frequency", "Fréquence d'accordage"@fr , @@ -295,7 +304,7 @@ midnam:update a lv2:Feature . units:unit units:hz ] , [ a lv2:InputPort, lv2:ControlPort ; - lv2:index 11 ; + lv2:index 12 ; lv2:symbol "stretched_tuning" ; lv2:name "Stretched tuning", "Accordage étiré"@fr , @@ -307,7 +316,7 @@ midnam:update a lv2:Feature . units:unit units:coef ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 12 ; + lv2:index 13 ; lv2:symbol "active_voices" ; lv2:name "Active voices", "Voix utilisées"@fr ; @@ -318,7 +327,7 @@ midnam:update a lv2:Feature . lv2:maximum 256 ; ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 13 ; + lv2:index 14 ; lv2:symbol "num_curves" ; lv2:name "Number of curves", "Nombre de courbes"@fr ; @@ -329,7 +338,7 @@ midnam:update a lv2:Feature . lv2:maximum 65535 ; ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 14 ; + lv2:index 15 ; lv2:symbol "num_masters" ; lv2:name "Number of masters", "Nombre de maîtres"@fr ; @@ -340,7 +349,7 @@ midnam:update a lv2:Feature . lv2:maximum 65535 ; ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 15 ; + lv2:index 16 ; lv2:symbol "num_groups" ; lv2:name "Number of groups", "Nombre de groupes"@fr ; @@ -351,7 +360,7 @@ midnam:update a lv2:Feature . lv2:maximum 65535 ; ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 16 ; + lv2:index 17 ; lv2:symbol "num_regions" ; lv2:name "Number of regions", "Nombre de régions"@fr ; @@ -362,7 +371,7 @@ midnam:update a lv2:Feature . lv2:maximum 65535 ; ] , [ a lv2:OutputPort, lv2:ControlPort ; - lv2:index 17 ; + lv2:index 18 ; lv2:symbol "num_samples" ; lv2:name "Number of samples", "Nombre d'échantillons"@fr ; diff --git a/plugins/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h index 06c078a7..678f0c02 100644 --- a/plugins/lv2/sfizz_lv2.h +++ b/plugins/lv2/sfizz_lv2.h @@ -49,22 +49,23 @@ enum { SFIZZ_CONTROL = 0, SFIZZ_NOTIFY = 1, - SFIZZ_LEFT = 2, - SFIZZ_RIGHT = 3, - SFIZZ_VOLUME = 4, - SFIZZ_POLYPHONY = 5, - SFIZZ_OVERSAMPLING = 6, - SFIZZ_PRELOAD = 7, - SFIZZ_FREEWHEELING = 8, - SFIZZ_SCALA_ROOT_KEY = 9, - SFIZZ_TUNING_FREQUENCY = 10, - SFIZZ_STRETCH_TUNING = 11, - SFIZZ_ACTIVE_VOICES = 12, - SFIZZ_NUM_CURVES = 13, - SFIZZ_NUM_MASTERS = 14, - SFIZZ_NUM_GROUPS = 15, - SFIZZ_NUM_REGIONS = 16, - SFIZZ_NUM_SAMPLES = 17, + SFIZZ_AUTOMATE = 2, + SFIZZ_LEFT = 3, + SFIZZ_RIGHT = 4, + SFIZZ_VOLUME = 5, + SFIZZ_POLYPHONY = 6, + SFIZZ_OVERSAMPLING = 7, + SFIZZ_PRELOAD = 8, + SFIZZ_FREEWHEELING = 9, + SFIZZ_SCALA_ROOT_KEY = 10, + SFIZZ_TUNING_FREQUENCY = 11, + SFIZZ_STRETCH_TUNING = 12, + SFIZZ_ACTIVE_VOICES = 13, + SFIZZ_NUM_CURVES = 14, + SFIZZ_NUM_MASTERS = 15, + SFIZZ_NUM_GROUPS = 16, + SFIZZ_NUM_REGIONS = 17, + SFIZZ_NUM_SAMPLES = 18, }; // For use with instance-access diff --git a/plugins/lv2/sfizz_lv2_plugin.h b/plugins/lv2/sfizz_lv2_plugin.h index 5555d994..348e417d 100644 --- a/plugins/lv2/sfizz_lv2_plugin.h +++ b/plugins/lv2/sfizz_lv2_plugin.h @@ -32,6 +32,7 @@ struct sfizz_plugin_t // Ports const LV2_Atom_Sequence *control_port {}; LV2_Atom_Sequence *notify_port {}; + LV2_Atom_Sequence *automate_port {}; float *output_buffers[2] {}; const float *volume_port {}; const float *polyphony_port {}; @@ -49,7 +50,8 @@ struct sfizz_plugin_t float *num_samples_port {}; // Atom forge - LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread + LV2_Atom_Forge forge_notify {}; ///< Forge for writing notification atoms in run thread + LV2_Atom_Forge forge_automate {}; ///< Forge for writing automation atoms in run thread LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers // Logger From cb85ca39708b7d12bd9f38bb55941d3f2acfc4cd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 6 Apr 2021 00:33:04 +0200 Subject: [PATCH 15/17] Track current CC values after restore --- plugins/lv2/sfizz.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index ed335d0b..08c7e328 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -1355,8 +1355,11 @@ restore(LV2_Handle instance, for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { absl::optional value = cc_values[cc]; if (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; } } From 68ee6775bb6525c3229be1532459c094c3f2489f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 6 Apr 2021 00:39:46 +0200 Subject: [PATCH 16/17] Let's not forget to send synth CC on restore --- plugins/lv2/sfizz.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 08c7e328..aaeab58a 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -1355,6 +1355,8 @@ restore(LV2_Handle instance, for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) { absl::optional value = cc_values[cc]; if (value) { + // Set CC in the synth + sfizz_send_hdcc(self->synth, 0, int(cc), *value); // Mark CCs for automation with state values self->ccauto[cc] = *value; self->have_ccauto = true; From 4731bef9e1dc1fe8ae66122597c065f473a6e441 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 6 Apr 2021 00:43:30 +0200 Subject: [PATCH 17/17] Have editor only request value when CC is used --- plugins/editor/src/editor/Editor.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index d91e20cc..914181ae 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -486,11 +486,14 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) updateCCValue(unsigned(ccForEditId(id)), v.to_float()); } else if (editIdIsCCUsed(id)) { - updateCCUsed(ccUsedForEditId(id), v.to_float() != 0); + bool used = v.to_float() != 0; + updateCCUsed(ccUsedForEditId(id), used); // TODO(jpc) remove value requests, when implementing CC automation - char pathBuf[256]; - sprintf(pathBuf, "/cc%u/value", ccUsedForEditId(id)); - sendQueuedOSC(pathBuf, "", nullptr); + if (used) { + char pathBuf[256]; + sprintf(pathBuf, "/cc%u/value", ccUsedForEditId(id)); + sendQueuedOSC(pathBuf, "", nullptr); + } } else if (editIdIsCCDefault(id)) { updateCCDefaultValue(ccDefaultForEditId(id), v.to_float());