commit
ac75f48e2b
3 changed files with 129 additions and 1 deletions
|
|
@ -6,11 +6,16 @@
|
||||||
|
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
|
#include "absl/strings/ascii.h"
|
||||||
|
#include "absl/strings/match.h"
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
||||||
: opcode(trim(inputOpcode))
|
: opcode(trim(inputOpcode))
|
||||||
, value(trim(inputValue))
|
, value(trim(inputValue))
|
||||||
|
, category(identifyCategory(inputOpcode))
|
||||||
{
|
{
|
||||||
size_t nextCharIndex { 0 };
|
size_t nextCharIndex { 0 };
|
||||||
int parameterPosition { 0 };
|
int parameterPosition { 0 };
|
||||||
|
|
@ -34,3 +39,77 @@ sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
||||||
if (nextCharIndex != opcode.npos)
|
if (nextCharIndex != opcode.npos)
|
||||||
lettersOnlyHash = hashNoAmpersand(opcode.substr(nextCharIndex), lettersOnlyHash);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sfz::Opcode::getDerivedName(sfz::OpcodeCategory newCategory, unsigned number) const
|
||||||
|
{
|
||||||
|
std::string derivedName(opcode);
|
||||||
|
|
||||||
|
switch (category) {
|
||||||
|
case kOpcodeNormal:
|
||||||
|
break;
|
||||||
|
case kOpcodeOnCcN:
|
||||||
|
case kOpcodeCurveCcN:
|
||||||
|
case kOpcodeStepCcN:
|
||||||
|
case kOpcodeSmoothCcN:
|
||||||
|
{
|
||||||
|
// when the input is cc, first delete the suffix `_*cc`
|
||||||
|
size_t pos = opcode.rfind('_');
|
||||||
|
assert(pos != opcode.npos);
|
||||||
|
derivedName.resize(pos);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper to extract the cc number optionally if the next part needs it
|
||||||
|
auto ccNumberSuffix = [this, number]() -> std::string {
|
||||||
|
return (number != ~0u) ? std::to_string(number) :
|
||||||
|
std::string(extractBackInteger(opcode));
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (newCategory) {
|
||||||
|
case kOpcodeNormal:
|
||||||
|
break;
|
||||||
|
case kOpcodeOnCcN:
|
||||||
|
absl::StrAppend(&derivedName, "_oncc", ccNumberSuffix());
|
||||||
|
break;
|
||||||
|
case kOpcodeCurveCcN:
|
||||||
|
absl::StrAppend(&derivedName, "_curvecc", ccNumberSuffix());
|
||||||
|
break;
|
||||||
|
case kOpcodeStepCcN:
|
||||||
|
absl::StrAppend(&derivedName, "_stepcc", ccNumberSuffix());
|
||||||
|
break;
|
||||||
|
case kOpcodeSmoothCcN:
|
||||||
|
absl::StrAppend(&derivedName, "_smoothcc", ccNumberSuffix());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return derivedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include "Range.h"
|
#include "Range.h"
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
#include <absl/types/optional.h>
|
#include "absl/types/optional.h"
|
||||||
#include "absl/meta/type_traits.h"
|
#include "absl/meta/type_traits.h"
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -20,6 +20,22 @@
|
||||||
#include "absl/strings/numbers.h"
|
#include "absl/strings/numbers.h"
|
||||||
|
|
||||||
namespace sfz {
|
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
|
* @brief Opcode description class. The class parses the parameters
|
||||||
* of the opcode on construction.
|
* of the opcode on construction.
|
||||||
|
|
@ -33,6 +49,19 @@ struct Opcode {
|
||||||
uint64_t lettersOnlyHash { Fnv1aBasis };
|
uint64_t lettersOnlyHash { Fnv1aBasis };
|
||||||
// This is to handle the integer parameters of some opcodes
|
// This is to handle the integer parameters of some opcodes
|
||||||
std::vector<uint16_t> parameters;
|
std::vector<uint16_t> parameters;
|
||||||
|
OpcodeCategory category;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Get the derived opcode name to convert it to another category.
|
||||||
|
*
|
||||||
|
* @param newCategory category to convert to
|
||||||
|
* @param number optional CC number, needed if destination is CC and source is not
|
||||||
|
* @return derived opcode name
|
||||||
|
*/
|
||||||
|
std::string getDerivedName(OpcodeCategory newCategory, unsigned number = ~0u) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static OpcodeCategory identifyCategory(absl::string_view name);
|
||||||
LEAK_DETECTOR(Opcode);
|
LEAK_DETECTOR(Opcode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,3 +138,23 @@ TEST_CASE("[Opcode] Note values")
|
||||||
REQUIRE(noteValue);
|
REQUIRE(noteValue);
|
||||||
REQUIRE(*noteValue == 61);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Opcode] Derived names")
|
||||||
|
{
|
||||||
|
REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeNormal) == "sample");
|
||||||
|
REQUIRE(sfz::Opcode("cutoff_cc22", "").getDerivedName(sfz::kOpcodeNormal) == "cutoff");
|
||||||
|
REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").getDerivedName(sfz::kOpcodeOnCcN) == "lfo01_pitch_oncc33");
|
||||||
|
REQUIRE(sfz::Opcode("pan_stepcc44", "").getDerivedName(sfz::kOpcodeCurveCcN) == "pan_curvecc44");
|
||||||
|
REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").getDerivedName(sfz::kOpcodeStepCcN) == "noise_level_stepcc55");
|
||||||
|
REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeSmoothCcN, 66) == "sample_smoothcc66");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue