diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f621420..96d23e1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,8 @@ android { // (android.media.midi) and AAudio low-latency audio we rely on. minSdk = 26 targetSdk = 34 - versionCode = 11 - versionName = "0.4.4" + versionCode = 12 + versionName = "0.4.5" // We provide our own instrumentation runner if/when tests are added. testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/space/rcmd/android/sizzle/audio/SynthVoice.kt b/app/src/main/java/space/rcmd/android/sizzle/audio/SynthVoice.kt index 53080d8..d2b79e5 100644 --- a/app/src/main/java/space/rcmd/android/sizzle/audio/SynthVoice.kt +++ b/app/src/main/java/space/rcmd/android/sizzle/audio/SynthVoice.kt @@ -268,7 +268,14 @@ class SynthVoice(private val sampleRate: Int) { 1 -> { level += dt / a; if (level >= 1f) { level = 1f; stage = 2 } } 2 -> { level -= dt / d.coerceAtLeast(0.001f) * (1f - s); if (level <= s) { level = s; stage = 3 } } 3 -> {} - 4 -> { level -= dt / r.coerceAtLeast(0.001f) * s.coerceAtLeast(0.001f); if (level <= 0f) { level = 0f; stage = 0 } } + // Release ramps to zero at a rate set by the release TIME alone. The + // decrement was previously scaled by the sustain level (`* s`), so a + // percussive patch (sustain≈0) released ~1000× too slowly — the voice + // effectively never freed, piling up stuck notes and CPU until the + // audio callback missed its deadline (dropouts) and note-offs looked + // ignored (panic needed). A constant 1/r rate guarantees the voice + // reaches silence within r seconds from any level. + 4 -> { level -= dt / r.coerceAtLeast(0.001f); if (level <= 0f) { level = 0f; stage = 0 } } } return level }