diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 4a541bf6..a7c4a462 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -33,6 +33,7 @@ #include "SfzHelpers.h" #include "LFOCommon.h" #include "MathHelpers.h" +#include "utility/Macros.h" namespace sfz @@ -68,6 +69,9 @@ struct OpcodeSpec Range bounds; int flags; + using Intermediate = typename std::conditional< + std::is_integral::value, int64_t, T>::type; + template using IsNormalizable = std::integral_constant< bool, std::is_arithmetic::value && !std::is_same::value>; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index ad15e4e9..4e2c007e 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -143,10 +143,31 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name) } template -absl::optional readInt_(OpcodeSpec spec, absl::string_view v) +absl::optional transformInt_(OpcodeSpec spec, int64_t v) { using Limits = std::numeric_limits; + if (v > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kEnforceUpperBound) + return spec.bounds.getEnd(); + else if (!(spec.flags & kPermissiveUpperBound)) + return absl::nullopt; + } else if (v < static_cast(spec.bounds.getStart())) { + if (spec.flags & kEnforceLowerBound) + return spec.bounds.getStart(); + else if (!(spec.flags & kPermissiveLowerBound)) + return absl::nullopt; + } + + v = std::max(v, Limits::min()); + v = std::min(v, Limits::max()); + + return static_cast(v); +} + +template +absl::optional readInt_(OpcodeSpec spec, absl::string_view v) +{ int64_t returnedValue; bool readValueSuccess = false; @@ -163,22 +184,7 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) if (!readValueSuccess) return absl::nullopt; - if (returnedValue > static_cast(spec.bounds.getEnd())) { - if (spec.flags & kEnforceUpperBound) - return spec.bounds.getEnd(); - else if (!(spec.flags & kPermissiveUpperBound)) - return absl::nullopt; - } else if (returnedValue < static_cast(spec.bounds.getStart())) { - if (spec.flags & kEnforceLowerBound) - return spec.bounds.getStart(); - else if (!(spec.flags & kPermissiveLowerBound)) - return absl::nullopt; - } - - returnedValue = std::max(returnedValue, Limits::min()); - returnedValue = std::min(returnedValue, Limits::max()); - - return static_cast(returnedValue); + return transformInt_(spec, returnedValue); } #define INSTANTIATE_FOR_INTEGRAL(T) \ @@ -186,6 +192,11 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ return readInt_(spec, value); \ + } \ + template <> \ + absl::optional Opcode::transformOptional(OpcodeSpec spec, int64_t value) const \ + { \ + return transformInt_(spec, value); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -198,30 +209,34 @@ INSTANTIATE_FOR_INTEGRAL(int64_t) template -absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) +absl::optional transformFloat_(OpcodeSpec spec, T v) { - T returnedValue; - if (!readLeadingFloat(v, &returnedValue)) - return absl::nullopt; - if (spec.flags & kWrapPhase) - returnedValue = wrapPhase(returnedValue); + v = wrapPhase(v); - if (returnedValue > spec.bounds.getEnd()) { + if (v > spec.bounds.getEnd()) { if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); else if (!(spec.flags & kPermissiveUpperBound)) return absl::nullopt; - } else if (returnedValue < spec.bounds.getStart()) { + } else if (v < spec.bounds.getStart()) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); else if (!(spec.flags & kPermissiveLowerBound)) return absl::nullopt; } - returnedValue = spec.normalizeInput(returnedValue); + return spec.normalizeInput(v); +} - return returnedValue; +template +absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) +{ + T returnedValue; + if (!readLeadingFloat(v, &returnedValue)) + return absl::nullopt; + + return transformFloat_(spec, returnedValue); } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ @@ -229,6 +244,11 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ return readFloat_(spec, value); \ + } \ + template <> \ + absl::optional Opcode::transformOptional(OpcodeSpec spec, T value) const \ + { \ + return transformFloat_(spec, value); \ } INSTANTIATE_FOR_FLOATING_POINT(float) diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index bc860d5f..a24a08b5 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -113,6 +113,14 @@ struct Opcode { template T read(OpcodeSpec spec) const { return readOptional(spec).value_or(spec); } + template using Intermediate = typename OpcodeSpec::Intermediate; + + template + absl::optional transformOptional(OpcodeSpec spec, Intermediate value) const; + + template + T transform(OpcodeSpec spec, Intermediate value) const { return transformOptional(spec, value).value_or(spec); } + private: static OpcodeCategory identifyCategory(absl::string_view name); LEAK_DETECTOR(Opcode);