From 396fb2199a91f72f7615d49605d9e236f9835eeb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 22 Jun 2020 22:14:03 +0200 Subject: [PATCH] Add the voice stealing helper --- src/sfizz/VoiceStealing.h | 87 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/sfizz/VoiceStealing.h diff --git a/src/sfizz/VoiceStealing.h b/src/sfizz/VoiceStealing.h new file mode 100644 index 00000000..8cf4362b --- /dev/null +++ b/src/sfizz/VoiceStealing.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz +#include "Config.h" +#include "Voice.h" +#include "SisterVoiceRing.h" +#include +#include "absl/types/span.h" + +namespace sfz +{ +class VoiceStealing +{ +public: + VoiceStealing() + { + voiceScores.reserve(config::maxVoices); + } + + Voice* steal(absl::Span voices) noexcept + { + // Start of the voice stealing algorithm + absl::c_sort(voices, voiceOrdering); + + const auto sumEnvelope = absl::c_accumulate(voices, 0.0f, [](float sum, const Voice* v) { + return sum + v->getAverageEnvelope(); + }); + const auto envThreshold = sumEnvelope + / static_cast(voices.size()) * config::stealingEnvelopeCoeff; + const auto ageThreshold = voices.front()->getAge() * config::stealingAgeCoeff; + + Voice* returnedVoice = voices.front(); + unsigned idx = 0; + while (idx < voices.size()) { + const auto ref = voices[idx]; + + if (ref->getAge() < ageThreshold) { + // Went too far, we'll kill the oldest note. + break; + } + + float maxEnvelope { 0.0f }; + SisterVoiceRing::applyToRing(ref, [&](Voice* v) { + maxEnvelope = max(maxEnvelope, v->getAverageEnvelope()); + }); + + if (maxEnvelope < envThreshold) { + returnedVoice = ref; + break; + } + + // Jump over the sister voices in the set + do { idx++; } + while (idx < voices.size() && sisterVoices(ref, voices[idx])); + } + return returnedVoice; + } + +private: + struct VoiceScore + { + Voice* voice; + double score; + }; + + struct VoiceScoreComparator + { + bool operator()(const VoiceScore& voiceScore, const double& score) + { + return (voiceScore.score < score); + } + + bool operator()(const double& score, const VoiceScore& voiceScore) + { + return (score < voiceScore.score); + } + + bool operator()(const VoiceScore& lhs, const VoiceScore& rhs) + { + return (lhs.score < rhs.score); + } + }; + std::vector voiceScores; +}; +}