Add checks for release voices and note_polyphony

This commit is contained in:
Paul Ferrand 2020-08-26 01:04:10 +02:00
parent 1f65c135bc
commit fa37669e08
3 changed files with 48 additions and 3 deletions

View file

@ -976,7 +976,8 @@ void sfz::Synth::checkNotePolyphony(const Region* region, int delay, const Trigg
for (Voice* voice : voiceViewArray) {
const sfz::TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent();
if (!voice->releasedOrFree()
const bool skipVoice = (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) || voice->isFree();
if (!skipVoice
&& voice->getRegion()->group == region->group
&& voiceTriggerEvent.number == triggerEvent.number
&& voiceTriggerEvent.type == triggerEvent.type) {
@ -984,8 +985,9 @@ void sfz::Synth::checkNotePolyphony(const Region* region, int delay, const Trigg
switch (region->selfMask) {
case SfzSelfMask::mask:
if (voiceTriggerEvent.value <= triggerEvent.value) {
if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value)
if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) {
selfMaskCandidate = voice;
}
}
break;
case SfzSelfMask::dontMask:

View file

@ -193,7 +193,7 @@ void sfz::Voice::registerNoteOff(int delay, int noteNumber, float velocity) noex
if (state != State::playing)
return;
if (triggerEvent.number == noteNumber) {
if (triggerEvent.number == noteNumber && triggerEvent.type == TriggerEventType::NoteOn) {
noteIsOff = true;
if (region->loopMode == SfzLoopMode::one_shot)

View file

@ -286,6 +286,7 @@ TEST_CASE("[Polyphony] Self-masking only works from low to high")
synth.noteOn(0, 64, 63 );
synth.noteOn(0, 64, 62 );
REQUIRE( synth.getNumActiveVoices(true) == 2 ); // Both notes are playing
REQUIRE( numPlayingVoices(synth) == 2 ); // id
REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm);
REQUIRE(!synth.getVoiceView(0)->releasedOrFree());
REQUIRE( synth.getVoiceView(1)->getTriggerEvent().value == 62_norm);
@ -386,3 +387,45 @@ TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups (wi
REQUIRE( synth.getVoiceView(1)->getTriggerEvent().value == 64_norm);
REQUIRE(!synth.getVoiceView(1)->releasedOrFree());
}
TEST_CASE("[Polyphony] Note polyphony operates on release voices")
{
sfz::Synth synth;
sfz::AudioBuffer<float> buffer { 2, blockSize };
synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"(
<region> key=48 note_polyphony=1 sample=*saw trigger=release_key ampeg_attack=1 ampeg_decay=1
)");
synth.noteOn(0, 48, 63 );
synth.noteOff(10, 48, 0 );
REQUIRE( synth.getNumActiveVoices(true) == 1);
synth.noteOn(20, 48, 65 );
synth.noteOff(30, 48, 10 );
REQUIRE( synth.getNumActiveVoices(true) == 2 );
synth.renderBlock(buffer);
REQUIRE(numPlayingVoices(synth) == 1 );
REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm);
REQUIRE( synth.getVoiceView(0)->releasedOrFree());
REQUIRE( synth.getVoiceView(1)->getTriggerEvent().value == 65_norm);
REQUIRE(!synth.getVoiceView(1)->releasedOrFree());
}
TEST_CASE("[Polyphony] Note polyphony operates on release voices (masking works from low to high but takes into account the replaced velocity)")
{
sfz::Synth synth;
sfz::AudioBuffer<float> buffer { 2, blockSize };
synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"(
<region> key=48 note_polyphony=1 sample=*saw trigger=release_key ampeg_attack=1 ampeg_decay=1
)");
synth.noteOn(0, 48, 63 );
synth.noteOff(10, 48, 0 );
REQUIRE( synth.getNumActiveVoices(true) == 1);
REQUIRE( numPlayingVoices(synth) == 1 );
synth.noteOn(20, 48, 61 );
synth.noteOff(30, 48, 10 );
REQUIRE( synth.getNumActiveVoices(true) == 2 );
REQUIRE( numPlayingVoices(synth) == 2 );
REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm);
REQUIRE(!synth.getVoiceView(0)->releasedOrFree());
REQUIRE( synth.getVoiceView(1)->getTriggerEvent().value == 61_norm);
REQUIRE(!synth.getVoiceView(1)->releasedOrFree());
}