taut fix ghost vox orphanage

This commit is contained in:
minjaesong
2026-06-15 02:07:09 +09:00
parent fc17892a23
commit f4c6c945b1
3 changed files with 38 additions and 16 deletions

View File

@@ -1,19 +1,14 @@
Copyright (c) 2020-2026 CuriousTorvald Copyright (c) 2020-2026 CuriousTorvald
Permission is hereby granted, free of charge, to any person obtaining a copy This program is free software: you can redistribute it and/or modify
of this software and associated documentation files (the "Software"), to deal it under the terms of the GNU General Public License as published by
in the Software without restriction, including without limitation the rights the Free Software Foundation, either version 3 of the License, or
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell (at your option) any later version.
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all This program is distributed in the hope that it will be useful,
copies or substantial portions of the Software. but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR You should have received a copy of the GNU General Public License
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, along with this program. If not, see <http://www.gnu.org/licenses/>.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -2868,7 +2868,18 @@ TODO:
at execApp (<eval>:1457:16) at execApp (<eval>:1457:16)
at Object.execute (<eval>:893:38) at Object.execute (<eval>:893:38)
at <eval>:867:31 at <eval>:867:31
[ ] Timbres of Heaven's Overdriven Gt decays EXTREMELY SLOWLY even after the fix [x] Timbres of Heaven's Overdriven Gt decays EXTREMELY SLOWLY even after the fix
* DONE 2026-06-15. Root cause (engine). Overdriven Gt becomes a 4-layer Metainstrument.
Layer children inherit the parent's key-off only via the per-tick background-voice sync
(AudioAdapter.kt:3782), which requires parent.active. With a fast fadeout (fo=1067 = 1-tick
cut), the foreground voice deactivates in the same tick KEY_OFF fires — before the sync runs —
so the children were detached as orphans that never picked up the release and kept looping at
the ~0.70 sustain until the next note. That's the "extremely slow decay"/ringing tail, and it's
ToH-specific because ToH leans on multi-layer presets with short releases.
Fix (AudioAdapter.kt, inactive-parent branch): inherit parent.keyOff/noteFading before
detaching, mirroring the existing active-branch. parent.keyOff survives deactivation and is
reset on retrigger, so a true value means this note was released. A parent that ended naturally
(no release) still leaves the child to finish on its own.
[ ] Some ways to decouple Sample+Inst and patterns into separate files (tsvm-doom needs separate file access; samplepack can be uploaded once on init) [ ] Some ways to decouple Sample+Inst and patterns into separate files (tsvm-doom needs separate file access; samplepack can be uploaded once on init)
TODO - list of demo songs that MUST ship with Microtone: TODO - list of demo songs that MUST ship with Microtone:

View File

@@ -3758,6 +3758,22 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
if (bg.isLayerChild) { if (bg.isLayerChild) {
val parent = ts.voices.getOrNull(bg.sourceChannel) val parent = ts.voices.getOrNull(bg.sourceChannel)
if (parent == null || !parent.active) { if (parent == null || !parent.active) {
// Parent note ended: detach so this layer finishes its own release as a
// plain ghost. But if the parent was RELEASED (key-off / note-fade) and its
// own fadeout deactivated it in the SAME tick the release fired — a fast
// fadeout, e.g. fo≈1067 (a 1-tick cut) — the parent-sync below never ran
// while it was active, so the release was never carried across and a still
// looping/sustaining child would ring on until the next note displaces it.
// Inherit the parent's final release here before detaching (parent.keyOff /
// noteFading survive deactivation; both are reset on retrigger, so a true
// value means THIS note was released, not a stale flag). A parent that ended
// without release (natural sample/env end) leaves the child to finish on its
// own, unchanged. Symptom: long tails on multi-layer SF2 presets with a short
// release, e.g. Timbres of Heaven's sustained guitars/organs.
if (parent != null && !bg.keyOff && !bg.noteFading) {
if (parent.keyOff) { bg.keyOff = true; applyKeyLift(bg, instruments[bg.instrumentId]) }
else if (parent.noteFading) bg.noteFading = true
}
bg.isLayerChild = false bg.isLayerChild = false
} else { } else {
bg.noteVal = (parent.noteVal + bg.layerRelDetune).coerceIn(0x20, 0xFFFF) bg.noteVal = (parent.noteVal + bg.layerRelDetune).coerceIn(0x20, 0xFFFF)