From 9cab74f2c43aeb40100e986aad4a97a875f317c8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 28 Sep 2020 21:49:20 +0200 Subject: [PATCH 1/2] flexEG: allow release to bypass the pre-sustain stages It makes the EG equivalent to ARIA in case of early release. --- src/sfizz/FlexEnvelope.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sfizz/FlexEnvelope.cpp b/src/sfizz/FlexEnvelope.cpp index c58d3ae5..6fd67ac1 100644 --- a/src/sfizz/FlexEnvelope.cpp +++ b/src/sfizz/FlexEnvelope.cpp @@ -141,12 +141,24 @@ void FlexEnvelope::Impl::process(absl::Span out) } // Perform stage transitions - const bool isReleased = isReleased_; - while ((!stageSustained_ && currentTime_ >= stageTime_) || - (stageSustained_ && isReleased)) { - // If stage is of zero duration, immediate transition to level - if (!stageSustained_ && stageTime_ == 0) + if (isReleased_) { + // on release, fast forward past the sustain stage + const unsigned sustainStage = desc.sustain; + while (currentStageNumber_ <= sustainStage) { + if (!advanceToNextStage()) { + out.remove_prefix(frameIndex); + fill(out, 0.0f); + return; + } + } + } + while (!stageSustained_ && currentTime_ >= stageTime_) { + // advance through completed timed stages + ASSERT(isReleased_ || !stageSustained_); + if (stageTime_ == 0) { + // if stage is of zero duration, immediate transition to level currentLevel_ = stageTargetLevel_; + } if (!advanceToNextStage()) { out.remove_prefix(frameIndex); fill(out, 0.0f); From 2a26682543ae00ef7c1cd339f6a8ae63e38e078e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 28 Sep 2020 22:37:46 +0200 Subject: [PATCH 2/2] Add test for flexEG release --- tests/FlexEGT.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/FlexEGT.cpp b/tests/FlexEGT.cpp index 229bee47..6490e30f 100644 --- a/tests/FlexEGT.cpp +++ b/tests/FlexEGT.cpp @@ -288,3 +288,72 @@ TEST_CASE("[FlexEG] Zero delay transitions") // Note(jpc): 0.9 is because EG pre-increments the time counter, slope is // 1 frame off into the future } + +TEST_CASE("[FlexEG] Early release") +{ + for (int i = 0; i < 3; ++i) { + sfz::Synth synth; + + synth.loadSfzString(fs::current_path(), R"( + sample=*sine + eg1_ampeg=1 + eg1_time1=1.0 eg1_level1=1.0 + eg1_time2=1.0 eg1_level2=1.0 eg1_sustain=2 + eg1_time3=1.0 eg1_level3=0.0 + )"); + sfz::FlexEnvelope envelope; + REQUIRE(synth.getNumRegions() == 1); + REQUIRE(synth.getRegionView(0)->flexEGs.size() == 1); + envelope.configure(&synth.getRegionView(0)->flexEGs[0]); + envelope.setSampleRate(100); + + envelope.start(0); + switch (i) { + case 0: + // A normal release: up 1s, sustain 1s, down 1s + envelope.release(200); + break; + case 1: + // A fast release: up 1s, down 1s + envelope.release(100); + break; + case 2: + // A faster release: up 0.5s, down 0.5s + envelope.release(50); + break; + } + + std::array output; + envelope.process(absl::MakeSpan(output)); + + // Theoretical output at 0.5s interval + const std::array ref0 {{ 0.0, 0.5, 1.0, 1.0, 1.0, 0.5, 0.0 }}; + const std::array ref1 {{ 0.0, 0.5, 1.0, 0.5, 0.0 }}; + const std::array ref2 {{ 0.0, 0.5, 0.25 }}; + + const float m = 0.015f; + switch (i) { + case 0: + REQUIRE(output[ 0] == Approx(ref0[0]).margin(m)); + REQUIRE(output[ 50] == Approx(ref0[1]).margin(m)); + REQUIRE(output[100] == Approx(ref0[2]).margin(m)); + REQUIRE(output[150] == Approx(ref0[3]).margin(m)); + REQUIRE(output[200] == Approx(ref0[4]).margin(m)); + REQUIRE(output[250] == Approx(ref0[5]).margin(m)); + REQUIRE(output[300] == Approx(ref0[6]).margin(m)); + break; + case 1: + REQUIRE(output[ 0] == Approx(ref1[0]).margin(m)); + REQUIRE(output[ 50] == Approx(ref1[1]).margin(m)); + REQUIRE(output[100] == Approx(ref1[2]).margin(m)); + REQUIRE(output[150] == Approx(ref1[3]).margin(m)); + REQUIRE(output[200] == Approx(ref1[4]).margin(m)); + break; + case 2: + REQUIRE(output[ 0] == Approx(ref2[0]).margin(m)); + REQUIRE(output[ 50] == Approx(ref2[1]).margin(m)); + REQUIRE(output[100] == Approx(ref2[2]).margin(m)); + break; + } + } +}