Consider all sister voices when killing a note
This commit is contained in:
parent
81ee1f2e59
commit
cd455c435e
1 changed files with 52 additions and 40 deletions
|
|
@ -389,15 +389,14 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
|
|||
// TODO: adjust with LFO targets
|
||||
const auto maxOffset = [region]() {
|
||||
uint64_t sumOffsetCC = region->offset + region->offsetRandom;
|
||||
for (const auto& offsets: region->offsetCC)
|
||||
for (const auto& offsets : region->offsetCC)
|
||||
sumOffsetCC += offsets.data;
|
||||
return Default::offsetCCRange.clamp(sumOffsetCC);
|
||||
}();
|
||||
|
||||
if (!resources.filePool.preloadFile(region->sampleId, maxOffset))
|
||||
removeCurrentRegion();
|
||||
}
|
||||
else if (region->oscillator && !region->isGenerator()) {
|
||||
} else if (region->oscillator && !region->isGenerator()) {
|
||||
if (!resources.filePool.checkSampleId(region->sampleId)) {
|
||||
removeCurrentRegion();
|
||||
continue;
|
||||
|
|
@ -412,7 +411,6 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
|
|||
if (region->keyswitchLabel && region->keyswitch)
|
||||
keyswitchLabels.push_back({ *region->keyswitch, *region->keyswitchLabel });
|
||||
|
||||
|
||||
// Some regions had group number but no "group-level" opcodes handled the polyphony
|
||||
while (groupMaxPolyphony.size() <= region->group)
|
||||
groupMaxPolyphony.push_back(config::maxVoices);
|
||||
|
|
@ -473,26 +471,6 @@ 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>& voice) {
|
||||
|
|
@ -503,34 +481,69 @@ sfz::Voice* sfz::Synth::findFreeVoice() noexcept
|
|||
|
||||
// Find voices that can be stolen
|
||||
absl::c_sort(voiceViewArray, [](Voice* lhs, Voice* rhs) {
|
||||
return lhs->getAge() > rhs->getAge();
|
||||
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;
|
||||
|
||||
if (lhs->getTriggerType() > rhs->getTriggerType())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const auto sumEnvelope = absl::c_accumulate(voiceViewArray, 0.0f, [] (float sum, const Voice* v) {
|
||||
const auto sumEnvelope = absl::c_accumulate(voiceViewArray, 0.0f, [](float sum, const Voice* v) {
|
||||
return sum + v->getAverageEnvelope();
|
||||
});
|
||||
const auto envThreshold = sumEnvelope / static_cast<float>(voiceViewArray.size()) * 0.25f;
|
||||
const auto envThreshold = sumEnvelope / static_cast<float>(voiceViewArray.size()) * 0.5f;
|
||||
const auto ageThreshold = voiceViewArray.front()->getAge() * 0.5f;
|
||||
|
||||
Voice* returnedVoice = voiceViewArray.front();
|
||||
for (auto & voice : voiceViewArray) {
|
||||
if (voice->getAge() < ageThreshold) {
|
||||
// std::cout << "Went too far, picking the oldest note..." << '\n';
|
||||
unsigned idx = 0;
|
||||
while (idx < voiceViewArray.size()) {
|
||||
const auto refIdx = idx;
|
||||
const auto ref = voiceViewArray[idx];
|
||||
idx++;
|
||||
|
||||
if (ref->getAge() < ageThreshold) {
|
||||
unsigned killIdx = 1;
|
||||
while (killIdx < voiceViewArray.size()
|
||||
&& sisterVoices(returnedVoice, voiceViewArray[killIdx])) {
|
||||
voiceViewArray[killIdx]->reset();
|
||||
killIdx++;
|
||||
}
|
||||
// std::cout << "Went too far, picking the oldest voice and killing "
|
||||
// << killIdx << " voices" << '\n';
|
||||
returnedVoice->reset();
|
||||
break;
|
||||
}
|
||||
if (voice->getAverageEnvelope() < envThreshold) {
|
||||
// std::cout << "Found a better candidate!" << '\n';
|
||||
returnedVoice = voice;
|
||||
|
||||
float sumEnvelope = ref->getAverageEnvelope();
|
||||
while (idx < voiceViewArray.size() && sisterVoices(ref, voiceViewArray[idx])) {
|
||||
sumEnvelope += voiceViewArray[idx]->getAverageEnvelope();
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (sumEnvelope < envThreshold) {
|
||||
returnedVoice = ref;
|
||||
// std::cout << "Killing " << idx - refIdx << " voices" << '\n';
|
||||
for (unsigned j = refIdx; j < idx; j++)
|
||||
voiceViewArray[j]->reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto killedVoices = killSisterVoices(returnedVoice);
|
||||
UNUSED(killedVoices); // only in debug
|
||||
assert(killedVoices > 0);
|
||||
assert(returnedVoice->isFree());
|
||||
// std::cout << "Killed " << killedVoices << " voices" << '\n';
|
||||
|
||||
return returnedVoice;
|
||||
}
|
||||
|
||||
|
|
@ -599,7 +612,6 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
if (!lock.owns_lock())
|
||||
return;
|
||||
|
||||
|
||||
size_t numFrames = buffer.getNumFrames();
|
||||
auto tempSpan = resources.bufferPool.getStereoBuffer(numFrames);
|
||||
auto tempMixSpan = resources.bufferPool.getStereoBuffer(numFrames);
|
||||
|
|
@ -1107,7 +1119,7 @@ void sfz::Synth::resetAllControllers(int delay) noexcept
|
|||
fs::file_time_type sfz::Synth::checkModificationTime()
|
||||
{
|
||||
auto returnedTime = modificationTime;
|
||||
for (const auto& file: parser.getIncludedFiles()) {
|
||||
for (const auto& file : parser.getIncludedFiles()) {
|
||||
std::error_code ec;
|
||||
const auto fileTime = fs::last_write_time(file, ec);
|
||||
if (!ec && returnedTime < fileTime)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue