Add the voice stealing helper
This commit is contained in:
parent
7559dfdd7b
commit
396fb2199a
1 changed files with 87 additions and 0 deletions
87
src/sfizz/VoiceStealing.h
Normal file
87
src/sfizz/VoiceStealing.h
Normal file
|
|
@ -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 <vector>
|
||||
#include "absl/types/span.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
class VoiceStealing
|
||||
{
|
||||
public:
|
||||
VoiceStealing()
|
||||
{
|
||||
voiceScores.reserve(config::maxVoices);
|
||||
}
|
||||
|
||||
Voice* steal(absl::Span<Voice*> 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<float>(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<VoiceScore> voiceScores;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue