diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 8ac6d3af..7a53d54d 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -7,6 +7,7 @@ constexpr auto uint32_t_max = std::numeric_limits::max(); extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec delayMod { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 557ae19f..289b8d7d 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -126,6 +126,7 @@ namespace Default { extern const OpcodeSpec delay; extern const OpcodeSpec delayRandom; + extern const OpcodeSpec delayMod; extern const OpcodeSpec offset; extern const OpcodeSpec offsetMod; extern const OpcodeSpec offsetRandom; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 230a18a8..4fed8896 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -97,6 +97,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("delay"): delay = opcode.read(Default::delay); break; + case hash("delay_oncc&"): // also delay_cc& + if (opcode.parameters.back() > config::numCCs) + return false; + + delayCC[opcode.parameters.back()] = opcode.read(Default::delayMod); + break; case hash("delay_random"): delayRandom = opcode.read(Default::delayRandom); break; @@ -1639,7 +1645,11 @@ uint64_t sfz::Region::getOffset(Oversampling factor) const noexcept float sfz::Region::getDelay() const noexcept { fast_real_distribution delayDistribution { 0, delayRandom }; - return delay + delayDistribution(Random::randomGenerator); + float finalDelay { delay }; + finalDelay += delayDistribution(Random::randomGenerator); + for (const auto& mod: delayCC) + finalDelay += mod.data * midiState.getCCValue(mod.cc); + return Default::delay.bounds.clamp(finalDelay); } uint32_t sfz::Region::trueSampleEnd(Oversampling factor) const noexcept diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index d8d6368e..98dda576 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -321,6 +321,7 @@ struct Region { absl::optional sampleQuality {}; float delay { Default::delay }; // delay float delayRandom { Default::delayRandom }; // delay_random + CCMap delayCC { Default::delayMod }; int64_t offset { Default::offset }; // offset int64_t offsetRandom { Default::offsetRandom }; // offset_random CCMap offsetCC { Default::offsetMod }; diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 7cca9126..9af440b8 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -103,6 +103,11 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.delayRandom); } break; + MATCH("/region&/delay_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.delayCC.getWithDefault(indices[1])); + } break; + MATCH("/region&/offset", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'h'>(delay, path, region.offset); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a26044ec..24467ea3 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -63,6 +63,30 @@ TEST_CASE("[Values] Delay") }; REQUIRE(messageList == expected); } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav delay_cc12=1.5 + sample=kick.wav delay_cc12=-1.5 + sample=kick.wav delay_cc14=3 delay_cc12=2 delay_cc12=-12 + )"); + synth.dispatchMessage(client, 0, "/region0/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/delay_cc14", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/delay_cc12", "", nullptr); + std::vector expected { + "/region0/delay_cc12,f : { 0 }", + "/region1/delay_cc12,f : { 1.5 }", + "/region2/delay_cc12,f : { 0 }", + "/region3/delay_cc14,f : { 3 }", + // "/region3/delay_cc12,f : { 2 }", + }; + REQUIRE(messageList == expected); + } } TEST_CASE("[Values] Sample and direction")