Move template functions of Opcode.h to implementation side
This commit is contained in:
parent
09341723c3
commit
6cc160b9ff
2 changed files with 151 additions and 101 deletions
|
|
@ -13,7 +13,9 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
namespace 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))
|
, category(identifyCategory(inputOpcode))
|
||||||
|
|
@ -49,7 +51,7 @@ static absl::string_view extractBackInteger(absl::string_view opcodeName)
|
||||||
return opcodeName.substr(i);
|
return opcodeName.substr(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sfz::Opcode::getDerivedName(sfz::OpcodeCategory newCategory, unsigned number) const
|
std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) const
|
||||||
{
|
{
|
||||||
std::string derivedName(opcode);
|
std::string derivedName(opcode);
|
||||||
|
|
||||||
|
|
@ -95,9 +97,9 @@ std::string sfz::Opcode::getDerivedName(sfz::OpcodeCategory newCategory, unsigne
|
||||||
return derivedName;
|
return derivedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
sfz::OpcodeCategory sfz::Opcode::identifyCategory(absl::string_view name)
|
OpcodeCategory Opcode::identifyCategory(absl::string_view name)
|
||||||
{
|
{
|
||||||
sfz::OpcodeCategory category = kOpcodeNormal;
|
OpcodeCategory category = kOpcodeNormal;
|
||||||
|
|
||||||
if (!name.empty() && absl::ascii_isdigit(name.back())) {
|
if (!name.empty() && absl::ascii_isdigit(name.back())) {
|
||||||
absl::string_view part = name;
|
absl::string_view part = name;
|
||||||
|
|
@ -115,7 +117,7 @@ sfz::OpcodeCategory sfz::Opcode::identifyCategory(absl::string_view name)
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<uint8_t> sfz::readNoteValue(absl::string_view value)
|
absl::optional<uint8_t> readNoteValue(absl::string_view value)
|
||||||
{
|
{
|
||||||
char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front());
|
char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front());
|
||||||
value.remove_prefix(1);
|
value.remove_prefix(1);
|
||||||
|
|
@ -156,6 +158,142 @@ absl::optional<uint8_t> sfz::readNoteValue(absl::string_view value)
|
||||||
return static_cast<uint8_t>(noteNumber);
|
return static_cast<uint8_t>(noteNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int>>
|
||||||
|
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
size_t numberEnd = 0;
|
||||||
|
|
||||||
|
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
|
||||||
|
++numberEnd;
|
||||||
|
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
||||||
|
++numberEnd;
|
||||||
|
|
||||||
|
value = value.substr(0, numberEnd);
|
||||||
|
|
||||||
|
int64_t returnedValue;
|
||||||
|
if (!absl::SimpleAtoi(value, &returnedValue))
|
||||||
|
return absl::nullopt;
|
||||||
|
|
||||||
|
if (returnedValue > std::numeric_limits<ValueType>::max())
|
||||||
|
returnedValue = std::numeric_limits<ValueType>::max();
|
||||||
|
if (returnedValue < std::numeric_limits<ValueType>::min())
|
||||||
|
returnedValue = std::numeric_limits<ValueType>::min();
|
||||||
|
|
||||||
|
return validRange.clamp(static_cast<ValueType>(returnedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int>>
|
||||||
|
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
size_t numberEnd = 0;
|
||||||
|
|
||||||
|
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
|
||||||
|
++numberEnd;
|
||||||
|
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
||||||
|
++numberEnd;
|
||||||
|
|
||||||
|
if (numberEnd < value.size() && value[numberEnd] == '.') {
|
||||||
|
++numberEnd;
|
||||||
|
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
||||||
|
++numberEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.substr(0, numberEnd);
|
||||||
|
|
||||||
|
float returnedValue;
|
||||||
|
if (!absl::SimpleAtof(value, &returnedValue))
|
||||||
|
return absl::nullopt;
|
||||||
|
|
||||||
|
return validRange.clamp(returnedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
|
||||||
|
{
|
||||||
|
switch (hash(opcode.value)) {
|
||||||
|
case hash("off"):
|
||||||
|
return false;
|
||||||
|
case hash("on"):
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
|
if (!value) // Try and read a note rather than a number
|
||||||
|
value = readNoteValue(opcode.value);
|
||||||
|
if (value)
|
||||||
|
target = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
|
if (!value) // Try and read a note rather than a number
|
||||||
|
value = readNoteValue(opcode.value);
|
||||||
|
if (value)
|
||||||
|
target = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
|
if (!value) // Try and read a note rather than a number
|
||||||
|
value = readNoteValue(opcode.value);
|
||||||
|
if (value)
|
||||||
|
target.setEnd(*value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
|
if (!value) // Try and read a note rather than a number
|
||||||
|
value = readNoteValue(opcode.value);
|
||||||
|
if (value)
|
||||||
|
target.setStart(*value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange)
|
||||||
|
{
|
||||||
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
|
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
|
||||||
|
target = { opcode.parameters.back(), *value };
|
||||||
|
else
|
||||||
|
target = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
#define INSTANCIATE_FOR(T) \
|
||||||
|
template absl::optional<T> readOpcode<T>(absl::string_view value, const Range<T>& validRange); \
|
||||||
|
template void setValueFromOpcode<T>(const Opcode& opcode, T& target, const Range<T>& validRange); \
|
||||||
|
template void setValueFromOpcode<T>(const Opcode& opcode, absl::optional<T>& target, const Range<T>& validRange); \
|
||||||
|
template void setRangeEndFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); \
|
||||||
|
template void setRangeStartFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); \
|
||||||
|
template void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<T>>& target, const Range<T>& validRange);
|
||||||
|
|
||||||
|
INSTANCIATE_FOR(float)
|
||||||
|
INSTANCIATE_FOR(double)
|
||||||
|
INSTANCIATE_FOR(int8_t)
|
||||||
|
INSTANCIATE_FOR(int16_t)
|
||||||
|
INSTANCIATE_FOR(int32_t)
|
||||||
|
INSTANCIATE_FOR(int64_t)
|
||||||
|
INSTANCIATE_FOR(uint8_t)
|
||||||
|
INSTANCIATE_FOR(uint16_t)
|
||||||
|
INSTANCIATE_FOR(uint32_t)
|
||||||
|
//INSTANCIATE_FOR(uint64_t)
|
||||||
|
|
||||||
|
#undef INSTANCIATE_FOR
|
||||||
|
|
||||||
|
} // namespace sfz
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode)
|
std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode)
|
||||||
{
|
{
|
||||||
return os << opcode.opcode << '=' << '"' << opcode.value << '"';
|
return os << opcode.opcode << '=' << '"' << opcode.value << '"';
|
||||||
|
|
|
||||||
|
|
@ -125,28 +125,7 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value);
|
||||||
* @return absl::optional<ValueType> the cast value, or null
|
* @return absl::optional<ValueType> the cast value, or null
|
||||||
*/
|
*/
|
||||||
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int> = 0>
|
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int> = 0>
|
||||||
inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
|
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
size_t numberEnd = 0;
|
|
||||||
|
|
||||||
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
|
|
||||||
++numberEnd;
|
|
||||||
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
|
||||||
++numberEnd;
|
|
||||||
|
|
||||||
value = value.substr(0, numberEnd);
|
|
||||||
|
|
||||||
int64_t returnedValue;
|
|
||||||
if (!absl::SimpleAtoi(value, &returnedValue))
|
|
||||||
return absl::nullopt;
|
|
||||||
|
|
||||||
if (returnedValue > std::numeric_limits<ValueType>::max())
|
|
||||||
returnedValue = std::numeric_limits<ValueType>::max();
|
|
||||||
if (returnedValue < std::numeric_limits<ValueType>::min())
|
|
||||||
returnedValue = std::numeric_limits<ValueType>::min();
|
|
||||||
|
|
||||||
return validRange.clamp(static_cast<ValueType>(returnedValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read a value from the sfz file and cast it to the destination parameter along
|
* @brief Read a value from the sfz file and cast it to the destination parameter along
|
||||||
|
|
@ -159,44 +138,12 @@ inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range
|
||||||
* @return absl::optional<ValueType> the cast value, or null
|
* @return absl::optional<ValueType> the cast value, or null
|
||||||
*/
|
*/
|
||||||
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int> = 0>
|
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int> = 0>
|
||||||
inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
|
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
size_t numberEnd = 0;
|
|
||||||
|
|
||||||
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
|
|
||||||
++numberEnd;
|
|
||||||
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
|
||||||
++numberEnd;
|
|
||||||
|
|
||||||
if (numberEnd < value.size() && value[numberEnd] == '.') {
|
|
||||||
++numberEnd;
|
|
||||||
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
|
|
||||||
++numberEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = value.substr(0, numberEnd);
|
|
||||||
|
|
||||||
float returnedValue;
|
|
||||||
if (!absl::SimpleAtof(value, &returnedValue))
|
|
||||||
return absl::nullopt;
|
|
||||||
|
|
||||||
return validRange.clamp(returnedValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read a boolean value from the sfz file and cast it to the destination parameter.
|
* @brief Read a boolean value from the sfz file and cast it to the destination parameter.
|
||||||
*/
|
*/
|
||||||
inline absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
|
absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode);
|
||||||
{
|
|
||||||
switch (hash(opcode.value)) {
|
|
||||||
case hash("off"):
|
|
||||||
return false;
|
|
||||||
case hash("on"):
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
|
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
|
||||||
|
|
@ -208,14 +155,7 @@ inline absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
|
||||||
* @param validRange the range of admitted values used to clamp the opcode
|
* @param validRange the range of admitted values used to clamp the opcode
|
||||||
*/
|
*/
|
||||||
template <class ValueType>
|
template <class ValueType>
|
||||||
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
|
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
|
||||||
if (!value) // Try and read a note rather than a number
|
|
||||||
value = readNoteValue(opcode.value);
|
|
||||||
if (value)
|
|
||||||
target = *value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
|
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
|
||||||
|
|
@ -227,14 +167,7 @@ inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Ra
|
||||||
* @param validRange the range of admitted values used to clamp the opcode
|
* @param validRange the range of admitted values used to clamp the opcode
|
||||||
*/
|
*/
|
||||||
template <class ValueType>
|
template <class ValueType>
|
||||||
inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange)
|
void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
|
||||||
if (!value) // Try and read a note rather than a number
|
|
||||||
value = readNoteValue(opcode.value);
|
|
||||||
if (value)
|
|
||||||
target = *value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a target end of a range from an opcode value, with possibly a textual note rather
|
* @brief Set a target end of a range from an opcode value, with possibly a textual note rather
|
||||||
|
|
@ -246,14 +179,7 @@ inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>&
|
||||||
* @param validRange the range of admitted values used to clamp the opcode
|
* @param validRange the range of admitted values used to clamp the opcode
|
||||||
*/
|
*/
|
||||||
template <class ValueType>
|
template <class ValueType>
|
||||||
inline void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
|
||||||
if (!value) // Try and read a note rather than a number
|
|
||||||
value = readNoteValue(opcode.value);
|
|
||||||
if (value)
|
|
||||||
target.setEnd(*value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a target beginning of a range from an opcode value, with possibly a textual note rather
|
* @brief Set a target beginning of a range from an opcode value, with possibly a textual note rather
|
||||||
|
|
@ -265,14 +191,7 @@ inline void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target
|
||||||
* @param validRange the range of admitted values used to clamp the opcode
|
* @param validRange the range of admitted values used to clamp the opcode
|
||||||
*/
|
*/
|
||||||
template <class ValueType>
|
template <class ValueType>
|
||||||
inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
|
||||||
if (!value) // Try and read a note rather than a number
|
|
||||||
value = readNoteValue(opcode.value);
|
|
||||||
if (value)
|
|
||||||
target.setStart(*value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a CC modulation parameter from an opcode value.
|
* @brief Set a CC modulation parameter from an opcode value.
|
||||||
|
|
@ -283,14 +202,7 @@ inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& targ
|
||||||
* @param validRange the range of admitted values used to clamp the opcode
|
* @param validRange the range of admitted values used to clamp the opcode
|
||||||
*/
|
*/
|
||||||
template <class ValueType>
|
template <class ValueType>
|
||||||
inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange)
|
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange);
|
||||||
{
|
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
|
||||||
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
|
|
||||||
target = { opcode.parameters.back(), *value };
|
|
||||||
else
|
|
||||||
target = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue