Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues when Note on/off at the maximum delay #1251

Closed
KKQ-KKQ opened this issue Feb 23, 2024 · 2 comments · Fixed by #1252
Closed

Issues when Note on/off at the maximum delay #1251

KKQ-KKQ opened this issue Feb 23, 2024 · 2 comments · Fixed by #1252

Comments

@KKQ-KKQ
Copy link
Contributor

KKQ-KKQ commented Feb 23, 2024

The following test cases fail in my environment.

TEST_CASE("[Synth] Note on and off at the maximum delay")
{
    sfz::Synth synth;
    synth.setSampleRate(12800);
    synth.setSamplesPerBlock(128);
    sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
    synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"(
        <region> loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav
    )");
    synth.setNumVoices(128);
    //synth.noteOn(126, 64, 0); // this passes the test
    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); // this fails
}

TEST_CASE("[Synth] Note on and off with delay")
{
    sfz::Synth synth;
    synth.setSampleRate(12800);
    synth.setSamplesPerBlock(128);
    sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
    synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"(
        <region> loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav
    )");
    synth.setNumVoices(128);

    for (int 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); // crash
    CHECK(synth.getNumActiveVoices() == 0);
}
@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 23, 2024

I found that the following patch fixes the second test.

diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp
index 63db7cdb..e5233aac 100644
--- a/src/sfizz/Voice.cpp
+++ b/src/sfizz/Voice.cpp
@@ -1188,7 +1188,7 @@ void Voice::Impl::fillWithData(AudioSpan<float> 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;

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 23, 2024

I found that the following patch fixes the first test. I'll make a pull request.

diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp
index 47907560..fa952373 100644
--- a/src/sfizz/ADSREnvelope.cpp
+++ b/src/sfizz/ADSREnvelope.cpp
@@ -101,7 +101,7 @@ void ADSREnvelope::getBlockInternal(absl::Span<Float> output) noexcept
             if (releaseDelay > 0) {
                 // prevent computing the segment further than release point
                 size = std::min<size_t>(size, releaseDelay);
-            } else if (releaseDelay == 0 && delay < 0) {
+            } else if (releaseDelay == 0 && delay <= 0) {
                 // release takes effect this frame
                 currentState = State::Release;
                 releaseDelay = -1;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant