From 5da331cf18e71512ac64b79f1a609ac51dabdb06 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 23 Jun 2021 12:32:54 +0200 Subject: [PATCH 1/4] Parse CC modifiers for flex EGs --- src/sfizz/Synth.cpp | 3 +++ src/sfizz/SynthMessaging.cpp | 44 +++++++++++++++++++++++++++++++ tests/RegionValuesT.cpp | 50 ++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 0e7f4dbe..1e200b58 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -2045,6 +2045,7 @@ void Synth::Impl::collectUsedCCsFromRegion(BitArray& usedCCs, co collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccHold); collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccStart); collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccSustain); + if (region.pitchEG) { collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccAttack); collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccRelease); @@ -2054,6 +2055,7 @@ void Synth::Impl::collectUsedCCsFromRegion(BitArray& usedCCs, co collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccStart); collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccSustain); } + if (region.filterEG) { collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccAttack); collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccRelease); @@ -2063,6 +2065,7 @@ void Synth::Impl::collectUsedCCsFromRegion(BitArray& usedCCs, co collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccStart); collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccSustain); } + for (const LFODescription& lfo : region.lfos) { collectUsedCCsFromCCMap(usedCCs, lfo.phaseCC); collectUsedCCsFromCCMap(usedCCs, lfo.delayCC); diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index b53cf1a0..3e6a87f2 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -51,6 +51,16 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co break; \ const auto& lfo = region.lfos[idx]; + #define GET_EG_OR_BREAK(idx) \ + if (idx >= region.flexEGs.size()) \ + break; \ + auto& eg = region.flexEGs[idx]; + + #define GET_EG_POINT_OR_BREAK(idx) \ + if (idx >= eg.points.size()) \ + break; \ + auto& point = eg.points[idx]; + MATCH("/hello", "") { client.receive(delay, "/hello", "", nullptr); } break; @@ -1352,10 +1362,44 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'i'>(delay, path, static_cast(lfo.sub[0].wave)); } break; + MATCH("/region&/eg&/point&/time", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EG_OR_BREAK(indices[1]) + GET_EG_POINT_OR_BREAK(indices[2] + 1) + + client.receive<'f'>(delay, path, point.time); + } break; + + MATCH("/region&/eg&/point&/time_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EG_OR_BREAK(indices[1]) + GET_EG_POINT_OR_BREAK(indices[2] + 1) + + client.receive<'f'>(delay, path, point.ccTime.getWithDefault(indices[3])); + } break; + + MATCH("/region&/eg&/point&/level", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EG_OR_BREAK(indices[1]) + GET_EG_POINT_OR_BREAK(indices[2] + 1) + + client.receive<'f'>(delay, path, point.level); + } break; + + MATCH("/region&/eg&/point&/level_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EG_OR_BREAK(indices[1]) + GET_EG_POINT_OR_BREAK(indices[2] + 1) + + client.receive<'f'>(delay, path, point.ccLevel.getWithDefault(indices[3])); + } break; + #undef GET_REGION_OR_BREAK #undef GET_FILTER_OR_BREAK #undef GET_EQ_OR_BREAK #undef GET_LFO_OR_BREAK + #undef GET_EG_OR_BREAK + #undef GET_EG_POINT_OR_BREAK //---------------------------------------------------------------------- // Setting values diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a6fc4dd7..970a259e 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -3251,3 +3251,53 @@ TEST_CASE("[Values] EQ value bounds") REQUIRE(messageList == expected); } } + +TEST_CASE("[Values] Flex EGs") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav eg1_time1=0.1 eg1_level1=0.5 eg1_time2=0.4 eg1_level2=2 eg2_time1=4 eg2_level1=0.1 + )"); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/time", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/level", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point1/time", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point1/level", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg1/point0/time", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg1/point0/level", "", nullptr); + std::vector expected { + "/region0/eg0/point0/time,f : { 0.1 }", + "/region0/eg0/point0/level,f : { 0.5 }", + "/region0/eg0/point1/time,f : { 0.4 }", + "/region0/eg0/point1/level,f : { 2 }", + "/region0/eg1/point0/time,f : { 4 }", + "/region0/eg1/point0/level,f : { 0.1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Flex EGs CC") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav eg1_time1_cc2=0.1 eg1_level1_oncc3=0.5 + )"); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/time_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/time_cc4", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/level_cc3", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eg0/point0/level_cc12", "", nullptr); + std::vector expected { + "/region0/eg0/point0/time_cc2,f : { 0.1 }", + "/region0/eg0/point0/time_cc4,f : { 0 }", + "/region0/eg0/point0/level_cc3,f : { 0.5 }", + "/region0/eg0/point0/level_cc12,f : { 0 }", + }; + REQUIRE(messageList == expected); +} From 8563a1735f9b32a3f160311c60cd404160e56337 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 23 Jun 2021 13:00:34 +0200 Subject: [PATCH 2/4] Merged implementations with dynamic updates --- src/sfizz/FlexEnvelope.cpp | 34 +++++++++++-------- src/sfizz/FlexEnvelope.h | 1 + src/sfizz/Synth.cpp | 2 +- .../modulations/sources/FlexEnvelope.cpp | 5 +-- src/sfizz/modulations/sources/FlexEnvelope.h | 4 ++- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/sfizz/FlexEnvelope.cpp b/src/sfizz/FlexEnvelope.cpp index ae06c022..2ae0e04a 100644 --- a/src/sfizz/FlexEnvelope.cpp +++ b/src/sfizz/FlexEnvelope.cpp @@ -57,6 +57,7 @@ struct FlexEnvelope::Impl { void process(absl::Span out); bool advanceToStage(unsigned stageNumber); bool advanceToNextStage(); + void updateCurrentTimeAndLevel(); }; FlexEnvelope::FlexEnvelope(Resources &resources) @@ -97,18 +98,8 @@ void FlexEnvelope::start(unsigned triggerDelay) const FlexEGDescription& desc = *impl.desc_; impl.delayFramesLeft_ = triggerDelay; - - FlexEGPoint point; - if (!desc.points.empty()) - point = desc.points[0]; - - // - impl.stageSourceLevel_ = 0.0; - impl.stageTargetLevel_ = point.level; - impl.stageTime_ = point.time; - impl.stageSustained_ = desc.sustain == 0; - impl.stageCurve_ = &point.curve(); impl.currentFramesUntilRelease_ = absl::nullopt; + impl.advanceToStage(0); } void FlexEnvelope::setFreeRunning(bool freeRunning) @@ -172,6 +163,10 @@ void FlexEnvelope::Impl::process(absl::Span out) const FlexEGDescription& desc = *desc_; size_t numFrames = out.size(); const float samplePeriod = samplePeriod_; + + if (desc.dynamic) + updateCurrentTimeAndLevel(); + // Skip the initial delay, for frame-accurate trigger size_t skipFrames = std::min(numFrames, delayFramesLeft_); if (skipFrames > 0) { @@ -266,12 +261,11 @@ bool FlexEnvelope::Impl::advanceToStage(unsigned stageNumber) const FlexEGPoint& point = desc.points[stageNumber]; stageSourceLevel_ = currentLevel_; - stageTargetLevel_ = point.getLevel(midiState); - stageTime_ = point.getTime(midiState); + currentTime_ = 0.0f; + updateCurrentTimeAndLevel(); stageSustained_ = int(stageNumber) == desc.sustain; stageCurve_ = &point.curve(); - currentTime_ = 0; return true; }; @@ -280,4 +274,16 @@ bool FlexEnvelope::Impl::advanceToNextStage() return advanceToStage(currentStageNumber_ + 1); } +void FlexEnvelope::Impl::updateCurrentTimeAndLevel() +{ + const FlexEGDescription& desc = *desc_; + if (currentStageNumber_ >= desc.points.size()) + return; + + const FlexEGPoint& point = desc.points[currentStageNumber_]; + const MidiState& midiState = resources_->getMidiState(); + stageTargetLevel_ = point.getLevel(midiState); + stageTime_ = point.getTime(midiState); +} + } // namespace sfz diff --git a/src/sfizz/FlexEnvelope.h b/src/sfizz/FlexEnvelope.h index a72d280f..c33bf751 100644 --- a/src/sfizz/FlexEnvelope.h +++ b/src/sfizz/FlexEnvelope.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "MidiState.h" #include #include diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 1e200b58..46b9f52d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -70,7 +70,7 @@ Synth::Impl::Impl() MidiState& midiState = resources_.getMidiState(); genController_.reset(new ControllerSource(resources_, voiceManager_)); genLFO_.reset(new LFOSource(voiceManager_)); - genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_)); + genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_, midiState)); genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, midiState)); genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, midiState)); genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, midiState)); diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index b3e85cfc..1a2698ad 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -14,9 +14,10 @@ namespace sfz { -FlexEnvelopeSource::FlexEnvelopeSource(VoiceManager& manager) - : voiceManager_(manager) +FlexEnvelopeSource::FlexEnvelopeSource(VoiceManager& manager, MidiState& midiState) + : voiceManager_(manager), midiState_(midiState) { + } void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) diff --git a/src/sfizz/modulations/sources/FlexEnvelope.h b/src/sfizz/modulations/sources/FlexEnvelope.h index 81b7a2f7..60cd5b14 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.h +++ b/src/sfizz/modulations/sources/FlexEnvelope.h @@ -7,13 +7,14 @@ #pragma once #include "../ModGenerator.h" #include "../../VoiceManager.h" +#include "../../MidiState.h" namespace sfz { class Synth; class FlexEnvelopeSource : public ModGenerator { public: - explicit FlexEnvelopeSource(VoiceManager& manager); + explicit FlexEnvelopeSource(VoiceManager& manager, MidiState& midiState); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void cancelRelease(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; @@ -21,6 +22,7 @@ public: private: VoiceManager& voiceManager_; + MidiState& midiState_; }; } // namespace sfz From cbff8666c14527fc162368f2f7eac6df3be9e781 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sat, 26 Jun 2021 23:03:29 +0200 Subject: [PATCH 3/4] Remove useless midistate injection --- src/sfizz/FlexEnvelope.h | 1 - src/sfizz/Synth.cpp | 2 +- src/sfizz/modulations/sources/FlexEnvelope.cpp | 4 ++-- src/sfizz/modulations/sources/FlexEnvelope.h | 4 +--- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sfizz/FlexEnvelope.h b/src/sfizz/FlexEnvelope.h index c33bf751..a72d280f 100644 --- a/src/sfizz/FlexEnvelope.h +++ b/src/sfizz/FlexEnvelope.h @@ -5,7 +5,6 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "MidiState.h" #include #include diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 46b9f52d..1e200b58 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -70,7 +70,7 @@ Synth::Impl::Impl() MidiState& midiState = resources_.getMidiState(); genController_.reset(new ControllerSource(resources_, voiceManager_)); genLFO_.reset(new LFOSource(voiceManager_)); - genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_, midiState)); + genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_)); genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, midiState)); genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, midiState)); genPolyAftertouch_.reset(new PolyAftertouchSource(voiceManager_, midiState)); diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index 1a2698ad..347886aa 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -14,8 +14,8 @@ namespace sfz { -FlexEnvelopeSource::FlexEnvelopeSource(VoiceManager& manager, MidiState& midiState) - : voiceManager_(manager), midiState_(midiState) +FlexEnvelopeSource::FlexEnvelopeSource(VoiceManager& manager) + : voiceManager_(manager) { } diff --git a/src/sfizz/modulations/sources/FlexEnvelope.h b/src/sfizz/modulations/sources/FlexEnvelope.h index 60cd5b14..81b7a2f7 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.h +++ b/src/sfizz/modulations/sources/FlexEnvelope.h @@ -7,14 +7,13 @@ #pragma once #include "../ModGenerator.h" #include "../../VoiceManager.h" -#include "../../MidiState.h" namespace sfz { class Synth; class FlexEnvelopeSource : public ModGenerator { public: - explicit FlexEnvelopeSource(VoiceManager& manager, MidiState& midiState); + explicit FlexEnvelopeSource(VoiceManager& manager); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void cancelRelease(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; @@ -22,7 +21,6 @@ public: private: VoiceManager& voiceManager_; - MidiState& midiState_; }; } // namespace sfz From 83be87c449b040ae1adb8400217fe855c97ecb9b Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 27 Jun 2021 11:22:03 +0200 Subject: [PATCH 4/4] Removed the dynamic update --- src/sfizz/FlexEnvelope.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sfizz/FlexEnvelope.cpp b/src/sfizz/FlexEnvelope.cpp index 2ae0e04a..3cbd4161 100644 --- a/src/sfizz/FlexEnvelope.cpp +++ b/src/sfizz/FlexEnvelope.cpp @@ -164,9 +164,6 @@ void FlexEnvelope::Impl::process(absl::Span out) size_t numFrames = out.size(); const float samplePeriod = samplePeriod_; - if (desc.dynamic) - updateCurrentTimeAndLevel(); - // Skip the initial delay, for frame-accurate trigger size_t skipFrames = std::min(numFrames, delayFramesLeft_); if (skipFrames > 0) {