From acbbb8354aabe6ec841e0472764935145295a9fe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 3 May 2020 15:08:05 +0200 Subject: [PATCH] Add categorization of opcodes --- src/sfizz/Opcode.cpp | 31 +++++++++++++++++++++++++++++++ src/sfizz/Opcode.h | 19 +++++++++++++++++++ tests/OpcodeT.cpp | 10 ++++++++++ 3 files changed, 60 insertions(+) diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index fbe8bcc5..7451fa3d 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -6,11 +6,14 @@ #include "Opcode.h" #include "StringViewHelpers.h" +#include "absl/strings/ascii.h" +#include "absl/strings/match.h" #include sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue) : opcode(trim(inputOpcode)) , value(trim(inputValue)) + , category(identifyCategory(inputOpcode)) { size_t nextCharIndex { 0 }; int parameterPosition { 0 }; @@ -34,3 +37,31 @@ sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue) if (nextCharIndex != opcode.npos) lettersOnlyHash = hashNoAmpersand(opcode.substr(nextCharIndex), lettersOnlyHash); } + +static absl::string_view extractBackInteger(absl::string_view opcodeName) +{ + size_t n = opcodeName.size(); + size_t i = n; + while (i > 0 && absl::ascii_isdigit(opcodeName[i - 1])) --i; + return opcodeName.substr(i); +} + +sfz::OpcodeCategory sfz::Opcode::identifyCategory(absl::string_view name) +{ + sfz::OpcodeCategory category = kOpcodeNormal; + + if (!name.empty() && absl::ascii_isdigit(name.back())) { + absl::string_view part = name; + part.remove_suffix(extractBackInteger(name).size()); + if (absl::EndsWith(part, "_oncc") || absl::EndsWith(part, "_cc")) + category = kOpcodeOnCcN; + else if (absl::EndsWith(part, "_curvecc")) + category = kOpcodeCurveCcN; + else if (absl::EndsWith(part, "_stepcc")) + category = kOpcodeStepCcN; + else if (absl::EndsWith(part, "_smoothcc")) + category = kOpcodeSmoothCcN; + } + + return category; +} diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 492cfb1e..25d2f931 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -20,6 +20,22 @@ #include "absl/strings/numbers.h" namespace sfz { +/** + * @brief A category which an opcode may belong to. + */ +enum OpcodeCategory { + //! An ordinary opcode + kOpcodeNormal, + //! A region opcode which matches *_onccN or *_ccN + kOpcodeOnCcN, + //! A region opcode which matches *_curveccN + kOpcodeCurveCcN, + //! A region opcode which matches *_stepccN + kOpcodeStepCcN, + //! A region opcode which matches *_smoothccN + kOpcodeSmoothCcN, +}; + /** * @brief Opcode description class. The class parses the parameters * of the opcode on construction. @@ -33,6 +49,9 @@ struct Opcode { uint64_t lettersOnlyHash { Fnv1aBasis }; // This is to handle the integer parameters of some opcodes std::vector parameters; + OpcodeCategory category; +private: + static OpcodeCategory identifyCategory(absl::string_view name); LEAK_DETECTOR(Opcode); }; diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index ffbb07ab..6a0123cf 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -138,3 +138,13 @@ TEST_CASE("[Opcode] Note values") REQUIRE(noteValue); REQUIRE(*noteValue == 61); } + +TEST_CASE("[Opcode] Categories") +{ + REQUIRE(sfz::Opcode("sample", "").category == sfz::kOpcodeNormal); + REQUIRE(sfz::Opcode("amplitude_oncc11", "").category == sfz::kOpcodeOnCcN); + REQUIRE(sfz::Opcode("cutoff_cc22", "").category == sfz::kOpcodeOnCcN); + REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").category == sfz::kOpcodeCurveCcN); + REQUIRE(sfz::Opcode("pan_stepcc44", "").category == sfz::kOpcodeStepCcN); + REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").category == sfz::kOpcodeSmoothCcN); +}