diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index 819434de..21a19ed2 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -97,13 +97,15 @@ void ADSREnvelope::getBlockInternal(absl::Span output) noexcept size_t count = 0; size_t size = output.size(); - if (shouldRelease && releaseDelay == 0) { - // release takes effect this frame - currentState = State::Release; - releaseDelay = -1; - } else if (shouldRelease && releaseDelay > 0) { - // prevent computing the segment further than release point - size = std::min(size, releaseDelay); + if (shouldRelease) { + if (releaseDelay > 0) { + // prevent computing the segment further than release point + size = std::min(size, releaseDelay); + } else if (releaseDelay == 0 && delay < 0) { + // release takes effect this frame + currentState = State::Release; + releaseDelay = -1; + } } Float previousValue; diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index 76738d7d..b1b10eee 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -588,3 +588,47 @@ TEST_CASE("[Polyphony] Choke same group and note if the region is switched off ( synth.renderBlock(buffer); REQUIRE( playingSamples(synth) == std::vector { "*sine" } ); } + +TEST_CASE("[Polyphony] A note coming at the same time as another can choke it") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav + key=81 group=2 sample=kick.wav + )"); + synth.noteOn(1, 69, 63); + synth.noteOn(1, 81, 127); + synth.renderBlock(buffer); + REQUIRE( activeSamples(synth) == std::vector { "snare.wav", "kick.wav" } ); + REQUIRE( playingSamples(synth) == std::vector { "kick.wav" } ); +} + +TEST_CASE("[Polyphony] A note coming one sample after another note can choke it") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav + key=81 group=2 sample=kick.wav + )"); + synth.noteOn(1, 69, 63); + synth.noteOn(2, 81, 127); + synth.renderBlock(buffer); + REQUIRE( activeSamples(synth) == std::vector { "snare.wav", "kick.wav" } ); + REQUIRE( playingSamples(synth) == std::vector { "kick.wav" } ); +} + +TEST_CASE("[Polyphony] A note coming one sample before another note cannot choke it") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav + key=81 group=2 sample=kick.wav + )"); + synth.noteOn(1, 81, 127); + synth.noteOn(2, 69, 63); + synth.renderBlock(buffer); + REQUIRE( playingSamples(synth) == std::vector { "kick.wav", "snare.wav" } ); +}