diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3c1f2bc..c2e40836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,7 +137,6 @@ set(SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RegionSet.cpp - sfizz/Defaults.cpp sfizz/PolyphonyGroup.cpp sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp @@ -201,6 +200,7 @@ set(SFIZZ_PARSER_HEADERS set(SFIZZ_PARSER_SOURCES sfizz/Opcode.cpp + sfizz/Defaults.cpp sfizz/OpcodeCleanup.cpp sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index ee712e58..f883bc20 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -1,6 +1,4 @@ #include "Defaults.h" -#include "MathHelpers.h" -#include "SfzHelpers.h" namespace sfz { @@ -23,7 +21,7 @@ extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; @@ -33,14 +31,14 @@ extern const OpcodeSpec notePolyphony { config::maxVoices, Range key { 60, Range(0, 127), kCanBeNote }; extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec loCC { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiCC { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec loVel { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiVel { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loCC { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiCC { 127, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loVel { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiVel { 127, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; -extern const OpcodeSpec loBend { -1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; -extern const OpcodeSpec hiBend { 1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec loBend { -8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec hiBend { 8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; @@ -49,7 +47,7 @@ extern const OpcodeSpec ccNumber { 0, Range(0, config::numCC extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec sustainThreshold { 1, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; @@ -58,19 +56,19 @@ extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec crossfadeOut { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeOut { 127.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; @@ -144,7 +142,7 @@ extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; -extern const OpcodeSpec compGain { 1.0f, Range(-100.0f, 100.0f), kDb2Mag }; +extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), kDb2Mag }; extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 27f5481c..8e25ec5e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -24,11 +24,14 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once +#include +#include +#include #include "Range.h" #include "Config.h" #include "SfzFilter.h" -#include -#include +#include "SfzHelpers.h" +#include "MathHelpers.h" namespace sfz @@ -68,10 +71,40 @@ enum OpcodeFlags : int { template struct OpcodeSpec { - T defaultValue; + T defaultInputValue; Range bounds; int flags; - operator T() const { return defaultValue; } + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + constexpr auto needsOperation { + kNormalizePercent | + kNormalizeMidi | + kNormalizeBend | + kDb2Mag + }; + + if (!(flags & needsOperation)) + return input; + else if (flags & kNormalizePercent) + return normalizePercents(input); + else if (flags & kNormalizeMidi) + return normalize7Bits(input); + else if (flags & kNormalizeBend) + return normalizeBend(input); + else if (flags & kDb2Mag) + return db2mag(input); + else // just in case + return input; + } + + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + return input; + } + + operator T() const { return normalizeInput(defaultInputValue); } }; namespace Default diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index a3e747fc..fcc323a8 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -155,9 +155,9 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) #define INSTANTIATE_FOR_INTEGRAL(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readInt_(spec, value).value_or(spec.defaultValue); \ + return readInt_(spec, value); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -205,23 +205,14 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) return {}; } - if (spec.flags & kNormalizeMidi) - returnedValue = normalize7Bits(returnedValue); - else if (spec.flags & kNormalizePercent) - returnedValue = normalizePercents(returnedValue); - else if (spec.flags & kNormalizeBend) - returnedValue = normalizeBend(returnedValue); - else if (spec.flags & kDb2Mag) - returnedValue = db2mag(returnedValue); - - return returnedValue; + return spec.normalizeInput(returnedValue); } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readFloat_(spec, value).value_or(spec.defaultValue); \ + return readFloat_(spec, value); \ } INSTANTIATE_FOR_FLOATING_POINT(float) @@ -292,17 +283,17 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) } template <> -OscillatorEnabled Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { auto v = readBooleanFromOpcode(*this); if (!v) - return spec.defaultValue; + return {}; return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } template <> -Trigger Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("attack"): return Trigger::attack; @@ -313,11 +304,11 @@ Trigger Opcode::read(OpcodeSpec spec) const } DBG("Unknown trigger value: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -CrossfadeCurve Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("power"): return CrossfadeCurve::power; @@ -325,11 +316,11 @@ CrossfadeCurve Opcode::read(OpcodeSpec spec) const } DBG("Unknown crossfade power curve: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -OffMode Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("fast"): return OffMode::fast; @@ -338,11 +329,11 @@ OffMode Opcode::read(OpcodeSpec spec) const } DBG("Unknown off mode: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -FilterType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("lpf_1p"): return kFilterLpf1p; @@ -371,11 +362,11 @@ FilterType Opcode::read(OpcodeSpec spec) const } DBG("Unknown filter type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -EqType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("peak"): return kEqPeak; @@ -384,11 +375,11 @@ EqType Opcode::read(OpcodeSpec spec) const } DBG("Unknown EQ type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -VelocityOverride Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("current"): return VelocityOverride::current; @@ -396,11 +387,11 @@ VelocityOverride Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -SelfMask Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("on"): @@ -409,25 +400,28 @@ SelfMask Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -bool Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { - return readBooleanFromOpcode(*this).value_or(spec.defaultValue); + return readBooleanFromOpcode(*this); } template <> -LFOWave Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec spec) const { const OpcodeSpec intSpec { - static_cast(spec.defaultValue), + static_cast(spec.defaultInputValue), Range(static_cast(spec.bounds.getStart()), static_cast(spec.bounds.getEnd())), 0 }; - int value = read(intSpec); - return static_cast(value); + + if (auto value = readOptional(intSpec)) + return static_cast(*value); + + return absl::nullopt; } } // namespace sfz diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 3df4ed08..314e64f0 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -102,7 +102,10 @@ struct Opcode { } template - T read(OpcodeSpec spec) const; + absl::optional readOptional(OpcodeSpec spec) const; + + template + T read(OpcodeSpec spec) const { return readOptional(spec).value_or(spec); } private: static OpcodeCategory identifyCategory(absl::string_view name); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 0f86c802..d892bd68 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -283,8 +283,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("sw_last"): if (!lastKeyswitchRange) { - lastKeyswitch = opcode.read(Default::key); - keySwitched = false; + lastKeyswitch = opcode.readOptional(Default::key); + keySwitched = !lastKeyswitch.has_value(); } break; case hash("sw_lolast"): @@ -315,15 +315,15 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - downKeyswitch = opcode.read(Default::key); - keySwitched = false; + downKeyswitch = opcode.readOptional(Default::key); + keySwitched = !downKeyswitch.has_value(); break; case hash("sw_up"): - upKeyswitch = opcode.read(Default::key); + upKeyswitch = opcode.readOptional(Default::key); break; case hash("sw_previous"): - previousKeyswitch = opcode.read(Default::key); - previousKeySwitched = false; + previousKeyswitch = opcode.readOptional(Default::key); + previousKeySwitched = !previousKeyswitch.has_value(); break; case hash("sw_vel"): velocityOverride = diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 4a7324f8..c0ea5968 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -389,7 +389,7 @@ struct Region { float position { normalizePercents(Default::position) }; // position uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_veltrack + float ampVeltrack { Default::ampVeltrack }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; float ampRandom { Default::ampRandom }; // amp_random diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 7577d60d..8fd15b33 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -16,7 +16,6 @@ #include "MathHelpers.h" #include "SIMDHelpers.h" #include "absl/meta/type_traits.h" -#include "Defaults.h" namespace sfz { @@ -126,6 +125,12 @@ constexpr float normalize7Bits(T value) return static_cast(min(max(value, T { 0 }), T { 127 })) / 127.0f; } +template <> +constexpr float normalize7Bits(bool value) +{ + return value ? 1.0f : 0.0f; +} + /** * @brief Normalize a CC value between 0.0 and 1.0 * @@ -188,11 +193,11 @@ inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset) { const int offsetKey { key + offset }; if (offsetKey > std::numeric_limits::max()) - return Default::key.bounds.getEnd(); + return 127; if (offsetKey < std::numeric_limits::min()) - return Default::key.bounds.getStart(); + return 0; - return Default::key.bounds.clamp(static_cast(offsetKey)); + return clamp(static_cast(offsetKey), 0, 127); } namespace literals { diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 7439a306..b01201a5 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -318,7 +318,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") @@ -353,7 +353,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Can be note") @@ -458,7 +458,7 @@ TEST_CASE("[Opcode] opcode read (float)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a457607b..c0e85444 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -747,7 +747,7 @@ TEST_CASE("[Values] Upswitch") "/region2/sw_up,N : { }", "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - "/region5/sw_up,i : { 60 }", + "/region5/sw_up,N : { }", }; REQUIRE(messageList == expected); } @@ -778,7 +778,7 @@ TEST_CASE("[Values] Downswitch") "/region2/sw_down,N : { }", "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - "/region5/sw_down,i : { 60 }", + "/region5/sw_down,N : { }", }; REQUIRE(messageList == expected); } @@ -809,7 +809,7 @@ TEST_CASE("[Values] Previous keyswitch") "/region2/sw_previous,N : { }", "/region3/sw_previous,N : { }", "/region4/sw_previous,i : { 60 }", - "/region5/sw_previous,i : { 64 }", + "/region5/sw_previous,N : { }", }; REQUIRE(messageList == expected); } @@ -889,7 +889,7 @@ TEST_CASE("[Values] BPM range") "/region0/bpm_range,ff : { 0, 500 }", "/region1/bpm_range,ff : { 34.1, 60.2 }", "/region2/bpm_range,ff : { 0, 60 }", - "/region3/bpm_range,ff : { 0, 0 }", + "/region3/bpm_range,ff : { 20, 500 }", "/region4/bpm_range,ff : { 10, 10 }", }; REQUIRE(messageList == expected); @@ -1553,12 +1553,11 @@ TEST_CASE("[Values] Amp Veltrack") )"); synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); std::vector expected { "/region0/amp_veltrack,f : { 100 }", "/region1/amp_veltrack,f : { 10.1 }", - // "/region2/amp_veltrack,f : { 100 }", + "/region2/amp_veltrack,f : { 100 }", }; REQUIRE(messageList == expected); }