diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 823a8653..1d8ccb49 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -473,19 +473,58 @@ bool sfz::Synth::loadSfzFile(const fs::path& file) return true; } +unsigned sfz::Synth::killSisterVoices(const Voice* voiceToKill) noexcept +{ + const auto age = voiceToKill->getAge(); + const auto type = voiceToKill->getTriggerType(); + const auto number = voiceToKill->getTriggerNumber(); + const auto value = voiceToKill->getTriggerValue(); + + unsigned killedVoices = 0; + for (auto & voice : voiceViewArray) { + if (voice->getAge() == age + && voice->getTriggerType() == type + && voice->getTriggerNumber() == number + && voice->getTriggerValue() == value) { + killedVoices++; + voice->reset(); + } + } + return killedVoices; +} + sfz::Voice* sfz::Synth::findFreeVoice() noexcept { - auto freeVoice = absl::c_find_if(voices, [](const std::unique_ptr& voice) { return voice->isFree(); }); + auto freeVoice = absl::c_find_if(voices, [](const std::unique_ptr& voice) { + return voice->isFree(); + }); if (freeVoice != voices.end()) return freeVoice->get(); // Find voices that can be stolen absl::c_sort(voiceViewArray, [](Voice* lhs, Voice* rhs) { - return lhs->getAverageEnvelope() < rhs->getAverageEnvelope(); + return lhs->getAge() < rhs->getAge(); }); - voiceViewArray.front()->reset(); - return voiceViewArray.front(); + const auto sumEnvelope = absl::c_accumulate(voiceViewArray, 0.0f, [] (float sum, const Voice* v) { + return sum + v->getAverageEnvelope(); + }); + const auto threshold = sumEnvelope / static_cast(voiceViewArray.size()) / 2; + + Voice* returnedVoice = voiceViewArray.front(); + for (auto & voice : voiceViewArray) { + if (voice->getAverageEnvelope() < threshold) { + returnedVoice = voice; + break; + } + } + const auto killedVoices = killSisterVoices(returnedVoice); + UNUSED(killedVoices); // only in debug + assert(killedVoices > 0); + assert(returnedVoice->isFree()); + std::cout << "Killed " << killedVoices << " voices"; + + return returnedVoice; } int sfz::Synth::getNumActiveVoices() const noexcept diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0eddea0b..9d2583ec 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -495,6 +495,8 @@ private: void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept; void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept; + unsigned killSisterVoices(const Voice* voiceToKill) noexcept; + // Opcode memory; these are used to build regions, as a new region // will integrate opcodes from the group, master and global block std::vector globalOpcodes;