Voice stealing tweaks
This commit is contained in:
parent
443e89c45d
commit
c39a50ee92
4 changed files with 40 additions and 25 deletions
|
|
@ -680,6 +680,9 @@ void sfz::Synth::setSampleRate(float sampleRate) noexcept
|
|||
void sfz::Synth::renderVoiceToOutputs(Voice& voice, AudioSpan<float>& tempSpan) noexcept
|
||||
{
|
||||
const Region* region = voice.getRegion();
|
||||
if (region == nullptr)
|
||||
return;
|
||||
|
||||
voice.renderBlock(tempSpan);
|
||||
for (size_t i = 0, n = effectBuses.size(); i < n; ++i) {
|
||||
if (auto& bus = effectBuses[i]) {
|
||||
|
|
@ -936,8 +939,12 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc
|
|||
}
|
||||
|
||||
render:
|
||||
// For some reason we did not find a voice to use.
|
||||
// This is a degraded case but we'll just drop the note on.
|
||||
if (selectedVoice == nullptr)
|
||||
continue;
|
||||
|
||||
// Kill voice if necessary, pre-rendering it into the output buffers
|
||||
ASSERT(selectedVoice);
|
||||
if (!selectedVoice->isFree()) {
|
||||
auto tempSpan = resources.bufferPool.getStereoBuffer(samplesPerBlock);
|
||||
SisterVoiceRing::applyToRing(selectedVoice, [&] (Voice* v) {
|
||||
|
|
@ -1295,22 +1302,22 @@ void sfz::Synth::resetVoices(int numVoices)
|
|||
voices.clear();
|
||||
voices.reserve(numVoices);
|
||||
|
||||
for (int i = 0; i < numVoices; ++i) {
|
||||
auto voice = absl::make_unique<Voice>(i, resources);
|
||||
voice->setStateListener(this);
|
||||
voices.emplace_back(std::move(voice));
|
||||
}
|
||||
|
||||
voiceViewArray.clear();
|
||||
voiceViewArray.reserve(numVoices);
|
||||
|
||||
regionPolyphonyArray.clear();
|
||||
regionPolyphonyArray.reserve(numVoices);
|
||||
|
||||
for (int i = 0; i < numVoices; ++i) {
|
||||
auto voice = absl::make_unique<Voice>(i, resources);
|
||||
voice->setStateListener(this);
|
||||
voiceViewArray.push_back(voice.get());
|
||||
voices.emplace_back(std::move(voice));
|
||||
}
|
||||
|
||||
for (auto& voice : voices) {
|
||||
voice->setSampleRate(this->sampleRate);
|
||||
voice->setSamplesPerBlock(this->samplesPerBlock);
|
||||
voiceViewArray.push_back(voice.get());
|
||||
}
|
||||
|
||||
this->numVoices = numVoices;
|
||||
|
|
|
|||
|
|
@ -270,7 +270,8 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
ASSERT(static_cast<int>(buffer.getNumFrames()) <= samplesPerBlock);
|
||||
buffer.fill(0.0f);
|
||||
|
||||
ASSERT(region != nullptr);
|
||||
if (region == nullptr)
|
||||
return;
|
||||
|
||||
const auto delay = min(static_cast<size_t>(initialDelay), buffer.getNumFrames());
|
||||
auto delayed_buffer = buffer.subspan(delay);
|
||||
|
|
|
|||
|
|
@ -494,28 +494,31 @@ private:
|
|||
|
||||
inline bool sisterVoices(const Voice* lhs, const Voice* rhs)
|
||||
{
|
||||
return lhs->getAge() == rhs->getAge()
|
||||
&& lhs->getTriggerNumber() == rhs->getTriggerNumber()
|
||||
&& lhs->getTriggerValue() == rhs->getTriggerValue()
|
||||
&& lhs->getTriggerType() == rhs->getTriggerType();
|
||||
if (lhs->getAge() != rhs->getAge())
|
||||
return false;
|
||||
|
||||
if (lhs->getTriggerNumber() != rhs->getTriggerNumber())
|
||||
return false;
|
||||
|
||||
if (lhs->getTriggerValue() != rhs->getTriggerValue())
|
||||
return false;
|
||||
|
||||
if (lhs->getTriggerType() != rhs->getTriggerType())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool voiceOrdering(const Voice* lhs, const Voice* rhs)
|
||||
{
|
||||
if (lhs->getAge() > rhs->getAge())
|
||||
return true;
|
||||
if (lhs->getAge() < rhs->getAge())
|
||||
return false;
|
||||
|
||||
if (lhs->getTriggerNumber() > rhs->getTriggerNumber())
|
||||
return true;
|
||||
if (lhs->getTriggerNumber() < rhs->getTriggerNumber())
|
||||
return false;
|
||||
|
||||
if (lhs->getTriggerValue() > rhs->getTriggerValue())
|
||||
return true;
|
||||
|
||||
if (lhs->getTriggerValue() < rhs->getTriggerValue())
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (lhs->getTriggerType() > rhs->getTriggerType())
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ sfz::VoiceStealing::VoiceStealing()
|
|||
sfz::Voice* sfz::VoiceStealing::steal(absl::Span<sfz::Voice*> voices) noexcept
|
||||
{
|
||||
// Start of the voice stealing algorithm
|
||||
absl::c_sort(voices, voiceOrdering);
|
||||
absl::c_stable_sort(voices, voiceOrdering);
|
||||
|
||||
const auto sumEnvelope = absl::c_accumulate(voices, 0.0f, [](float sum, const Voice* v) {
|
||||
return sum + v->getAverageEnvelope();
|
||||
|
|
@ -21,9 +21,8 @@ sfz::Voice* sfz::VoiceStealing::steal(absl::Span<sfz::Voice*> voices) noexcept
|
|||
// This is not perfect because pad-type voices will take a long time to output
|
||||
// their sound, but it's reasonable for sounds with a quick attack and longer
|
||||
// release.
|
||||
const auto ageThreshold = voices.front()->getAge() * config::stealingAgeCoeff;
|
||||
// This needs to be positive
|
||||
ASSERT(ageThreshold >= 0);
|
||||
const auto ageThreshold =
|
||||
static_cast<int>(voices.front()->getAge() * config::stealingAgeCoeff) + 1;
|
||||
|
||||
Voice* returnedVoice = voices.front();
|
||||
unsigned idx = 0;
|
||||
|
|
@ -49,5 +48,10 @@ sfz::Voice* sfz::VoiceStealing::steal(absl::Span<sfz::Voice*> voices) noexcept
|
|||
do { idx++; }
|
||||
while (idx < voices.size() && sisterVoices(ref, voices[idx]));
|
||||
}
|
||||
|
||||
// Guard for future changes: voices with age 0 just started; don't kill those.
|
||||
if (returnedVoice->getAge() == 0)
|
||||
return {};
|
||||
|
||||
return returnedVoice;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue