From df603172612f0f35ce1fb48377caf6650bafa9d1 Mon Sep 17 00:00:00 2001 From: myuu-151 Date: Thu, 29 Oct 2026 15:45:31 +0000 Subject: [PATCH] libasnd: clear VOICE_UPDATE when the voice is sent to the DSP VOICE_UPDATE was cleared only for voice 0 (in the DMA callback) and by the look-ahead, which clears the next active voice's flag while the voice before it is still being mixed. A voice set with ASND_SetVoice after the look-ahead had passed it was sent to the DSP with the flag still on. When its mix came back, __dsp_requestcallback took the flag to mean the voice had been set again during the mix, discarded the DSP's progress and sent the voice from its start once more, so the first 1024 samples of the sound played twice. Clear the flag at the point the voice is sent, as the voice 0 path already does. A voice set while it is on the DSP still sets the flag again and is restarted as before. Co-Authored-By: Claude Opus 5.5 (1M context) --- libasnd/asndlib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libasnd/asndlib.c b/libasnd/asndlib.c index 128915665..69c026150 100644 --- a/libasnd/asndlib.c +++ b/libasnd/asndlib.c @@ -220,6 +220,11 @@ static void __dsp_requestcallback(dsptask_t *task) return; } + // the DSP takes the new song now: clear the flag here, not only in the look-ahead below (a voice set after the + // look-ahead passed it would otherwise be restarted when it comes back, playing its first block twice) + if(sound_data[snd_chan].flags & VOICE_UPDATE) + sound_data[snd_chan].flags &=~(VOICE_UPDATE | VOICE_VOLUPDATE | VOICE_PAUSE | VOICE_UPDATEADD); + sound_data_dma=sound_data[snd_chan]; DCFlushRange(&sound_data_dma, sizeof(t_sound_data));