diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index d4caaaba1..a484cb0c4 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1309,12 +1309,12 @@ void Synth::Impl::startVoice(Layer* layer, int delay, const TriggerEvent& trigge ring.addVoiceToRing(selectedVoice); } -void Synth::Impl::checkOffGroups(const Region* region, int delay, int number) +void Synth::Impl::checkOffGroups(const Region* region, int delay, int number, bool chokedByCC) { for (auto& voice : voiceManager_) { if (voice.checkOffGroup(region, delay, number)) { const TriggerEvent& event = voice.getTriggerEvent(); - if (event.type == TriggerEventType::NoteOn) + if (event.type == TriggerEventType::NoteOn && !chokedByCC) noteOffDispatch(delay, event.number, event.value); } } @@ -1451,7 +1451,7 @@ void Synth::Impl::ccDispatch(int delay, int ccNumber, float value, int extendedA if (region.useTimerRange && ! voiceManager_.withinValidTimerRange(®ion, midiState.getInternalClock() + delay, sampleRate_)) continue; - checkOffGroups(®ion, delay, ccNumber); + checkOffGroups(®ion, delay, ccNumber, true); startVoice(layer, delay, triggerEvent, ring); } } diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index c7687954d..9989a6ca1 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -260,7 +260,7 @@ struct Synth::Impl final: public Parser::Listener { * @param delay * @param number */ - void checkOffGroups(const Region* region, int delay, int number); + void checkOffGroups(const Region* region, int delay, int number, bool chokedByCC = false); /** * @brief Resets the callback duration breakdown to 0 diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index 4dec7381c..e9eb6f4a3 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -589,6 +589,31 @@ TEST_CASE("[Polyphony] Choke same group and note if the region is switched off ( REQUIRE( playingSamples(synth) == std::vector { "*sine" } ); } +TEST_CASE("[Polyphony] Choking on poly-aftertouch respects the note number") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyat_choke.sfz", R"( + key=55 group=1 off_by=2 sample=*saw + key=55 group=2 on_locc130=127 on_hicc130=127 trigger=release sample=*sine + )"); + synth.noteOn(0, 55, 63 ); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); + synth.hdPolyAftertouch(0, 54, 1.0f); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); + synth.hdPolyAftertouch(0, 57, 1.0f); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); + synth.hdPolyAftertouch(0, 55, 1.0f); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "*sine"} ); + synth.hdPolyAftertouch(0, 55, 0.0f); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "*sine"} ); +} + TEST_CASE("[Polyphony] A note coming at the same time as another can choke it") { sfz::Synth synth; @@ -632,28 +657,3 @@ TEST_CASE("[Polyphony] A note coming one sample before another note cannot choke synth.renderBlock(buffer); REQUIRE( playingSamples(synth) == std::vector { "kick.wav", "snare.wav" } ); } - -TEST_CASE("[Polyphony] Choking on poly-aftertouch respects the note number") -{ - sfz::Synth synth; - sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyat_choke.sfz", R"( - key=55 group=1 off_by=2 sample=*saw - key=55 group=2 on_locc130=127 on_hicc130=127 trigger=release polyphony=1 sample=*sine - )"); - synth.noteOn(0, 55, 63 ); - synth.renderBlock(buffer); - REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); - synth.hdPolyAftertouch(0, 54, 1.0f); - synth.renderBlock(buffer); - REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); - synth.hdPolyAftertouch(0, 57, 1.0f); - synth.renderBlock(buffer); - REQUIRE( playingSamples(synth) == std::vector { "*saw" } ); - synth.hdPolyAftertouch(0, 55, 1.0f); - synth.renderBlock(buffer); - REQUIRE( playingSamples(synth) == std::vector { "*sine"} ); - synth.hdPolyAftertouch(0, 55, 0.0f); - synth.renderBlock(buffer); - REQUIRE( playingSamples(synth) == std::vector { "*sine"} ); -}