fix: bypass SpessaSynth AudioWorklet MIDI pipeline for looped voice release

SpessaSynth 4.3.1 bug: looped voices (Tremolo Strings, Trumpet) ignore
release envelope + CC 120 when processed through MIDI message pipeline
(processMessage). Fix: send stopAll directly to worklet via
handleMessage post() bypass, plus noteOn(vel=0) as alternate note-off.
This commit is contained in:
2026-07-27 12:27:51 +07:00
parent 187686aa82
commit 18d2503cb9
3 changed files with 12 additions and 7 deletions
+6 -6
View File
@@ -173,14 +173,11 @@
stopNote: function (channel, pitch) {
if (channel < 0 || channel > 15) return;
if (_initialized && _synthInstance) {
// Ensure sustain is OFF before noteOff (SpessaSynth uses >=8192 threshold)
try { _synthInstance.controllerChange(channel, 64, 0); } catch (e) {}
// Standard MIDI noteOff for the specific pitch — enters SoundFont release envelope
try { _synthInstance.noteOff(channel, pitch); } catch (e) {}
// Force immediate voice kill: CC 120 (All Sound Off) sets isActive=false instantly,
// bypassing the release envelope. CC 123 (All Notes Off) merely enters the release
// phase which respects long release tails (2-5s for sustained instruments).
try { _synthInstance.noteOn(channel, pitch, 0); } catch (e) {}
try { _synthInstance.controllerChange(channel, 120, 0); } catch (e) {}
try { _synthInstance.post({ channelNumber: channel, type: "stopAll", data: 1 }); } catch (e) {}
}
},
@@ -321,7 +318,10 @@
stopAll: function () {
if (_initialized && _synthInstance) {
try { for (let ch = 0; ch < 16; ch++) _synthInstance.controllerChange(ch, 120, 0); } catch (e) {}
for (let ch = 0; ch < 16; ch++) {
try { _synthInstance.controllerChange(ch, 120, 0); } catch (e) {}
try { _synthInstance.post({ channelNumber: ch, type: "stopAll", data: 1 }); } catch (e) {}
}
}
// Cancel all scheduled future notes
while (_scheduledNotes.length > 0) {
+1 -1
View File
@@ -27,7 +27,7 @@
<script src="/static/js/services/audioEngine.js?v=202607271016"></script>
<script src="/static/js/services/storage.js?v=202607271016"></script>
<script src="/static/js/services/soundfontStorage.js?v=202607271016"></script>
<script src="/static/js/services/soundfontPlayer.js?v=202607271016"></script>
<script src="/static/js/services/soundfontPlayer.js?v=202607271215"></script>
<script src="/static/js/services/aiGateway.js?v=202607271016"></script>
<script src="/static/js/services/dawCommandDispatcher.js?v=202607271016"></script>
<script src="/static/js/app.precompiled.js?v=202607271016" defer></script>