[Scummvm-git-logs] scummvm master -> d5077a13b3480fc730e4f660b8e85cd882e842fa
sev-
noreply at scummvm.org
Mon Aug 18 10:40:22 UTC 2025
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
01ba459d9c MOHAWK: Fix sound discontinuity.
50926fec90 MOHAWK: Refactor discontinuity check.
d5077a13b3 MOHAWK: Add option to toggle discontinuity check.
Commit: 01ba459d9c9fdc9b5289d53f81351213f3a580b7
https://github.com/scummvm/scummvm/commit/01ba459d9c9fdc9b5289d53f81351213f3a580b7
Author: Alstruit (34786806+Alstruit at users.noreply.github.com)
Date: 2025-08-18T12:40:18+02:00
Commit Message:
MOHAWK: Fix sound discontinuity.
Changed paths:
engines/mohawk/sound.cpp
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index e0a674f2112..c7e36cb6eb1 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -137,6 +137,57 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
dataChunk.loopStart = stream->readUint32BE();
dataChunk.loopEnd = stream->readUint32BE();
+ // This fix applies a balanced heuristic to detect and prevent audible pops/clicks
+ // at the end of 8-bit unsigned PCM samples, which were present in the original game assets.
+ if (dataChunk.encoding == kCodecRaw && dataChunk.bitsPerSample == 8 && dataChunk.sampleCount >= 4) {
+ const int PCM8_U_SILENCE = 0x80;
+ const int SQUELCH = 32; // Threshold of discontinuity before removing. Lower values = increased sensitivity.
+ bool is_safe = false;
+
+ // Peek at the last 4 samples without permanently moving the stream pointer.
+ uint32 current_pos = stream->pos();
+ stream->seek(current_pos + dataSize - 4, SEEK_SET);
+ byte s[4];
+ stream->read(s, 4);
+ stream->seek(current_pos, SEEK_SET); // Return to original position
+
+ // Path 1: Check for sustained quietness. If all samples are very close to silence,
+ // any minor fluctuation is inaudible and the sound is considered safe.
+ bool is_stable_and_quiet = true;
+ for (int i = 0; i < 4; i++) {
+ if (abs(s[i] - PCM8_U_SILENCE) > SQUELCH) {
+ is_stable_and_quiet = false;
+ break;
+ }
+ }
+ if (is_stable_and_quiet) {
+ is_safe = true;
+ }
+
+ // Path 2: If not stable/quiet, check for a consistent fade-out trend.
+ if (!is_safe) {
+ int dist_last = abs(s[3] - PCM8_U_SILENCE);
+ int dist_prev = abs(s[2] - PCM8_U_SILENCE);
+ int dist_ante = abs(s[1] - PCM8_U_SILENCE);
+
+ if (dist_last < dist_prev && dist_prev < dist_ante) {
+ is_safe = true;
+ }
+ }
+
+ // If the ending is neither stable nor fading, apply the fix.
+ if (!is_safe) {
+ debug(0, "MOHAWK: Pop/click detected at sample %u. Final samples: %02x %02x %02x %02x. Truncating one sample.",
+ dataChunk.sampleCount, s[0], s[1], s[2], s[3]);
+
+ dataChunk.sampleCount--;
+ dataSize--; // Also decrement the total data size to be read.
+ if (dataChunk.loopCount == 0xFFFF && dataChunk.loopEnd > dataChunk.sampleCount) {
+ dataChunk.loopEnd = dataChunk.sampleCount;
+ }
+ }
+ }
+
// NOTE: We currently ignore all of the loop parameters here. Myst uses the
// loopCount variable but the loopStart and loopEnd are always 0 and the size of
// the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE
Commit: 50926fec90c62b8fc8503e6445e63cd9fed9b8d6
https://github.com/scummvm/scummvm/commit/50926fec90c62b8fc8503e6445e63cd9fed9b8d6
Author: Alstruit (34786806+Alstruit at users.noreply.github.com)
Date: 2025-08-18T12:40:18+02:00
Commit Message:
MOHAWK: Refactor discontinuity check.
Apply suggestions.
Changed paths:
engines/mohawk/sound.cpp
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index c7e36cb6eb1..a1fa6d44ebc 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -35,6 +35,65 @@
namespace Mohawk {
+/**
+ * Applies a heuristic to detect and address discontinuity
+ * at the end of 8-bit unsigned PCM samples, which were present in the
+ * original game assets. The function modifies the DataChunk and dataSize
+ * directly if a fix is applied.
+ *
+ * @param dataChunk The DataChunk containing sample metadata.
+ * @param dataSize The total size of the data.
+ * @param stream The stream to look for samples.
+ */
+void scanAndFixAudioPops(DataChunk &dataChunk, uint32 &dataSize, Common::SeekableReadStream *stream) {
+ const int PCM8_U_SILENCE = 0x80;
+ const int SQUELCH = 32; // Threshold of discontinuity before removing. Lower values = increased sensitivity.
+ bool is_safe = false;
+
+ // Peek at the last 4 samples without permanently moving the stream pointer.
+ uint32 current_pos = stream->pos();
+ stream->seek(current_pos + dataSize - 4, SEEK_SET);
+ byte s[4];
+ stream->read(s, 4);
+ stream->seek(current_pos, SEEK_SET); // Return to original position
+
+ // Path 1: Check for sustained quietness. If all samples are very close to silence,
+ // any minor fluctuation is inaudible and the sound is considered safe.
+ bool is_stable_and_quiet = true;
+ for (int i = 0; i < 4; i++) {
+ if (abs(s[i] - PCM8_U_SILENCE) > SQUELCH) {
+ is_stable_and_quiet = false;
+ break;
+ }
+ }
+ if (is_stable_and_quiet) {
+ is_safe = true;
+ }
+
+ // Path 2: If not stable/quiet, check for a consistent fade-out trend.
+ if (!is_safe) {
+ int dist_last = abs(s[3] - PCM8_U_SILENCE);
+ int dist_prev = abs(s[2] - PCM8_U_SILENCE);
+ int dist_ante = abs(s[1] - PCM8_U_SILENCE);
+
+ if (dist_last < dist_prev && dist_prev < dist_ante) {
+ is_safe = true;
+ }
+ }
+
+ // If the ending is neither stable nor fading, apply the fix.
+ if (!is_safe) {
+ debug(0, "MOHAWK: Pop/click detected at sample %u. Final samples: %02x %02x %02x %02x. Truncating one sample.",
+ dataChunk.sampleCount, s[0], s[1], s[2], s[3]);
+
+ dataChunk.sampleCount--;
+ dataSize--; // Also decrement the total data size to be read.
+ if (dataChunk.loopCount == 0xFFFF && dataChunk.loopEnd > dataChunk.sampleCount) {
+ dataChunk.loopEnd = dataChunk.sampleCount;
+ }
+ }
+}
+
Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
uint32 tag = 0;
ADPCMStatus adpcmStatus;
@@ -137,56 +196,10 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
dataChunk.loopStart = stream->readUint32BE();
dataChunk.loopEnd = stream->readUint32BE();
- // This fix applies a balanced heuristic to detect and prevent audible pops/clicks
- // at the end of 8-bit unsigned PCM samples, which were present in the original game assets.
- if (dataChunk.encoding == kCodecRaw && dataChunk.bitsPerSample == 8 && dataChunk.sampleCount >= 4) {
- const int PCM8_U_SILENCE = 0x80;
- const int SQUELCH = 32; // Threshold of discontinuity before removing. Lower values = increased sensitivity.
- bool is_safe = false;
-
- // Peek at the last 4 samples without permanently moving the stream pointer.
- uint32 current_pos = stream->pos();
- stream->seek(current_pos + dataSize - 4, SEEK_SET);
- byte s[4];
- stream->read(s, 4);
- stream->seek(current_pos, SEEK_SET); // Return to original position
-
- // Path 1: Check for sustained quietness. If all samples are very close to silence,
- // any minor fluctuation is inaudible and the sound is considered safe.
- bool is_stable_and_quiet = true;
- for (int i = 0; i < 4; i++) {
- if (abs(s[i] - PCM8_U_SILENCE) > SQUELCH) {
- is_stable_and_quiet = false;
- break;
- }
- }
- if (is_stable_and_quiet) {
- is_safe = true;
- }
-
- // Path 2: If not stable/quiet, check for a consistent fade-out trend.
- if (!is_safe) {
- int dist_last = abs(s[3] - PCM8_U_SILENCE);
- int dist_prev = abs(s[2] - PCM8_U_SILENCE);
- int dist_ante = abs(s[1] - PCM8_U_SILENCE);
-
- if (dist_last < dist_prev && dist_prev < dist_ante) {
- is_safe = true;
- }
- }
-
- // If the ending is neither stable nor fading, apply the fix.
- if (!is_safe) {
- debug(0, "MOHAWK: Pop/click detected at sample %u. Final samples: %02x %02x %02x %02x. Truncating one sample.",
- dataChunk.sampleCount, s[0], s[1], s[2], s[3]);
-
- dataChunk.sampleCount--;
- dataSize--; // Also decrement the total data size to be read.
- if (dataChunk.loopCount == 0xFFFF && dataChunk.loopEnd > dataChunk.sampleCount) {
- dataChunk.loopEnd = dataChunk.sampleCount;
- }
- }
- }
+ // For unsigned 8-bit PCM, check for and fix a potential pop/click at the end of the sample.
+ if (dataChunk.encoding == kCodecRaw && dataChunk.bitsPerSample == 8 && dataChunk.sampleCount >= 4) {
+ scanAndFixAudioPops(dataChunk, dataSize, stream);
+ }
// NOTE: We currently ignore all of the loop parameters here. Myst uses the
// loopCount variable but the loopStart and loopEnd are always 0 and the size of
Commit: d5077a13b3480fc730e4f660b8e85cd882e842fa
https://github.com/scummvm/scummvm/commit/d5077a13b3480fc730e4f660b8e85cd882e842fa
Author: Alstruit (34786806+Alstruit at users.noreply.github.com)
Date: 2025-08-18T12:40:18+02:00
Commit Message:
MOHAWK: Add option to toggle discontinuity check.
Applies to non Myst/Riven games.
- Myst does not have audio discontinuity.
- Riven does not use 8 bit unsigned PCM.
Changed paths:
engines/mohawk/dialogs.cpp
engines/mohawk/dialogs.h
engines/mohawk/metaengine.cpp
engines/mohawk/sound.cpp
diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp
index 00fd90dd3be..e9a12327cec 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -449,4 +449,33 @@ bool RivenOptionsWidget::save() {
#endif
+MohawkDefaultOptionsWidget::MohawkDefaultOptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain) :
+ OptionsContainerWidget(boss, name, "MohawkEngineOptionsDialog", domain) {
+
+ _audioPopFixCheckbox = new GUI::CheckboxWidget(widgetsBoss(), "MohawkEngineOptionsDialog.AudioDiscontinuityFix",
+ _("Fix audio pops/clicks"),
+ _("Reduces audible pops at the end of some sound effects (Non Myst/Riven only)."));
+}
+
+MohawkDefaultOptionsWidget::~MohawkDefaultOptionsWidget() {
+}
+
+void MohawkDefaultOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const {
+ layouts.addDialog(layoutName, overlayedLayout)
+ .addLayout(GUI::ThemeLayout::kLayoutVertical)
+ .addPadding(0, 0, 0, 0)
+ .addWidget("AudioDiscontinuityFix", "Checkbox")
+ .closeLayout()
+ .closeDialog();
+}
+
+void MohawkDefaultOptionsWidget::load() {
+ _audioPopFixCheckbox->setState(ConfMan.getBool("fix_audio_pops", _domain));
+}
+
+bool MohawkDefaultOptionsWidget::save() {
+ ConfMan.setBool("fix_audio_pops", _audioPopFixCheckbox->getState(), _domain);
+ return true;
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h
index 8452788af43..e846bf0a85b 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -143,6 +143,22 @@ private:
#endif
+class MohawkDefaultOptionsWidget : public GUI::OptionsContainerWidget {
+public:
+ MohawkDefaultOptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain);
+ ~MohawkDefaultOptionsWidget() override;
+
+ // OptionsContainerWidget API
+ void load() override;
+ bool save() override;
+
+private:
+ // OptionsContainerWidget API
+ void defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const override;
+
+ GUI::CheckboxWidget *_audioPopFixCheckbox;
+};
+
} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/metaengine.cpp b/engines/mohawk/metaengine.cpp
index 85752ece985..b9f9ce30c55 100644
--- a/engines/mohawk/metaengine.cpp
+++ b/engines/mohawk/metaengine.cpp
@@ -334,6 +334,14 @@ void MohawkMetaEngine::registerDefaultSettings(const Common::String &target) con
return Mohawk::MohawkMetaEngine_Riven::registerDefaultSettings();
}
+ // Rest of the Mohawk games.
+ ConfMan.registerDefault("fix_audio_pops", true);
+
+ if (!ConfMan.hasKey("fix_audio_pops", target)) {
+ ConfMan.setBool("fix_audio_pops", true, target);
+ ConfMan.flushToDisk();
+ }
+
return MetaEngine::registerDefaultSettings(target);
}
@@ -351,7 +359,7 @@ GUI::OptionsContainerWidget *MohawkMetaEngine::buildEngineOptionsWidget(GUI::Gui
}
#endif
- return MetaEngine::buildEngineOptionsWidget(boss, name, target);
+ return new Mohawk::MohawkDefaultOptionsWidget(boss, name, target);
}
#if PLUGIN_ENABLED_DYNAMIC(MOHAWK)
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index a1fa6d44ebc..8c104e0e17b 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -20,6 +20,7 @@
*/
#include "common/debug.h"
+#include "common/config-manager.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
@@ -198,7 +199,12 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
// For unsigned 8-bit PCM, check for and fix a potential pop/click at the end of the sample.
if (dataChunk.encoding == kCodecRaw && dataChunk.bitsPerSample == 8 && dataChunk.sampleCount >= 4) {
- scanAndFixAudioPops(dataChunk, dataSize, stream);
+ MohawkEngine *mohawkEngine = static_cast<MohawkEngine *>(g_engine);
+ const char *gameId = mohawkEngine->getGameId();
+ // Myst does not have pops and Riven does not have unsigned 8-bit PCM and so is ignored.
+ if (strcmp(gameId, "myst") != 0 && strcmp(gameId, "riven") != 0 && ConfMan.getBool("fix_audio_pops")) {
+ scanAndFixAudioPops(dataChunk, dataSize, stream);
+ }
}
// NOTE: We currently ignore all of the loop parameters here. Myst uses the
More information about the Scummvm-git-logs
mailing list