diff --git a/src/sfizz/SisterVoiceRing.h b/src/sfizz/SisterVoiceRing.h index 4e7cc743..bb6137bb 100644 --- a/src/sfizz/SisterVoiceRing.h +++ b/src/sfizz/SisterVoiceRing.h @@ -61,13 +61,14 @@ struct SisterVoiceRing { * * @param voice * @param delay + * @param fast whether to apply a fast release */ template>::value, int> = 0> - static void offAllSisters(T* voice, int delay) { + static void offAllSisters(T* voice, int delay, bool fast = false) { if (voice != nullptr) { SisterVoiceRing::applyToRing(voice, [&] (Voice* v) { - v->off(delay); + v->off(delay, fast); }); } } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 039b967b..245a7240 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -71,6 +71,7 @@ void sfz::Synth::onVoiceStateChanged(NumericId id, Voice::State state) if (state == Voice::State::idle) { auto voice = getVoiceById(id); RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); + engineSet->removeVoice(voice); polyphonyGroups[voice->getRegion()->group].removeVoice(voice); } @@ -744,7 +745,7 @@ sfz::Voice* sfz::Synth::findFreeVoice() noexcept if (freeVoice != voices.end()) return freeVoice->get(); - DBG("Engine polyphony reached"); + DBG("Engine hard polyphony reached"); return {}; } @@ -972,6 +973,7 @@ void sfz::Synth::startVoice(Region* region, int delay, const TriggerEvent& trigg checkRegionPolyphony(region, delay); checkGroupPolyphony(region, delay); checkSetPolyphony(region, delay); + checkEnginePolyphony(delay); Voice* selectedVoice = findFreeVoice(); if (selectedVoice == nullptr) @@ -980,6 +982,7 @@ void sfz::Synth::startVoice(Region* region, int delay, const TriggerEvent& trigg ASSERT(selectedVoice->isFree()); selectedVoice->startVoice(region, delay, triggerEvent); ring.addVoiceToRing(selectedVoice); + engineSet->registerVoice(selectedVoice); RegionSet::registerVoiceInHierarchy(region, selectedVoice); polyphonyGroups[region->group].registerVoice(selectedVoice); } @@ -1108,6 +1111,19 @@ void sfz::Synth::checkSetPolyphony(const Region* region, int delay) noexcept } } +void sfz::Synth::checkEnginePolyphony(int delay) noexcept +{ + auto& activeVoices = engineSet->getActiveVoices(); + + if (activeVoices.size() >= static_cast(numRequiredVoices)) { + tempPolyphonyArray.clear(); + absl::c_copy_if(activeVoices, + std::back_inserter(tempPolyphonyArray), [](Voice* v) { return !v->releasedOrFree(); }); + const auto voiceToSteal = stealer.steal(absl::MakeSpan(tempPolyphonyArray)); + SisterVoiceRing::offAllSisters(voiceToSteal, delay, true); + } +} + void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexcept { const auto randValue = randNoteDistribution(Random::randomGenerator); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 2663afcc..af3aa469 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -865,6 +865,13 @@ private: */ void checkSetPolyphony(const Region* region, int delay) noexcept; + /** + * @brief Check the engine polyphony, fast releasing voices if necessary + * + * @param delay + */ + void checkEnginePolyphony(int delay) noexcept; + /** * @brief Start a voice for a specific region. * This will do the needed polyphony checks and voice stealing. diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 7dd2f948..96eb9ada 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -167,11 +167,11 @@ void sfz::Voice::release(int delay) noexcept resources.modMatrix.releaseVoice(id, region->getId(), delay); } -void sfz::Voice::off(int delay) noexcept +void sfz::Voice::off(int delay, bool fast) noexcept { if (!region->flexAmpEG) { - if (region->offMode == SfzOffMode::fast) { - egAmplitude.setReleaseTime( Default::offTime ); + if (region->offMode == SfzOffMode::fast || fast) { + egAmplitude.setReleaseTime(Default::offTime); } else if (region->offMode == SfzOffMode::time) { egAmplitude.setReleaseTime(region->offTime); } diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index dbcae7d7..54fd16e5 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -328,8 +328,9 @@ public: * and set the envelopes if necessary. * * @param delay + * @param fast whether to apply a fast release regardless of the off mode */ - void off(int delay) noexcept; + void off(int delay, bool fast = false) noexcept; /** * @brief gets the age of the Voice