[Scummvm-git-logs] scummvm master -> 42e3d74a6abbe499b431a323bc380f551e53e76e
AndywinXp
noreply at scummvm.org
Thu Jul 10 11:21:44 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
42e3d74a6a SCUMM: COMI/DIMUSE: Fix rare glitches from rapid State/Sequence successions
Commit: 42e3d74a6abbe499b431a323bc380f551e53e76e
https://github.com/scummvm/scummvm/commit/42e3d74a6abbe499b431a323bc380f551e53e76e
Author: AndywinXp (andywinxp at gmail.com)
Date: 2025-07-10T13:21:36+02:00
Commit Message:
SCUMM: COMI/DIMUSE: Fix rare glitches from rapid State/Sequence successions
When entering certain rooms, it can happen that the game starts state and
sequence events in rapid succession (e.g. entering the Barbershop for the first time).
If the iMUSE callback runs between these evenys, it will cause small audio glitches
where the fade to the state is executed (when it shouldn't), then it's immediately
canceled and a fade from the intermediate state music to the sequence music is heard.
The disassembly doesn't present the problem, as a byproduct of some of its shenanigans,
i.e. checking for a xor flag (which we have) and the play cursor position (which we don't have),
which ends up creating perfect timing conditions for this issue to never occur.
The fastest way to fix this on our end is to skip the first audio callback after music
changes to match original DirectSound timing behavior.
Changed paths:
engines/scumm/imuse_digi/dimuse_scripts.cpp
engines/scumm/imuse_digi/dimuse_waveout.cpp
diff --git a/engines/scumm/imuse_digi/dimuse_scripts.cpp b/engines/scumm/imuse_digi/dimuse_scripts.cpp
index a2500d9fefd..41a12ffb159 100644
--- a/engines/scumm/imuse_digi/dimuse_scripts.cpp
+++ b/engines/scumm/imuse_digi/dimuse_scripts.cpp
@@ -758,6 +758,13 @@ void IMuseDigital::playComiMusic(const char *songName, const imuseComiTable *tab
int hookId = 0;
int fadeDelay = 0;
+ // This flag is not set in the original,
+ // but since we're not using DirectSound and this is pretty much timing related
+ // please see IMuseDigital::waveOutWrite() for more context...
+ _mutex->lock();
+ _waveOutXorTrigger = 1;
+ _mutex->unlock();
+
if ((songName != nullptr) && (attribPos != 0)) {
if (table->attribPos != 0)
attribPos = table->attribPos;
diff --git a/engines/scumm/imuse_digi/dimuse_waveout.cpp b/engines/scumm/imuse_digi/dimuse_waveout.cpp
index c9712a998d3..61230d9e2ad 100644
--- a/engines/scumm/imuse_digi/dimuse_waveout.cpp
+++ b/engines/scumm/imuse_digi/dimuse_waveout.cpp
@@ -71,13 +71,44 @@ void IMuseDigital::waveOutWrite(uint8 **audioData, int &feedSize, int &sampleRat
if (_waveOutDisableWrite)
return;
+ feedSize = 0;
+
+ // A bit of context for what follows:
+ //
+ // In COMI, when entering certain rooms (e.g. barber shop in Plunder Island), the game
+ // sends a State music event followed immediately by a Sequence music event.
+ // If the iMUSE callback happens to run between these two commands, it can cause a brief
+ // audio glitch where a few milliseconds of the intermediate state music is heard
+ // before being replaced by the sequence music, with the fade in between canceled.
+ //
+ // To prevent this, we skip the very first audio callback after any music change
+ // by setting _waveOutXorTrigger to 1 in playComiMusic(). This gives the scripts
+ // enough time to send any follow-up sequence events before iMUSE processes
+ // the audio transition, ensuring the absence of glitches and most importantly
+ // no permanent audio delay on other audio feeds.
+ //
+ // This is very strongly inspired by what the disassembly does:
+ //
+ // The original DirectSound implementation uses the XOR flag combined with play
+ // cursor position checks that naturally skip audio processing cycles when the
+ // play cursor gets too close to the write cursor. In addition to this, the main
+ // portion of tracksCallback() is executed in loop until feedSide is finally 0.
+ // This creates the exact timing conditions where rapid music events have sufficient
+ // time to accumulate before iMUSE processes any audio transitions.
+ //
+ // We're not using DirectSound, so recreate this I could either simulate the
+ // play cursor handling shenanigans, or I could just do exactly what I have done :-)
+ if (_vm->_game.id == GID_CMI && _waveOutXorTrigger == 1) {
+ _waveOutXorTrigger = 0;
+ return;
+ }
+
if (!_isEarlyDiMUSE && _vm->_game.id == GID_DIG) {
_waveOutXorTrigger ^= 1;
if (!_waveOutXorTrigger)
return;
}
- feedSize = 0;
if (_mixer->isReady()) {
curBufferBlock = &_waveOutOutputBuffer[_waveOutPreferredFeedSize * _waveOutWriteIndex * _waveOutBytesPerSample * _waveOutNumChannels];
More information about the Scummvm-git-logs
mailing list