diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index 479075603..fa952373c 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -101,7 +101,7 @@ void ADSREnvelope::getBlockInternal(absl::Span output) noexcept if (releaseDelay > 0) { // prevent computing the segment further than release point size = std::min(size, releaseDelay); - } else if (releaseDelay == 0 && delay < 0) { + } else if (releaseDelay == 0 && delay <= 0) { // release takes effect this frame currentState = State::Release; releaseDelay = -1; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 63db7cdbe..e5233aacd 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1188,7 +1188,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept unsigned i = 0; while (i < numSamples) { int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; - if (wrappedIndex > loop.end) { + while (wrappedIndex > loop.end) { wrappedIndex -= loop.size; blockRestarts += 1; loop_.restarts += 1; diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 1b77c276f..311533ad7 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -2160,3 +2160,46 @@ TEST_CASE("[Synth] Reuse offed voices in the last case scenario for new notes") REQUIRE( notes == std::vector { i - 1, i } ); } } + +TEST_CASE("[Synth] Note on and off at the maximum delay") +{ + sfz::Synth synth; + synth.setSampleRate(12800); + synth.setSamplesPerBlock(128); + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"( + loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav + )"); + synth.setNumVoices(128); + synth.noteOn(127, 64, 64); + CHECK(synth.getNumActiveVoices() == 1); + synth.noteOff(127, 64, 0); + CHECK(synth.getNumActiveVoices() == 1); + // Render for a while + for (int i = 0; i < 100; ++i) + synth.renderBlock(buffer); + CHECK(synth.getNumActiveVoices() == 0); +} + +TEST_CASE("[Synth] Note on and off with delay") +{ + sfz::Synth synth; + synth.setSampleRate(12800); + synth.setSamplesPerBlock(128); + sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"( + loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav + )"); + synth.setNumVoices(128); + + int i; + for (i = 0; i < 127; ++i) { + synth.noteOn(i, i, 64); + synth.noteOff(i+1, i, 0); + } + CHECK(synth.getNumActiveVoices() == 127); + // Render for a while + for (int i = 0; i < 100; ++i) + synth.renderBlock(buffer); + CHECK(synth.getNumActiveVoices() == 0); +} \ No newline at end of file