From 5a0aafa793716bdc23b0831a8d61c541f21b690a Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 12:23:17 +0200 Subject: [PATCH 01/13] Parse label_noteNN and add getters for the labels in the internal API --- src/sfizz/SfzHelpers.h | 4 +++- src/sfizz/Synth.cpp | 12 +++++++++--- src/sfizz/Synth.h | 20 ++++++++++++++++++-- tests/FilesT.cpp | 18 ++++++++++++++++++ tests/TestFiles/labels.sfz | 7 +++++++ 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/TestFiles/labels.sfz diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 60979282..57bf109f 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -20,7 +20,9 @@ namespace sfz { -using CCNamePair = std::pair; +using CCNamePair = std::pair; +using NoteNamePair = std::pair; + template using MidiNoteArray = std::array; template diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index fd12b218..fd3b5587 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -142,7 +142,9 @@ void sfz::Synth::clear() numMasters = 0; defaultSwitch = absl::nullopt; defaultPath = ""; - ccNames.clear(); + resources.midiState.reset(); + ccLabels.clear(); + noteLabels.clear(); globalOpcodes.clear(); masterOpcodes.clear(); groupOpcodes.clear(); @@ -208,7 +210,11 @@ void sfz::Synth::handleControlOpcodes(const std::vector& members) case hash("Label_cc&"): // fallthrough case hash("label_cc&"): if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) - ccNames.emplace_back(member.parameters.back(), std::string(member.value)); + ccLabels.emplace_back(member.parameters.back(), std::string(member.value)); + break; + case hash("label_note&"): + if (Default::keyRange.containsWithEnd(member.parameters.back())) + noteLabels.emplace_back(member.parameters.back(), std::string(member.value)); break; case hash("Default_path"): // fallthrough @@ -871,7 +877,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node cns = device.append_child("ControlNameList"); cns.append_attribute("Name").set_value("Controls"); - for (const CCNamePair& pair : ccNames) { + for (const CCNamePair& pair : ccLabels) { pugi::xml_node cn = cns.append_child("Control"); cn.append_attribute("Type").set_value("7bit"); cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 4d34d8e8..0f34fdb7 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -388,6 +388,19 @@ public: */ const Parser& getParser() const noexcept { return parser; } + /** + * @brief Get the note labels, if any + * + * @return const std::vector& + */ + const std::vector& getNoteLabels() const noexcept { return noteLabels; } + /** + * @brief Get the CC labels, if any + * + * @return const std::vector& + */ + const std::vector& getCCLabels() const noexcept { return ccLabels; } + protected: /** * @brief The parser callback; this is called by the parent object each time @@ -494,8 +507,11 @@ private: * @return Voice* */ Voice* findFreeVoice() noexcept; - // Names for the cc as set by the label_cc opcode - std::vector ccNames; + + // Names for the CC and notes as set by label_cc and label_note + std::vector ccLabels; + std::vector noteLabels; + // Default active switch if multiple keyswitchable regions are present absl::optional defaultSwitch; std::vector unknownOpcodes; diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 4dd43c8f..d7bedade 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -563,3 +563,21 @@ TEST_CASE("[Files] Empty file") REQUIRE(!synth.loadSfzFile({})); REQUIRE(parser.getIncludedFiles().empty()); } + +TEST_CASE("[Files] Labels") +{ + sfz::Synth synth; + synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels.sfz"); + auto noteLabels = synth.getNoteLabels(); + auto ccLabels = synth.getCCLabels(); + REQUIRE( noteLabels.size() == 2); + REQUIRE( noteLabels[0].first == 12 ); + REQUIRE( noteLabels[0].second == "Cymbals" ); + REQUIRE( noteLabels[1].first == 65 ); + REQUIRE( noteLabels[1].second == "Crash" ); + REQUIRE( ccLabels.size() == 2); + REQUIRE( ccLabels[0].first == 54 ); + REQUIRE( ccLabels[0].second == "Gain" ); + REQUIRE( ccLabels[1].first == 2 ); + REQUIRE( ccLabels[1].second == "Other" ); +} diff --git a/tests/TestFiles/labels.sfz b/tests/TestFiles/labels.sfz new file mode 100644 index 00000000..49f51ed5 --- /dev/null +++ b/tests/TestFiles/labels.sfz @@ -0,0 +1,7 @@ + +label_cc54=Gain +label_cc2=Other +label_note12=Cymbals +label_note65=Crash +label_note128=Ignored + sample=*sine From c075e40c23003f47637c97b736314859341140fc Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 12:57:03 +0200 Subject: [PATCH 02/13] Added public API bindings --- src/sfizz.h | 51 +++++++++++++++++++++++++ src/sfizz.hpp | 16 +++++++- src/sfizz/SfzHelpers.h | 2 +- src/sfizz/sfizz.cpp | 10 +++++ src/sfizz/sfizz_wrapper.cpp | 75 +++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 2 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index 69faa3ed..63482393 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -394,6 +394,57 @@ SFIZZ_EXPORTED_API void sfizz_add_external_definitions(sfizz_synth_t* synth, con */ SFIZZ_EXPORTED_API void sfizz_clear_external_definitions(sfizz_synth_t* synth); +#define SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX -1 + +/** + * @brief Get the number of note labels registered in the current sfz file + * @version 0.4.0-dev + */ +SFIZZ_EXPORTED_API unsigned int sfizz_get_num_note_labels(sfizz_synth_t* synth); + +/** + * @brief Get the note number for the label registered at index label_index. + * @version 0.4.0-dev + * + * @returns SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. + * @returns the number + */ +SFIZZ_EXPORTED_API int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index); + +/** + * @brief Get the note text for the label registered at index label_index. + * @version 0.4.0-dev + * + * @returns NULL if the index is out of bounds. + * @returns the label + */ +SFIZZ_EXPORTED_API const char * sfizz_get_note_label_text(sfizz_synth_t* synth, int label_index); + +/** + * @brief Get the number of note labels registered in the current sfz file + * @version 0.4.0-dev + * + */ +SFIZZ_EXPORTED_API unsigned int sfizz_get_num_cc_labels(sfizz_synth_t* synth); + +/** + * @brief Get the CC number for the label registered at index label_index. + * @version 0.4.0-dev + * + * @returns SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. + * @returns the number + */ + +SFIZZ_EXPORTED_API int sfizz_get_cc_label_number(sfizz_synth_t* synth, int label_index); +/** + * @brief Get the CC text for the label registered at index label_index. + * @version 0.4.0-dev + * + * @returns NULL if the index is out of bounds. + * @returns the label + */ +SFIZZ_EXPORTED_API const char * sfizz_get_cc_label_text(sfizz_synth_t* synth, int label_index); + #ifdef __cplusplus } #endif diff --git a/src/sfizz.hpp b/src/sfizz.hpp index 49e9cd7a..d726d6c5 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -287,7 +288,8 @@ public: void setLoggingPrefix(const std::string& prefix) noexcept; /** - * @brief Disable logging. + * @brief + * */ void disableLogging() noexcept; @@ -312,6 +314,18 @@ public: */ void clearExternalDefinitions(); + /** + * @brief Get the note labels, if any + * @version 0.4.0-dev + * + */ + const std::vector>& getNoteLabels() const noexcept; + /** + * @brief Get the CC labels, if any + * @version 0.4.0-dev + * + */ + const std::vector>& getCCLabels() const noexcept; private: std::unique_ptr synth; }; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 57bf109f..5d581a74 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -20,7 +20,7 @@ namespace sfz { -using CCNamePair = std::pair; +using CCNamePair = std::pair; using NoteNamePair = std::pair; template diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 3e17af01..97e52cd4 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -220,3 +220,13 @@ void sfz::Sfizz::clearExternalDefinitions() { synth->getParser().clearExternalDefinitions(); } + +const std::vector>& sfz::Sfizz::getNoteLabels() const noexcept +{ + return synth->getNoteLabels(); +} + +const std::vector>& sfz::Sfizz::getCCLabels() const noexcept +{ + return synth->getCCLabels(); +} diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 3c9d88f0..c614bf44 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -8,6 +8,7 @@ #include "Macros.h" #include "Synth.h" #include "sfizz.h" +#include #ifdef __cplusplus extern "C" { @@ -268,6 +269,80 @@ void sfizz_clear_external_definitions(sfizz_synth_t* synth) self->getParser().clearExternalDefinitions(); } +unsigned int sfizz_get_num_note_labels(sfizz_synth_t* synth) +{ + auto self = reinterpret_cast(synth); + return self->getNoteLabels().size(); +} + +int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index) +{ + auto self = reinterpret_cast(synth); + const auto noteLabels = self->getNoteLabels(); + if (label_index < 0) + return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; + + if (static_cast(label_index) >= noteLabels.size()) + return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; + + // Sanity checks for the future or platforms + static_assert( + std::numeric_limits::max() < std::numeric_limits::max(), + "The C API sends back an int but the note index in NoteNamePair can overflow it on this platform" + ); + return static_cast(noteLabels[label_index].first); +} + +const char * sfizz_get_note_label_text(sfizz_synth_t* synth, int label_index) +{ + auto self = reinterpret_cast(synth); + const auto noteLabels = self->getNoteLabels(); + if (label_index < 0) + return NULL; + + if (static_cast(label_index) >= noteLabels.size()) + return NULL; + + return noteLabels[label_index].second.c_str(); +} + +unsigned int sfizz_get_num_cc_labels(sfizz_synth_t* synth) +{ + auto self = reinterpret_cast(synth); + return self->getCCLabels().size(); +} + +int sfizz_get_cc_label_number(sfizz_synth_t* synth, int label_index) +{ + auto self = reinterpret_cast(synth); + const auto ccLabels = self->getCCLabels(); + if (label_index < 0) + return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; + + if (static_cast(label_index) >= ccLabels.size()) + return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; + + // Sanity checks for the future or platforms + static_assert( + std::numeric_limits::max() < std::numeric_limits::max(), + "The C API sends back an int but the cc index in CCNamePair can overflow it on this platform" + ); + return static_cast(ccLabels[label_index].first); +} + +const char * sfizz_get_cc_label_text(sfizz_synth_t* synth, int label_index) +{ + auto self = reinterpret_cast(synth); + const auto ccLabels = self->getCCLabels(); + if (label_index < 0) + return NULL; + + if (static_cast(label_index) >= ccLabels.size()) + return NULL; + + return ccLabels[label_index].second.c_str(); +} + #ifdef __cplusplus } #endif From 7cbd920f7b1295bff01553750865d5dc51c69aeb Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 13:17:14 +0200 Subject: [PATCH 03/13] Added note names to the MIDNAM file --- src/sfizz/Synth.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index fd3b5587..b3a43e84 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -885,6 +885,16 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const } } + { + pugi::xml_node nnl = device.append_child("NoteNameList"); + nnl.append_attribute("Name").set_value("Notes"); + for (const CCNamePair& pair : noteLabels) { + pugi::xml_node nn = nnl.append_child("Note"); + nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); + nn.append_attribute("Name").set_value(pair.second.c_str()); + } + } + /// struct string_writer : pugi::xml_writer { std::string result; From 25353e78ff8b6927e4fdf9fd479e713cbfb563b5 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 13:37:26 +0200 Subject: [PATCH 04/13] Use auto in the foreach loops --- src/sfizz/Synth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b3a43e84..00d5804f 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -877,7 +877,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node cns = device.append_child("ControlNameList"); cns.append_attribute("Name").set_value("Controls"); - for (const CCNamePair& pair : ccLabels) { + for (const auto& pair : ccLabels) { pugi::xml_node cn = cns.append_child("Control"); cn.append_attribute("Type").set_value("7bit"); cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); @@ -888,7 +888,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node nnl = device.append_child("NoteNameList"); nnl.append_attribute("Name").set_value("Notes"); - for (const CCNamePair& pair : noteLabels) { + for (const auto& pair : noteLabels) { pugi::xml_node nn = nnl.append_child("Note"); nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); nn.append_attribute("Name").set_value(pair.second.c_str()); From b7f336e2435694884f2e442fb44935e7c94f36cb Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 14:00:40 +0200 Subject: [PATCH 05/13] Correct documentation --- src/sfizz.h | 24 ++++++++++-------------- src/sfizz.hpp | 4 ++-- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index 63482393..ab55f5d2 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -398,50 +398,46 @@ SFIZZ_EXPORTED_API void sfizz_clear_external_definitions(sfizz_synth_t* synth); /** * @brief Get the number of note labels registered in the current sfz file - * @version 0.4.0-dev + * @since 0.4.0-dev */ SFIZZ_EXPORTED_API unsigned int sfizz_get_num_note_labels(sfizz_synth_t* synth); /** * @brief Get the note number for the label registered at index label_index. - * @version 0.4.0-dev + * @since 0.4.0-dev * - * @returns SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. - * @returns the number + * @returns the number or SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. */ SFIZZ_EXPORTED_API int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index); /** * @brief Get the note text for the label registered at index label_index. - * @version 0.4.0-dev + * @since 0.4.0-dev * - * @returns NULL if the index is out of bounds. - * @returns the label + * @returns the label or NULL if the index is out of bounds. */ SFIZZ_EXPORTED_API const char * sfizz_get_note_label_text(sfizz_synth_t* synth, int label_index); /** * @brief Get the number of note labels registered in the current sfz file - * @version 0.4.0-dev + * @since 0.4.0-dev * */ SFIZZ_EXPORTED_API unsigned int sfizz_get_num_cc_labels(sfizz_synth_t* synth); /** * @brief Get the CC number for the label registered at index label_index. - * @version 0.4.0-dev + * @since 0.4.0-dev * - * @returns SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. - * @returns the number + * @returns the number or SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. */ SFIZZ_EXPORTED_API int sfizz_get_cc_label_number(sfizz_synth_t* synth, int label_index); /** * @brief Get the CC text for the label registered at index label_index. - * @version 0.4.0-dev + * @since 0.4.0-dev * - * @returns NULL if the index is out of bounds. - * @returns the label + * @returns the label or NULL if the index is out of bounds. */ SFIZZ_EXPORTED_API const char * sfizz_get_cc_label_text(sfizz_synth_t* synth, int label_index); diff --git a/src/sfizz.hpp b/src/sfizz.hpp index d726d6c5..f8885259 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -316,13 +316,13 @@ public: /** * @brief Get the note labels, if any - * @version 0.4.0-dev + * @since 0.4.0-dev * */ const std::vector>& getNoteLabels() const noexcept; /** * @brief Get the CC labels, if any - * @version 0.4.0-dev + * @since 0.4.0-dev * */ const std::vector>& getCCLabels() const noexcept; From ff60b35b7378d086f07da940603fedb9f3d1202f Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 14:01:18 +0200 Subject: [PATCH 06/13] Added since to the external definition things --- src/sfizz.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sfizz.h b/src/sfizz.h index ab55f5d2..a48cce55 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -380,6 +380,7 @@ SFIZZ_EXPORTED_API void sfizz_all_sound_off(sfizz_synth_t* synth); * @brief Add external definitions prior to loading; * Note that these do not get reset by loading or resetting the synth. * You need to call sfizz_clear_external_definitions() to erase them. + * @since 0.4.0-dev * * @param synth * @param id @@ -389,6 +390,7 @@ SFIZZ_EXPORTED_API void sfizz_add_external_definitions(sfizz_synth_t* synth, con /** * @brief Clears external definitions for the next file loading. + * @since 0.4.0-dev * * @param synth */ From fc34ccb20574dee90dfd7c24bda1e1bfa3843167 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 8 Apr 2020 14:43:51 +0200 Subject: [PATCH 07/13] Added @since in the C++ bindings --- src/sfizz.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sfizz.hpp b/src/sfizz.hpp index f8885259..d3838eea 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -302,6 +302,7 @@ public: * @brief Add external definitions prior to loading; * Note that these do not get reset by loading or resetting the synth. * You need to call clearExternalDefintions() to erase them. + * @since 0.4.0-dev * * @param id * @param value @@ -310,6 +311,7 @@ public: /** * @brief Clears external definitions for the next file loading. + * @since 0.4.0-dev * */ void clearExternalDefinitions(); From a810dc57753dee3dddfda06e3d385cdc04951a5c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 14 Apr 2020 16:58:19 +0200 Subject: [PATCH 08/13] Add the MIDNAM property: UsesNoteNameList --- src/sfizz/Synth.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 00d5804f..2a3bdebd 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -872,6 +872,9 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const chns.append_child("UsesControlNameList") .append_attribute("Name") .set_value("Controls"); + chns.append_child("UsesNoteNameList") + .append_attribute("Name") + .set_value("Notes"); } { From 5f94e34230d0c187f35bbbac5304c8fd73093c68 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 15 Apr 2020 18:04:02 +0200 Subject: [PATCH 09/13] Rename all: note label -> key label --- src/sfizz.h | 14 +++++++------- src/sfizz.hpp | 4 ++-- src/sfizz/Synth.cpp | 8 ++++---- src/sfizz/Synth.h | 8 ++++---- src/sfizz/sfizz.cpp | 4 ++-- src/sfizz/sfizz_wrapper.cpp | 20 ++++++++++---------- tests/FilesT.cpp | 12 ++++++------ tests/TestFiles/labels.sfz | 6 +++--- 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index a48cce55..a941d59a 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -399,29 +399,29 @@ SFIZZ_EXPORTED_API void sfizz_clear_external_definitions(sfizz_synth_t* synth); #define SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX -1 /** - * @brief Get the number of note labels registered in the current sfz file + * @brief Get the number of key labels registered in the current sfz file * @since 0.4.0-dev */ -SFIZZ_EXPORTED_API unsigned int sfizz_get_num_note_labels(sfizz_synth_t* synth); +SFIZZ_EXPORTED_API unsigned int sfizz_get_num_key_labels(sfizz_synth_t* synth); /** - * @brief Get the note number for the label registered at index label_index. + * @brief Get the key number for the label registered at index label_index. * @since 0.4.0-dev * * @returns the number or SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX if the index is out of bounds. */ -SFIZZ_EXPORTED_API int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index); +SFIZZ_EXPORTED_API int sfizz_get_key_label_number(sfizz_synth_t* synth, int label_index); /** - * @brief Get the note text for the label registered at index label_index. + * @brief Get the key text for the label registered at index label_index. * @since 0.4.0-dev * * @returns the label or NULL if the index is out of bounds. */ -SFIZZ_EXPORTED_API const char * sfizz_get_note_label_text(sfizz_synth_t* synth, int label_index); +SFIZZ_EXPORTED_API const char * sfizz_get_key_label_text(sfizz_synth_t* synth, int label_index); /** - * @brief Get the number of note labels registered in the current sfz file + * @brief Get the number of CC labels registered in the current sfz file * @since 0.4.0-dev * */ diff --git a/src/sfizz.hpp b/src/sfizz.hpp index d3838eea..9c9d9208 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -317,11 +317,11 @@ public: void clearExternalDefinitions(); /** - * @brief Get the note labels, if any + * @brief Get the key labels, if any * @since 0.4.0-dev * */ - const std::vector>& getNoteLabels() const noexcept; + const std::vector>& getKeyLabels() const noexcept; /** * @brief Get the CC labels, if any * @since 0.4.0-dev diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 2a3bdebd..03f3cc34 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -144,7 +144,7 @@ void sfz::Synth::clear() defaultPath = ""; resources.midiState.reset(); ccLabels.clear(); - noteLabels.clear(); + keyLabels.clear(); globalOpcodes.clear(); masterOpcodes.clear(); groupOpcodes.clear(); @@ -212,9 +212,9 @@ void sfz::Synth::handleControlOpcodes(const std::vector& members) if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) ccLabels.emplace_back(member.parameters.back(), std::string(member.value)); break; - case hash("label_note&"): + case hash("label_key&"): if (Default::keyRange.containsWithEnd(member.parameters.back())) - noteLabels.emplace_back(member.parameters.back(), std::string(member.value)); + keyLabels.emplace_back(member.parameters.back(), std::string(member.value)); break; case hash("Default_path"): // fallthrough @@ -891,7 +891,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node nnl = device.append_child("NoteNameList"); nnl.append_attribute("Name").set_value("Notes"); - for (const auto& pair : noteLabels) { + for (const auto& pair : keyLabels) { pugi::xml_node nn = nnl.append_child("Note"); nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); nn.append_attribute("Name").set_value(pair.second.c_str()); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0f34fdb7..738e54d2 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -389,11 +389,11 @@ public: const Parser& getParser() const noexcept { return parser; } /** - * @brief Get the note labels, if any + * @brief Get the key labels, if any * * @return const std::vector& */ - const std::vector& getNoteLabels() const noexcept { return noteLabels; } + const std::vector& getKeyLabels() const noexcept { return keyLabels; } /** * @brief Get the CC labels, if any * @@ -508,9 +508,9 @@ private: */ Voice* findFreeVoice() noexcept; - // Names for the CC and notes as set by label_cc and label_note + // Names for the CC and notes as set by label_cc and label_key std::vector ccLabels; - std::vector noteLabels; + std::vector keyLabels; // Default active switch if multiple keyswitchable regions are present absl::optional defaultSwitch; diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 97e52cd4..5ce7c133 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -221,9 +221,9 @@ void sfz::Sfizz::clearExternalDefinitions() synth->getParser().clearExternalDefinitions(); } -const std::vector>& sfz::Sfizz::getNoteLabels() const noexcept +const std::vector>& sfz::Sfizz::getKeyLabels() const noexcept { - return synth->getNoteLabels(); + return synth->getKeyLabels(); } const std::vector>& sfz::Sfizz::getCCLabels() const noexcept diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index c614bf44..e27d0872 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -269,20 +269,20 @@ void sfizz_clear_external_definitions(sfizz_synth_t* synth) self->getParser().clearExternalDefinitions(); } -unsigned int sfizz_get_num_note_labels(sfizz_synth_t* synth) +unsigned int sfizz_get_num_key_labels(sfizz_synth_t* synth) { auto self = reinterpret_cast(synth); - return self->getNoteLabels().size(); + return self->getKeyLabels().size(); } -int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index) +int sfizz_get_key_label_number(sfizz_synth_t* synth, int label_index) { auto self = reinterpret_cast(synth); - const auto noteLabels = self->getNoteLabels(); + const auto keyLabels = self->getKeyLabels(); if (label_index < 0) return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; - if (static_cast(label_index) >= noteLabels.size()) + if (static_cast(label_index) >= keyLabels.size()) return SFIZZ_OUT_OF_BOUNDS_LABEL_INDEX; // Sanity checks for the future or platforms @@ -290,20 +290,20 @@ int sfizz_get_note_label_number(sfizz_synth_t* synth, int label_index) std::numeric_limits::max() < std::numeric_limits::max(), "The C API sends back an int but the note index in NoteNamePair can overflow it on this platform" ); - return static_cast(noteLabels[label_index].first); + return static_cast(keyLabels[label_index].first); } -const char * sfizz_get_note_label_text(sfizz_synth_t* synth, int label_index) +const char * sfizz_get_key_label_text(sfizz_synth_t* synth, int label_index) { auto self = reinterpret_cast(synth); - const auto noteLabels = self->getNoteLabels(); + const auto keyLabels = self->getKeyLabels(); if (label_index < 0) return NULL; - if (static_cast(label_index) >= noteLabels.size()) + if (static_cast(label_index) >= keyLabels.size()) return NULL; - return noteLabels[label_index].second.c_str(); + return keyLabels[label_index].second.c_str(); } unsigned int sfizz_get_num_cc_labels(sfizz_synth_t* synth) diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index d7bedade..d4ce5568 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -568,13 +568,13 @@ TEST_CASE("[Files] Labels") { sfz::Synth synth; synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels.sfz"); - auto noteLabels = synth.getNoteLabels(); + auto keyLabels = synth.getKeyLabels(); auto ccLabels = synth.getCCLabels(); - REQUIRE( noteLabels.size() == 2); - REQUIRE( noteLabels[0].first == 12 ); - REQUIRE( noteLabels[0].second == "Cymbals" ); - REQUIRE( noteLabels[1].first == 65 ); - REQUIRE( noteLabels[1].second == "Crash" ); + REQUIRE( keyLabels.size() == 2); + REQUIRE( keyLabels[0].first == 12 ); + REQUIRE( keyLabels[0].second == "Cymbals" ); + REQUIRE( keyLabels[1].first == 65 ); + REQUIRE( keyLabels[1].second == "Crash" ); REQUIRE( ccLabels.size() == 2); REQUIRE( ccLabels[0].first == 54 ); REQUIRE( ccLabels[0].second == "Gain" ); diff --git a/tests/TestFiles/labels.sfz b/tests/TestFiles/labels.sfz index 49f51ed5..ceb9f17b 100644 --- a/tests/TestFiles/labels.sfz +++ b/tests/TestFiles/labels.sfz @@ -1,7 +1,7 @@ label_cc54=Gain label_cc2=Other -label_note12=Cymbals -label_note65=Crash -label_note128=Ignored +label_key12=Cymbals +label_key65=Crash +label_key128=Ignored sample=*sine From aa4af91131b9bc8b1152f6fd80e56187ffbeee31 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 16 Apr 2020 00:53:21 +0200 Subject: [PATCH 10/13] Parse sw_label --- src/sfizz/Region.cpp | 3 +++ src/sfizz/Region.h | 1 + tests/RegionT.cpp | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 3411e915..fd87ef30 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -199,6 +199,9 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) setValueFromOpcode(opcode, keyswitch, Default::keyRange); keySwitched = false; break; + case hash("sw_label"): + keyswitchLabel = opcode.value; + break; case hash("sw_down"): setValueFromOpcode(opcode, keyswitchDown, Default::keyRange); keySwitched = false; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index fa952675..66a0e94e 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -259,6 +259,7 @@ struct Region { CCMap> ccConditions { Default::ccValueRange }; Range keyswitchRange { Default::keyRange }; // sw_hikey and sw_lokey absl::optional keyswitch {}; // sw_last + absl::optional keyswitchLabel {}; absl::optional keyswitchUp {}; // sw_up absl::optional keyswitchDown {}; // sw_down absl::optional previousNote {}; // sw_previous diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index f982c424..fe33765c 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -273,6 +273,15 @@ TEST_CASE("[Region] Parsing opcodes") REQUIRE(region.keyswitchRange == sfz::Range(0, 0)); } + SECTION("sw_label") + { + REQUIRE(!region.keyswitchLabel); + region.parseOpcode({ "sw_label", "note" }); + REQUIRE(region.keyswitchLabel == "note"); + region.parseOpcode({ "sw_label", "ring" }); + REQUIRE(region.keyswitchLabel == "ring"); + } + SECTION("sw_last") { REQUIRE(!region.keyswitch); From 4b55f955d639b5d71beb0b77f5f73cab6f80da4e Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 16 Apr 2020 00:53:40 +0200 Subject: [PATCH 11/13] Add switch labels to the midnam --- src/sfizz/Synth.cpp | 9 +++++++++ src/sfizz/Synth.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 03f3cc34..6c30fe56 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -396,6 +396,10 @@ bool sfz::Synth::loadSfzFile(const fs::path& file) } } + if (region->keyswitchLabel && region->keyswitch) + keyswitchLabels.push_back({ *region->keyswitch, *region->keyswitchLabel }); + + // Some regions had group number but no "group-level" opcodes handled the polyphony while (groupMaxPolyphony.size() <= region->group) groupMaxPolyphony.push_back(config::maxVoices); @@ -891,6 +895,11 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node nnl = device.append_child("NoteNameList"); nnl.append_attribute("Name").set_value("Notes"); + for (const auto& pair : keyswitchLabels) { + pugi::xml_node nn = nnl.append_child("Note"); + nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); + nn.append_attribute("Name").set_value(pair.second.c_str()); + } for (const auto& pair : keyLabels) { pugi::xml_node nn = nnl.append_child("Note"); nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 738e54d2..0eddea0b 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -511,6 +511,7 @@ private: // Names for the CC and notes as set by label_cc and label_key std::vector ccLabels; std::vector keyLabels; + std::vector keyswitchLabels; // Default active switch if multiple keyswitchable regions are present absl::optional defaultSwitch; From 8fcafa7b679a2ac450c2a2ce9cd48079bfcfe380 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 18 Apr 2020 21:26:56 +0200 Subject: [PATCH 12/13] Add some checks to test the midnam file --- tests/FilesT.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index d4ce5568..6a8dac59 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -580,4 +580,9 @@ TEST_CASE("[Files] Labels") REQUIRE( ccLabels[0].second == "Gain" ); REQUIRE( ccLabels[1].first == 2 ); REQUIRE( ccLabels[1].second == "Other" ); + const std::string xmlMidnam = synth.exportMidnam(); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); } From 2de8fe237f46c5e2add69e92bcebcc7f61c76638 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 18 Apr 2020 21:35:38 +0200 Subject: [PATCH 13/13] Add a test for key switch MIDNAM --- tests/FilesT.cpp | 10 ++++++++++ tests/TestFiles/labels_sw.sfz | 4 ++++ 2 files changed, 14 insertions(+) create mode 100644 tests/TestFiles/labels_sw.sfz diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 6a8dac59..99f0e64b 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -586,3 +586,13 @@ TEST_CASE("[Files] Labels") REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); } + +TEST_CASE("[Files] Switch labels") +{ + sfz::Synth synth; + synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels_sw.sfz"); + const std::string xmlMidnam = synth.exportMidnam(); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); + REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); +} diff --git a/tests/TestFiles/labels_sw.sfz b/tests/TestFiles/labels_sw.sfz new file mode 100644 index 00000000..5c1721f9 --- /dev/null +++ b/tests/TestFiles/labels_sw.sfz @@ -0,0 +1,4 @@ + sw_lokey=36 sw_hikey=40 sw_default=36 + sw_last=36 sw_label=Sine lokey=41 sample=*sine + sw_last=38 sw_label=Triangle lokey=41 sample=*triangle + sw_last=40 sw_label=Saw lokey=41 sample=*saw