From 92aaa2a17e710b45a11715f507e4bfd9ad28ac09 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 21 Dec 2019 21:24:49 +0100 Subject: [PATCH] Added proper support for off_modes --- src/sfizz/ADSREnvelope.cpp | 5 ++++- src/sfizz/ADSREnvelope.h | 5 ++++- src/sfizz/Voice.cpp | 11 +++++++---- src/sfizz/Voice.h | 3 ++- tests/FilesT.cpp | 27 +++++++++++++++++++++++++-- tests/TestFiles/off_mode.sfz | 3 +++ 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 tests/TestFiles/off_mode.sfz diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index b84b680f..23b0356c 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -224,10 +224,13 @@ int ADSREnvelope::getRemainingDelay() const noexcept } template -void ADSREnvelope::startRelease(int releaseDelay) noexcept +void ADSREnvelope::startRelease(int releaseDelay, bool fastRelease) noexcept { shouldRelease = true; this->releaseDelay = releaseDelay; + + if (fastRelease) + this->release = 0; } } diff --git a/src/sfizz/ADSREnvelope.h b/src/sfizz/ADSREnvelope.h index af8abe02..ac091a80 100644 --- a/src/sfizz/ADSREnvelope.h +++ b/src/sfizz/ADSREnvelope.h @@ -66,8 +66,11 @@ public: * @brief Start the envelope release after a delay. * * @param releaseDelay the delay before releasing in samples + * @param fastRelease whether the release should be fast (i.e. 0 or so) or + * follow the release duration that was set when + * initializing the envelope */ - void startRelease(int releaseDelay) noexcept; + void startRelease(int releaseDelay, bool fastRelease = false) noexcept; /** * @brief Is the envelope smoothing? * diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 9fa4ba2b..3bd0253e 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -130,7 +130,7 @@ bool sfz::Voice::isFree() const noexcept return (state == State::idle); } -void sfz::Voice::release(int delay) noexcept +void sfz::Voice::release(int delay, bool fastRelease) noexcept { if (state != State::playing) return; @@ -139,7 +139,7 @@ void sfz::Voice::release(int delay) noexcept reset(); } else { state = State::release; - egEnvelope.startRelease(delay); + egEnvelope.startRelease(delay, fastRelease); } } @@ -499,8 +499,11 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept bool sfz::Voice::checkOffGroup(int delay, uint32_t group) noexcept { - if (region != nullptr && triggerType == TriggerType::NoteOn && region->offBy && *region->offBy == group) { - release(delay); + if (region == nullptr) + return false; + + if (triggerType == TriggerType::NoteOn && region->offBy && *region->offBy == group) { + release(delay, region->offMode == SfzOffMode::fast); return true; } diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 8b94abda..289a6cf1 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -264,8 +264,9 @@ private: * @brief Release the voice after a given delay * * @param delay + * @param fastRelease whether to do a normal release or cut the voice abruptly */ - void release(int delay) noexcept; + void release(int delay, bool fastRelease = false) noexcept; Region* region { nullptr }; enum class State { diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 60285e5f..7e0cec84 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -355,7 +355,6 @@ TEST_CASE("[Files] Default path is ignored for generators") REQUIRE(synth.getRegionView(0)->sample == R"(*sine)"); } - TEST_CASE("[Files] Set CC applies properly to all channels") { sfz::Synth synth; @@ -366,7 +365,6 @@ TEST_CASE("[Files] Set CC applies properly to all channels") } } - TEST_CASE("[Files] Note and octave offsets") { sfz::Synth synth; @@ -408,3 +406,28 @@ TEST_CASE("[Files] Note and octave offsets") REQUIRE( synth.getRegionView(6)->pitchKeycenter == 50 ); } +TEST_CASE("[Files] Off modes") +{ + sfz::Synth synth; + synth.setSamplesPerBlock(256); + synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_mode.sfz"); + REQUIRE( synth.getNumRegions() == 3 ); + synth.noteOn(0, 0, 64, 63); + REQUIRE( synth.getNumActiveVoices() == 2 ); + const auto* fastVoice = + synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(0) : + synth.getVoiceView(1) ; + const auto* normalVoice = + synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(1) : + synth.getVoiceView(0) ; + synth.noteOn(100, 0, 63, 63); + REQUIRE( synth.getNumActiveVoices() == 3 ); + sfz::AudioBuffer buffer { 2, 256 }; + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices() == 2 ); + REQUIRE( fastVoice->isFree() ); + REQUIRE( !normalVoice->isFree() ); + +} diff --git a/tests/TestFiles/off_mode.sfz b/tests/TestFiles/off_mode.sfz new file mode 100644 index 00000000..fb5d3437 --- /dev/null +++ b/tests/TestFiles/off_mode.sfz @@ -0,0 +1,3 @@ + group=1 off_by=2 key=64 off_mode=fast ampeg_release=0.1 sample=mono_sample.wav + group=1 off_by=2 key=64 off_mode=normal ampeg_release=0.1 sample=mono_sample.wav + group=2 key=63 off_mode=normal ampeg_release=0.1 sample=mono_sample.wav