From 5527282159b7e001f4b021d7002e163c7b777f28 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 29 Jun 2021 10:48:53 +0200 Subject: [PATCH] Parse the relevant inputs --- src/sfizz/Defaults.cpp | 3 + src/sfizz/Defaults.h | 3 + src/sfizz/FilterDescription.h | 1 + src/sfizz/Region.cpp | 50 +++++++++++++++ src/sfizz/Region.h | 2 + src/sfizz/SfzHelpers.h | 7 +++ src/sfizz/SynthMessaging.cpp | 62 ++++++++++++++++++ tests/RegionValuesT.cpp | 115 +++++++++++++++++++++++++--------- 8 files changed, 215 insertions(+), 28 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 40ce37c7..a70f3602 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -90,6 +90,7 @@ FloatSpec width { 100.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds FloatSpec widthMod { 0.0f, {-200.0f, 200.0f}, kNormalizePercent|kPermissiveBounds }; FloatSpec ampKeytrack { 0.0f, {-96.0f, 12.0f}, kPermissiveBounds }; FloatSpec ampVeltrack { 100.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds }; +FloatSpec ampVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds }; FloatSpec ampVelcurve { 0.0f, {0.0f, 1.0f}, kPermissiveBounds }; FloatSpec ampRandom { 0.0f, {-24.0f, 24.0f}, kPermissiveBounds }; BoolSpec rtDead { false, {false, true}, kEnforceBounds }; @@ -103,6 +104,7 @@ FloatSpec filterGainMod { 0.0f, {-96.0f, 96.0f}, kPermissiveBounds }; FloatSpec filterRandom { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds }; FloatSpec filterKeytrack { 0, {0, 1200}, kPermissiveBounds }; FloatSpec filterVeltrack { 0, {-12000, 12000}, kPermissiveBounds }; +FloatSpec filterVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds }; FloatSpec eqBandwidth { 1.0f, {0.001f, 4.0f}, kPermissiveBounds }; FloatSpec eqBandwidthMod { 0.0f, {-4.0f, 4.0f}, kPermissiveBounds }; FloatSpec eqFrequency { 0.0f, {0.0f, 20000.0f}, kPermissiveBounds }; @@ -114,6 +116,7 @@ FloatSpec eqVel2Gain { 0.0f, {-96.0f, 96.0f}, kPermissiveBounds }; FloatSpec pitchKeytrack { 100, {-1200, 1200}, kPermissiveBounds }; FloatSpec pitchRandom { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds }; FloatSpec pitchVeltrack { 0, {-12000, 12000}, kPermissiveBounds }; +FloatSpec pitchVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds }; FloatSpec transpose { 0, {-127, 127}, kPermissiveBounds }; FloatSpec pitch { 0.0f, {-2400.0f, 2400.0f}, kPermissiveBounds }; FloatSpec pitchMod { 0.0f, {-2400.0f, 2400.0f}, kPermissiveBounds }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 7d6c54fa..2a271920 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -202,6 +202,7 @@ namespace Default extern const OpcodeSpec widthMod; extern const OpcodeSpec ampKeytrack; extern const OpcodeSpec ampVeltrack; + extern const OpcodeSpec ampVeltrackMod; extern const OpcodeSpec ampVelcurve; extern const OpcodeSpec ampRandom; extern const OpcodeSpec rtDead; @@ -215,6 +216,7 @@ namespace Default extern const OpcodeSpec filterRandom; extern const OpcodeSpec filterKeytrack; extern const OpcodeSpec filterVeltrack; + extern const OpcodeSpec filterVeltrackMod; extern const OpcodeSpec eqBandwidth; extern const OpcodeSpec eqBandwidthMod; extern const OpcodeSpec eqFrequency; @@ -226,6 +228,7 @@ namespace Default extern const OpcodeSpec pitchKeytrack; extern const OpcodeSpec pitchRandom; extern const OpcodeSpec pitchVeltrack; + extern const OpcodeSpec pitchVeltrackMod; extern const OpcodeSpec transpose; extern const OpcodeSpec pitch; extern const OpcodeSpec pitchMod; diff --git a/src/sfizz/FilterDescription.h b/src/sfizz/FilterDescription.h index 4674477c..59eadab9 100644 --- a/src/sfizz/FilterDescription.h +++ b/src/sfizz/FilterDescription.h @@ -20,6 +20,7 @@ struct FilterDescription float keytrack { Default::filterKeytrack }; uint8_t keycenter { Default::key }; float veltrack { Default::filterVeltrack }; + CCMap> veltrackCC { ModifierCurvePair{ Default::filterVeltrackMod, Default::curveCC } }; float random { Default::filterRandom }; FilterType type { FilterType::kFilterLpf2p }; }; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 344d7c6a..0dc7fc3d 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -449,6 +449,18 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode) case hash("amp_veltrack"): ampVeltrack = opcode.read(Default::ampVeltrack); break; + case hash("amp_veltrack_oncc&"): + if (opcode.parameters.back() >= config::numCCs) + return false; + + ampVeltrackCC[opcode.parameters.back()].modifier = opcode.read(Default::ampVeltrackMod); + break; + case hash("amp_veltrack_curvecc&"): + if (opcode.parameters.back() >= config::numCCs) + return false; + + ampVeltrackCC[opcode.parameters.back()].curve = opcode.read(Default::curveCC); + break; case hash("amp_random"): ampRandom = opcode.read(Default::ampRandom); break; @@ -625,6 +637,32 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode) filters[filterIndex].veltrack = opcode.read(Default::filterVeltrack); } break; + case hash("fil&_veltrack_oncc&"): + { + const auto filterIndex = opcode.parameters.front() - 1; + if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) + return false; + + const auto cc = opcode.parameters.back(); + if (cc >= config::numCCs) + return false; + + filters[filterIndex].veltrackCC[cc].modifier = opcode.read(Default::ampVeltrackMod); + } + break; + case hash("fil&_veltrack_curvecc&"): + { + const auto filterIndex = opcode.parameters.front() - 1; + if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) + return false; + + const auto cc = opcode.parameters.back(); + if (cc >= config::numCCs) + return false; + + filters[filterIndex].veltrackCC[cc].curve = opcode.read(Default::curveCC); + } + break; case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random { const auto filterIndex = opcode.parameters.front() - 1; @@ -755,6 +793,18 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode) case hash("pitch_veltrack"): pitchVeltrack = opcode.read(Default::pitchVeltrack); break; + case hash("pitch_veltrack_oncc&"): + if (opcode.parameters.back() >= config::numCCs) + return false; + + pitchVeltrackCC[opcode.parameters.back()].modifier = opcode.read(Default::pitchVeltrackMod); + break; + case hash("pitch_veltrack_curvecc&"): + if (opcode.parameters.back() >= config::numCCs) + return false; + + pitchVeltrackCC[opcode.parameters.back()].curve = opcode.read(Default::curveCC); + break; case hash("pitch_random"): pitchRandom = opcode.read(Default::pitchRandom); break; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index fe407065..11a5757b 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -384,6 +384,7 @@ struct Region { uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack float ampVeltrack { Default::ampVeltrack }; // amp_veltrack + CCMap> ampVeltrackCC { ModifierCurvePair{ Default::ampVeltrackMod, Default::curveCC } }; std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; float ampRandom { Default::ampRandom }; // amp_random @@ -415,6 +416,7 @@ struct Region { float pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack float pitchRandom { Default::pitchRandom }; // pitch_random float pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack + CCMap> pitchVeltrackCC { ModifierCurvePair{ Default::pitchVeltrackMod, Default::curveCC } }; float transpose { Default::transpose }; // transpose float pitch { Default::pitch }; // tune float bendUp { Default::bendUp }; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 46a7e166..8fce77fa 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -22,6 +22,13 @@ namespace sfz { using CCNamePair = std::pair; using NoteNamePair = std::pair; +template +struct ModifierCurvePair +{ + T modifier {}; + uint8_t curve {}; +}; + template using MidiNoteArray = std::array; template diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 3e6a87f2..ce0c62b3 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -782,6 +782,26 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.ampVeltrack * 100.0f); } break; + MATCH("/region&/amp_veltrack_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.ampVeltrackCC.contains(indices[1])) { + const auto& cc = region.ampVeltrackCC.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, cc.modifier * 100.0f); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amp_veltrack_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.ampVeltrackCC.contains(indices[1])) { + const auto& cc = region.ampVeltrackCC.getWithDefault(indices[1]); + client.receive<'i'>(delay, path, cc.curve ); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + MATCH("/region&/amp_random", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'f'>(delay, path, region.ampRandom); @@ -921,6 +941,26 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'i'>(delay, path, region.pitchVeltrack); } break; + MATCH("/region&/pitch_veltrack_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.pitchVeltrackCC.contains(indices[1])) { + const auto& cc = region.pitchVeltrackCC.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, cc.modifier * 100.0f); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/pitch_veltrack_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.pitchVeltrackCC.contains(indices[1])) { + const auto& cc = region.pitchVeltrackCC.getWithDefault(indices[1]); + client.receive<'i'>(delay, path, cc.curve ); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + MATCH("/region&/pitch_random", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'f'>(delay, path, region.pitchRandom); @@ -1277,6 +1317,28 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'i'>(delay, path, filter.veltrack); } break; + MATCH("/region&/filter&/veltrack_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + if (filter.veltrackCC.contains(indices[2])) { + const auto& cc = filter.veltrackCC.getWithDefault(indices[2]); + client.receive<'f'>(delay, path, cc.modifier * 100.0f); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/filter&/veltrack_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + if (filter.veltrackCC.contains(indices[2])) { + const auto& cc = filter.veltrackCC.getWithDefault(indices[2]); + client.receive<'i'>(delay, path, cc.curve ); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + MATCH("/region&/filter&/type", "") { GET_REGION_OR_BREAK(indices[0]) GET_FILTER_OR_BREAK(indices[1]) diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 970a259e..dfbb3f51 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -1629,20 +1629,47 @@ TEST_CASE("[Values] Amp Veltrack") Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav - sample=kick.wav amp_veltrack=10.1 - sample=kick.wav amp_veltrack=-132 - )"); - synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/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 : { -132 }", - }; - REQUIRE(messageList == expected); + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_veltrack=10.1 + sample=kick.wav amp_veltrack=-132 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/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 : { -132 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_veltrack_cc1=10.1 amp_veltrack_curvecc1=3 + sample=kick.wav amp_veltrack_oncc2=-40 amp_veltrack_curvecc3=4 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_veltrack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_veltrack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_veltrack_curvecc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amp_veltrack_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amp_veltrack_curvecc3", "", nullptr); + // TODO: activate for the new region parser ; accept oob + // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); + std::vector expected { + "/region0/amp_veltrack_cc1,N : { }", + "/region1/amp_veltrack_cc1,f : { 10.1 }", + "/region1/amp_veltrack_curvecc1,i : { 3 }", + "/region2/amp_veltrack_cc2,f : { -40 }", + "/region2/amp_veltrack_curvecc3,i : { 4 }", + }; + REQUIRE(messageList == expected); + } } TEST_CASE("[Values] Amp Random") @@ -1987,20 +2014,47 @@ TEST_CASE("[Values] Pitch Veltrack") Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav - sample=kick.wav pitch_veltrack=10 - sample=kick.wav pitch_veltrack=-132 - )"); - synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr); - std::vector expected { - "/region0/pitch_veltrack,i : { 0 }", - "/region1/pitch_veltrack,i : { 10 }", - "/region2/pitch_veltrack,i : { -132 }", - }; - REQUIRE(messageList == expected); + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_veltrack=10 + sample=kick.wav pitch_veltrack=-132 + )"); + synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr); + std::vector expected { + "/region0/pitch_veltrack,i : { 0 }", + "/region1/pitch_veltrack,i : { 10 }", + "/region2/pitch_veltrack,i : { -132 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_veltrack_cc1=10.1 pitch_veltrack_curvecc1=3 + sample=kick.wav pitch_veltrack_oncc2=-40 pitch_veltrack_curvecc3=4 + )"); + synth.dispatchMessage(client, 0, "/region0/pitch_veltrack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_curvecc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_curvecc3", "", nullptr); + // TODO: activate for the new region parser ; accept oob + // synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr); + std::vector expected { + "/region0/pitch_veltrack_cc1,N : { }", + "/region1/pitch_veltrack_cc1,f : { 10.1 }", + "/region1/pitch_veltrack_curvecc1,i : { 3 }", + "/region2/pitch_veltrack_cc2,f : { -40 }", + "/region2/pitch_veltrack_curvecc3,i : { 4 }", + }; + REQUIRE(messageList == expected); + } } TEST_CASE("[Values] Pitch Random") @@ -2992,6 +3046,7 @@ TEST_CASE("[Values] Filter dispatching") sample=kick.wav cutoff3=50 resonance2=3 fil2_gain=-5 fil3_keytrack=100 fil_gain=5 fil1_gain=-5 fil2_veltrack=-100 + fil4_veltrack_cc7=-100 fil5_veltrack_curvecc2=2 )"); synth.dispatchMessage(client, 0, "/region0/filter2/cutoff", "", nullptr); @@ -3000,6 +3055,8 @@ TEST_CASE("[Values] Filter dispatching") synth.dispatchMessage(client, 0, "/region0/filter2/keytrack", "", nullptr); synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr); synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter3/veltrack_cc7", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter4/veltrack_curvecc2", "", nullptr); std::vector expected { "/region0/filter2/cutoff,f : { 50 }", "/region0/filter1/resonance,f : { 3 }", @@ -3007,6 +3064,8 @@ TEST_CASE("[Values] Filter dispatching") "/region0/filter2/keytrack,i : { 100 }", "/region0/filter0/gain,f : { -5 }", "/region0/filter1/veltrack,i : { -100 }", + "/region0/filter3/veltrack_cc7,f : { -100 }", + "/region0/filter4/veltrack_curvecc2,i : { 2 }", }; REQUIRE(messageList == expected); }