[Scummvm-git-logs] scummvm master -> b4c52cac223d5e9749b4b8e18573414f80ea11b9
AndywinXp
noreply at scummvm.org
Mon Jan 2 16:50:04 UTC 2023
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
b4c52cac22 SCUMM: DIMUSE: Implement adaptive buffer underrun correction
Commit: b4c52cac223d5e9749b4b8e18573414f80ea11b9
https://github.com/scummvm/scummvm/commit/b4c52cac223d5e9749b4b8e18573414f80ea11b9
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-01-02T17:50:00+01:00
Commit Message:
SCUMM: DIMUSE: Implement adaptive buffer underrun correction
Thanks to lephilousophe for the help on this one :-)
Changed paths:
engines/scumm/imuse_digi/dimuse_engine.cpp
engines/scumm/imuse_digi/dimuse_engine.h
engines/scumm/imuse_digi/dimuse_tracks.cpp
diff --git a/engines/scumm/imuse_digi/dimuse_engine.cpp b/engines/scumm/imuse_digi/dimuse_engine.cpp
index 10c70f16e5d..2e92b40ebe4 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.cpp
+++ b/engines/scumm/imuse_digi/dimuse_engine.cpp
@@ -78,6 +78,8 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer, Common::M
_radioChatterSFX = false;
_isEngineDisabled = false;
+ _checkForUnderrun = false;
+ _underrunCooldown = 0;
_audioNames = nullptr;
_numAudioNames = 0;
@@ -115,14 +117,20 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer, Common::M
_maxQueuedStreams++;
}
- // The lower optimal bound is always 5, except if we're operating in low latency mode
- _maxQueuedStreams = MAX(_mixer->getOutputBufSize() <= 1024 ? 4 : 5, _maxQueuedStreams);
+ // The lower optimal bound is always 4, except if we're operating in low latency mode
+ _maxQueuedStreams = MAX(_mixer->getOutputBufSize() <= 1024 ? 3 : 4, _maxQueuedStreams);
} else {
debug(5, "IMuseDigital::IMuseDigital(): WARNING: output audio buffer size not specified for this platform, defaulting _maxQueuedStreams to 4");
_maxQueuedStreams = 4;
}
+ // This value has been calculated in a way that is a good compromise
+ // between the absence of underruns and the lowest latency achievable.
+ // Of course this is never perfect, given the vast number of platforms
+ // we support, so the value might eventually be corrected by our custom
+ // adaptive buffer underrun correction routine.
_nominalBufferCount = _maxQueuedStreams;
+ _underrunCooldown = _maxQueuedStreams;
_vm->getTimerManager()->installTimerProc(timer_handler, 1000000 / _callbackFps, this, "IMuseDigital");
}
@@ -152,8 +160,8 @@ IMuseDigital::~IMuseDigital() {
}
int IMuseDigital::roundRobinSetBufferCount() {
- int minStreams = MAX<int>(_nominalBufferCount - 3, 0);
- int maxStreams = _nominalBufferCount + 3;
+ int minStreams = MAX<int>(_nominalBufferCount - 5, 1);
+ int maxStreams = _nominalBufferCount + 5;
_maxQueuedStreams++;
if (_maxQueuedStreams > maxStreams) {
@@ -163,6 +171,11 @@ int IMuseDigital::roundRobinSetBufferCount() {
return _maxQueuedStreams;
}
+void IMuseDigital::adaptBufferCount() {
+ _maxQueuedStreams++;
+ _nominalBufferCount = _maxQueuedStreams;
+}
+
void IMuseDigital::stopSound(int sound) {
diMUSEStopSound(sound);
}
diff --git a/engines/scumm/imuse_digi/dimuse_engine.h b/engines/scumm/imuse_digi/dimuse_engine.h
index 903f4b272b7..85dd2424f75 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.h
+++ b/engines/scumm/imuse_digi/dimuse_engine.h
@@ -84,6 +84,8 @@ private:
bool _isEarlyDiMUSE;
bool _isEngineDisabled;
+ bool _checkForUnderrun;
+ int _underrunCooldown;
// These three are manipulated in the waveOut functions
uint8 *_outputAudioBuffer;
@@ -405,6 +407,7 @@ public:
int clampTuning(int value, int minValue, int maxValue);
int checkHookId(int &trackHookId, int sampleHookId);
int roundRobinSetBufferCount();
+ void adaptBufferCount();
// CMDs
int cmdsHandleCmd(int cmd, uint8 *ptr = nullptr,
diff --git a/engines/scumm/imuse_digi/dimuse_tracks.cpp b/engines/scumm/imuse_digi/dimuse_tracks.cpp
index 36c49a95b11..2b180cf455e 100644
--- a/engines/scumm/imuse_digi/dimuse_tracks.cpp
+++ b/engines/scumm/imuse_digi/dimuse_tracks.cpp
@@ -150,6 +150,23 @@ void IMuseDigital::tracksCallback() {
_tracksPauseTimer = 3;
}
+ // This piece of code is responsible for adaptive buffer overrun correction:
+ // it checks whether a buffer underrun has occurred within our output stream
+ // and then it increments the buffer count.
+ //
+ // This is not part of the original implementation, but it's used to yield
+ // smooth audio hopefully on every device.
+ if (_internalMixer->_stream->endOfData() && _checkForUnderrun) {
+ debug(5, "IMuseDigital::tracksCallback(): WARNING: audio buffer underrun, adapting the buffer queue count...");
+
+ adaptBufferCount();
+
+ // Allow the routine to cooldown: i.e. wait until the engine manages to
+ // refill the stream with the most recent maximum number of queueable buffers.
+ _underrunCooldown = _maxQueuedStreams;
+ _checkForUnderrun = false;
+ }
+
// If we leave the number of queued streams unbounded, we fill the queue with streams faster than
// we can play them: this leads to a very noticeable audio latency and desync with the graphics.
if ((int)_internalMixer->_stream->numQueuedStreams() < _maxQueuedStreams) {
@@ -159,6 +176,15 @@ void IMuseDigital::tracksCallback() {
waveOutWrite(&_outputAudioBuffer, _outputFeedSize, _outputSampleRate);
if (_outputFeedSize != 0) {
+ // Let's see if we should check for buffer underruns...
+ if (!_checkForUnderrun) {
+ if (_underrunCooldown == 0) {
+ _checkForUnderrun = true;
+ } else {
+ _underrunCooldown--;
+ }
+ }
+
_internalMixer->clearMixerBuffer();
if (_isEarlyDiMUSE && _splayer && _splayer->isAudioCallbackEnabled()) {
_splayer->processDispatches(_outputFeedSize);
More information about the Scummvm-git-logs
mailing list