Ability for OpcodeSpec to process number values
This commit is contained in:
parent
4edbd5143d
commit
eb6716181f
3 changed files with 59 additions and 27 deletions
|
|
@ -33,6 +33,7 @@
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
#include "LFOCommon.h"
|
#include "LFOCommon.h"
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
|
#include "utility/Macros.h"
|
||||||
|
|
||||||
|
|
||||||
namespace sfz
|
namespace sfz
|
||||||
|
|
@ -68,6 +69,9 @@ struct OpcodeSpec
|
||||||
Range<T> bounds;
|
Range<T> bounds;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
using Intermediate = typename std::conditional<
|
||||||
|
std::is_integral<T>::value, int64_t, T>::type;
|
||||||
|
|
||||||
template <class U>
|
template <class U>
|
||||||
using IsNormalizable = std::integral_constant<
|
using IsNormalizable = std::integral_constant<
|
||||||
bool, std::is_arithmetic<U>::value && !std::is_same<U, bool>::value>;
|
bool, std::is_arithmetic<U>::value && !std::is_same<U, bool>::value>;
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,31 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
|
absl::optional<T> transformInt_(OpcodeSpec<T> spec, int64_t v)
|
||||||
{
|
{
|
||||||
using Limits = std::numeric_limits<T>;
|
using Limits = std::numeric_limits<T>;
|
||||||
|
|
||||||
|
if (v > static_cast<int64_t>(spec.bounds.getEnd())) {
|
||||||
|
if (spec.flags & kEnforceUpperBound)
|
||||||
|
return spec.bounds.getEnd();
|
||||||
|
else if (!(spec.flags & kPermissiveUpperBound))
|
||||||
|
return absl::nullopt;
|
||||||
|
} else if (v < static_cast<int64_t>(spec.bounds.getStart())) {
|
||||||
|
if (spec.flags & kEnforceLowerBound)
|
||||||
|
return spec.bounds.getStart();
|
||||||
|
else if (!(spec.flags & kPermissiveLowerBound))
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = std::max<int64_t>(v, Limits::min());
|
||||||
|
v = std::min<int64_t>(v, Limits::max());
|
||||||
|
|
||||||
|
return static_cast<T>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
|
||||||
|
{
|
||||||
int64_t returnedValue;
|
int64_t returnedValue;
|
||||||
bool readValueSuccess = false;
|
bool readValueSuccess = false;
|
||||||
|
|
||||||
|
|
@ -163,22 +184,7 @@ absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
|
||||||
if (!readValueSuccess)
|
if (!readValueSuccess)
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
|
|
||||||
if (returnedValue > static_cast<int64_t>(spec.bounds.getEnd())) {
|
return transformInt_(spec, returnedValue);
|
||||||
if (spec.flags & kEnforceUpperBound)
|
|
||||||
return spec.bounds.getEnd();
|
|
||||||
else if (!(spec.flags & kPermissiveUpperBound))
|
|
||||||
return absl::nullopt;
|
|
||||||
} else if (returnedValue < static_cast<int64_t>(spec.bounds.getStart())) {
|
|
||||||
if (spec.flags & kEnforceLowerBound)
|
|
||||||
return spec.bounds.getStart();
|
|
||||||
else if (!(spec.flags & kPermissiveLowerBound))
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
returnedValue = std::max<int64_t>(returnedValue, Limits::min());
|
|
||||||
returnedValue = std::min<int64_t>(returnedValue, Limits::max());
|
|
||||||
|
|
||||||
return static_cast<T>(returnedValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INSTANTIATE_FOR_INTEGRAL(T) \
|
#define INSTANTIATE_FOR_INTEGRAL(T) \
|
||||||
|
|
@ -186,6 +192,11 @@ absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
|
||||||
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
|
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
|
||||||
{ \
|
{ \
|
||||||
return readInt_<T>(spec, value); \
|
return readInt_<T>(spec, value); \
|
||||||
|
} \
|
||||||
|
template <> \
|
||||||
|
absl::optional<T> Opcode::transformOptional(OpcodeSpec<T> spec, int64_t value) const \
|
||||||
|
{ \
|
||||||
|
return transformInt_<T>(spec, value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_FOR_INTEGRAL(uint8_t)
|
INSTANTIATE_FOR_INTEGRAL(uint8_t)
|
||||||
|
|
@ -198,30 +209,34 @@ INSTANTIATE_FOR_INTEGRAL(int64_t)
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
|
absl::optional<T> transformFloat_(OpcodeSpec<T> spec, T v)
|
||||||
{
|
{
|
||||||
T returnedValue;
|
|
||||||
if (!readLeadingFloat(v, &returnedValue))
|
|
||||||
return absl::nullopt;
|
|
||||||
|
|
||||||
if (spec.flags & kWrapPhase)
|
if (spec.flags & kWrapPhase)
|
||||||
returnedValue = wrapPhase(returnedValue);
|
v = wrapPhase(v);
|
||||||
|
|
||||||
if (returnedValue > spec.bounds.getEnd()) {
|
if (v > spec.bounds.getEnd()) {
|
||||||
if (spec.flags & kEnforceUpperBound)
|
if (spec.flags & kEnforceUpperBound)
|
||||||
return spec.bounds.getEnd();
|
return spec.bounds.getEnd();
|
||||||
else if (!(spec.flags & kPermissiveUpperBound))
|
else if (!(spec.flags & kPermissiveUpperBound))
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
} else if (returnedValue < spec.bounds.getStart()) {
|
} else if (v < spec.bounds.getStart()) {
|
||||||
if (spec.flags & kEnforceLowerBound)
|
if (spec.flags & kEnforceLowerBound)
|
||||||
return spec.bounds.getStart();
|
return spec.bounds.getStart();
|
||||||
else if (!(spec.flags & kPermissiveLowerBound))
|
else if (!(spec.flags & kPermissiveLowerBound))
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
returnedValue = spec.normalizeInput(returnedValue);
|
return spec.normalizeInput(v);
|
||||||
|
}
|
||||||
|
|
||||||
return returnedValue;
|
template <typename T>
|
||||||
|
absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
|
||||||
|
{
|
||||||
|
T returnedValue;
|
||||||
|
if (!readLeadingFloat(v, &returnedValue))
|
||||||
|
return absl::nullopt;
|
||||||
|
|
||||||
|
return transformFloat_(spec, returnedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INSTANTIATE_FOR_FLOATING_POINT(T) \
|
#define INSTANTIATE_FOR_FLOATING_POINT(T) \
|
||||||
|
|
@ -229,6 +244,11 @@ absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
|
||||||
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
|
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
|
||||||
{ \
|
{ \
|
||||||
return readFloat_<T>(spec, value); \
|
return readFloat_<T>(spec, value); \
|
||||||
|
} \
|
||||||
|
template <> \
|
||||||
|
absl::optional<T> Opcode::transformOptional(OpcodeSpec<T> spec, T value) const \
|
||||||
|
{ \
|
||||||
|
return transformFloat_<T>(spec, value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_FOR_FLOATING_POINT(float)
|
INSTANTIATE_FOR_FLOATING_POINT(float)
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,14 @@ struct Opcode {
|
||||||
template <class T>
|
template <class T>
|
||||||
T read(OpcodeSpec<T> spec) const { return readOptional(spec).value_or(spec); }
|
T read(OpcodeSpec<T> spec) const { return readOptional(spec).value_or(spec); }
|
||||||
|
|
||||||
|
template <class T> using Intermediate = typename OpcodeSpec<T>::Intermediate;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
absl::optional<T> transformOptional(OpcodeSpec<T> spec, Intermediate<T> value) const;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T transform(OpcodeSpec<T> spec, Intermediate<T> value) const { return transformOptional(spec, value).value_or(spec); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static OpcodeCategory identifyCategory(absl::string_view name);
|
static OpcodeCategory identifyCategory(absl::string_view name);
|
||||||
LEAK_DETECTOR(Opcode);
|
LEAK_DETECTOR(Opcode);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue