diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 1d85b6ac..01cf351b 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -687,6 +687,8 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc for (auto& region : noteActivationLists[noteNumber]) { if (region->registerNoteOn(noteNumber, velocity, randValue)) { unsigned activeNotesInGroup { 0 }; + unsigned activeNotes { 0 }; + Voice* selfMaskCandidate { nullptr }; for (auto& voice : voices) { const auto voiceRegion = voice->getRegion(); @@ -696,6 +698,24 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc if (voiceRegion->group == region->group) activeNotesInGroup += 1; + if (region->notePolyphony) { + if (voice->getTriggerNumber() == noteNumber && voice->getTriggerType() == Voice::TriggerType::NoteOn) { + activeNotes += 1; + switch (region->selfMask) { + case SfzSelfMask::mask: + if (voice->getTriggerValue() < velocity) { + if (!selfMaskCandidate || selfMaskCandidate->getTriggerValue() > voice->getTriggerValue()) + selfMaskCandidate = voice.get(); + } + break; + case SfzSelfMask::dontMask: + if (!selfMaskCandidate || selfMaskCandidate->getSourcePosition() < voice->getSourcePosition()) + selfMaskCandidate = voice.get(); + break; + } + } + } + if (voice->checkOffGroup(delay, region->group)) noteOffDispatch(delay, voice->getTriggerNumber(), voice->getTriggerValue()); } @@ -703,6 +723,13 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc if (activeNotesInGroup >= groupMaxPolyphony[region->group]) continue; + if (region->notePolyphony && activeNotes >= *region->notePolyphony) { + if (selfMaskCandidate != nullptr) + selfMaskCandidate->release(delay); + else // We're the lowest velocity guy here + continue; + } + auto voice = findFreeVoice(); if (voice == nullptr) continue; diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 1772bf45..4227c326 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -210,6 +210,13 @@ public: * @param numFilters */ void setMaxEQsPerVoice(size_t numEQs); + /** + * @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, bool fastRelease = false) noexcept; Duration getLastDataDuration() const noexcept { return dataDuration; } Duration getLastAmplitudeDuration() const noexcept { return amplitudeDuration; } @@ -243,13 +250,6 @@ private: * @param buffer */ void processStereo(AudioSpan buffer) noexcept; - /** - * @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, bool fastRelease = false) noexcept; Region* region { nullptr }; enum class State {