[Scummvm-git-logs] scummvm master -> aa209212aa9e59350ec43b2180d98b897d9e7e1d
bluegr
noreply at scummvm.org
Mon Sep 28 09:21:59 UTC 2026
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
80009088ac MOHAWK: Zoombini - Add loop support on tSND
2eadd9b5db MOHAWK: Wrap makeMohawkWaveStream signature
e6ed831fa6 MOHAWK: Zoombini - Clarify tSND loop comments
aa209212aa MOHAWK: Zoombini - Infinite loop support on tSND (2)
Commit: 80009088ac2e194974050a359b44bed45a31ec18
https://github.com/scummvm/scummvm/commit/80009088ac2e194974050a359b44bed45a31ec18
Author: Hajin Jang (jb6804 at naver.com)
Date: 2026-09-28T12:21:52+03:00
Commit Message:
MOHAWK: Zoombini - Add loop support on tSND
Assisted-by: Codex:gpt-5.6
Changed paths:
engines/mohawk/sound.cpp
engines/mohawk/sound.h
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index f87c3612b57..acf1e25fc89 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -109,13 +109,30 @@ void scanAndFixAudioPops(DataChunk &dataChunk, uint32 &dataSize, Common::Seekabl
}
}
-Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
+/**
+ * Decode an MHWK/WAVE resource and optionally export a supported loop range.
+ *
+ * Loop metadata stays separate from the returned decoder stream so existing
+ * callers retain the public rewindable-stream contract.
+ * Zoombini playback always requests @p loopInfo and applies the exported
+ * infinite loop.
+ *
+ * @param stream The resource stream, which is consumed and deleted.
+ * @param cueList Optional destination for parsed Cue# entries.
+ * @param loopInfo Optional destination for a validated embedded-loop range.
+ * @return The decoded seekable stream, or nullptr when decoding fails.
+ */
+Audio::SeekableAudioStream *makeMohawkWaveStream(
+ Common::SeekableReadStream *stream, CueList *cueList,
+ MohawkWaveLoopInfo *loopInfo) {
uint32 tag = 0;
ADPCMStatus adpcmStatus;
DataChunk dataChunk;
uint32 dataSize = 0;
memset(&dataChunk, 0, sizeof(DataChunk));
+ if (loopInfo)
+ *loopInfo = MohawkWaveLoopInfo();
if (stream->readUint32BE() != ID_MHWK) // MHWK tag again
error ("Could not find tag 'MHWK'");
@@ -199,8 +216,10 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
break;
case ID_DATA:
debug(2, "Found Tag DATA");
- // We subtract 20 from the actual chunk size, which is the total size
- // of the chunk's header
+ // The Data payload begins with a 20-byte big-endian format header.
+ // The declared chunk size includes this header.
+ // loopStart is inclusive and loopEnd is exclusive.
+ // Both loop positions use source sample frames rather than byte offsets.
dataSize = stream->readUint32BE() - 20;
dataChunk.sampleRate = stream->readUint16BE();
dataChunk.sampleCount = stream->readUint32BE();
@@ -211,21 +230,14 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
dataChunk.loopStart = stream->readUint32BE();
dataChunk.loopEnd = stream->readUint32BE();
- // 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) {
- 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);
+ // 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) {
+ 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
- // 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
- // files and therefore does not contain any of this metadata and we have to specify
- // whether or not to loop elsewhere.
dataChunk.audioData = stream->readStream(dataSize);
break;
@@ -251,6 +263,21 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
else
flags |= Audio::FLAG_UNSIGNED;
+ // Publish only the verified raw 8-bit infinite-loop form.
+ // Available Zoombini looped SND resources use this form.
+ // Finite loops are not published because
+ // @ref Audio::SubLoopingAudioStream ends at the exclusive loop end
+ // after its final iteration instead of continuing through the tail.
+ // Validate after the optional pop fix so the exclusive loop end cannot
+ // exceed a truncated sample payload.
+ if (loopInfo && dataChunk.bitsPerSample == 8 &&
+ dataChunk.loopCount == 0xFFFF &&
+ dataChunk.loopStart < dataChunk.loopEnd &&
+ dataChunk.loopEnd <= dataChunk.sampleCount) {
+ loopInfo->start = dataChunk.loopStart;
+ loopInfo->end = dataChunk.loopEnd;
+ }
+
return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
} else if (dataChunk.encoding == kCodecADPCM) {
uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
@@ -268,7 +295,7 @@ Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *s
return nullptr;
}
-Sound::Sound(MohawkEngine* vm) :
+Sound::Sound(MohawkEngine *vm) :
_vm(vm) {
}
@@ -276,12 +303,12 @@ Sound::~Sound() {
stopSound();
}
-Audio::RewindableAudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
- Audio::RewindableAudioStream *audStream = nullptr;
+Audio::SeekableAudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList, MohawkWaveLoopInfo *loopInfo) {
+ Audio::SeekableAudioStream *audStream = nullptr;
switch (_vm->getGameType()) {
case GType_ZOOMBINI:
- audStream = makeMohawkWaveStream(_vm->getResource(ID_SND, id));
+ audStream = makeMohawkWaveStream(_vm->getResource(ID_SND, id), cueList, loopInfo);
break;
case GType_LIVINGBOOKSV1:
audStream = makeLivingBooksWaveStream_v1(_vm->getResource(ID_WAV, id));
@@ -302,18 +329,30 @@ Audio::RewindableAudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList
Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop, CueList *cueList) {
debug (0, "Playing sound %d", id);
- Audio::RewindableAudioStream *rewindStream = makeAudioStream(id, cueList);
+ MohawkWaveLoopInfo loopInfo;
+ Audio::SeekableAudioStream *seekableStream = makeAudioStream(id, cueList, &loopInfo);
- if (rewindStream) {
+ if (seekableStream) {
SndHandle *handle = getHandle();
handle->type = kUsedHandle;
handle->id = id;
- handle->samplesPerSecond = rewindStream->getRate();
-
- // Set the stream to loop here if it's requested
- Audio::AudioStream *audStream = rewindStream;
- if (loop)
- audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
+ handle->samplesPerSecond = seekableStream->getRate();
+
+ // Logical Journey of the Zoombinis make use of loop.
+ // Playback starts with the resource prefix from frame zero.
+ // Reaching the exported exclusive end then seeks to the inclusive start.
+ // @ref Audio::SubLoopingAudioStream uses zero iterations to mean an infinite loop.
+ // It takes ownership of the decoded seekable stream. The mixer owns the wrapper.
+ // The ordinary whole-resource loop policy remains the fallback
+ // only when the resource has no supported embedded loop.
+ Audio::AudioStream *audStream = seekableStream;
+ if (loopInfo.isValid()) {
+ audStream = new Audio::SubLoopingAudioStream(seekableStream, 0,
+ Audio::Timestamp(0, loopInfo.start, seekableStream->getRate()),
+ Audio::Timestamp(0, loopInfo.end, seekableStream->getRate()));
+ } else if (loop) { // Set the stream to loop here if it's requested
+ audStream = Audio::makeLoopingAudioStream(seekableStream, 0);
+ }
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle->handle, audStream, -1, volume);
return &handle->handle;
@@ -322,7 +361,7 @@ Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop, CueList
return nullptr;
}
-Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
+Audio::SeekableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
uint16 header = stream->readUint16BE();
uint16 rate = 0;
uint32 size = 0;
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index f5553c5b7c9..51bebc9d0c3 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -33,7 +33,7 @@ class MidiDriver;
class MidiParser;
namespace Audio {
-class RewindableAudioStream;
+class SeekableAudioStream;
}
namespace Mohawk {
@@ -45,35 +45,83 @@ enum SndHandleType {
kUsedHandle
};
+/**
+ * Tracks one mixer playback instance created by @ref Mohawk::Sound.
+ *
+ * The sound manager reuses an entry after its mixer handle becomes inactive.
+ * Resource identity and sample rate are retained separately because the mixer
+ * handle does not expose the Mohawk SND ID or a source-frame position.
+ */
struct SndHandle {
+ /** Mixer handle used to stop the instance and query its playback state. */
Audio::SoundHandle handle;
+ /** Allocation state of this entry in @ref Mohawk::Sound::_handles. */
SndHandleType type;
+ /** Source sample rate used to convert elapsed milliseconds to sample frames. */
uint samplesPerSecond;
+ /** Mohawk SND resource ID associated with the active mixer instance. */
uint16 id;
};
-struct ADPCMStatus { // Holds ADPCM status data, but is irrelevant for us.
+/**
+ * Parsed contents of an MHWK/WAVE ADPC seek-state chunk.
+ *
+ * Each item captures enough per-channel decoder state to resume ADPCM decoding
+ * at a particular source sample frame. The current decoder parses and validates
+ * these records but does not yet use them for seeking.
+ */
+struct ADPCMStatus {
+ /** Serialized ADPC chunk payload size in bytes. */
uint32 size;
+ /** Number of seek-state records stored in @ref Mohawk::ADPCMStatus::statusItems. */
uint16 itemCount;
+ /** Number of channel states serialized in each seek-state record. */
uint16 channels;
+ /** Decoder state associated with one source sample-frame position. */
struct StatusItem {
+ /** Source sample frame at which this decoder state becomes valid. */
uint32 sampleFrame;
+ /** Predictor and step-table state needed to resume one ADPCM channel. */
struct {
+ /** Most recently decoded sample, used as the ADPCM predictor. */
int16 last;
+ /** Index into the ADPCM step-size table. */
uint16 stepIndex;
+ /**
+ * Per-channel decoder state.
+ *
+ * Only the first @ref Mohawk::ADPCMStatus::channels entries are serialized.
+ */
} channelStatus[MAX_CHANNELS];
- } *statusItems;
+ } *statusItems; /**< Dynamically allocated array containing
+ * @ref Mohawk::ADPCMStatus::itemCount records.
+ * The MHWK decoder owns this array while parsing the ADPC
+ * chunk and releases it immediately because ADPCM seeking
+ * is not currently implemented.
+ */
};
+/** One named synchronization point parsed from an MHWK/WAVE Cue# chunk. */
struct CueListPoint {
+ /** Source sample frame at which the cue occurs. */
uint32 sampleFrame;
+ /** Serialized cue label used by consumers to identify the synchronization point. */
Common::String name;
};
+/**
+ * Parsed synchronization-point list from an MHWK/WAVE Cue# chunk.
+ *
+ * Callers may use these points to synchronize animation or other game state
+ * with sound playback.
+ */
struct CueList {
+ /** Serialized Cue# chunk payload size in bytes. */
uint32 size;
+ /** Number of cue records declared by the chunk. */
uint16 pointCount;
+ /** Cue records in their serialized order. */
Common::Array<CueListPoint> points;
};
@@ -83,24 +131,92 @@ enum {
kCodecMPEG2 = 2
};
+/**
+ * Parsed state for the 20-byte MHWK/WAVE Data header and its payload.
+ *
+ * The loop positions are source sample-frame positions, not byte offsets.
+ * @ref Mohawk::DataChunk::loopStart is inclusive.
+ * @ref Mohawk::DataChunk::loopEnd is exclusive and must not exceed
+ * @ref Mohawk::DataChunk::sampleCount.
+ *
+ * A loop count of zero disables the embedded loop.
+ * A loop count of 0xFFFF requests an infinite loop.
+ * Another nonzero value requests that many additional passes through the
+ * loop range.
+ *
+ * Zoombini playback applies every supported embedded infinite loop automatically.
+ * Finite loop counts remain parsed but are not yet applied by the ScummVM stream wrapper.
+ */
struct DataChunk {
+ /** Number of source sample frames played per second. */
uint16 sampleRate;
+ /** Total number of source sample frames declared by the Data header. */
uint32 sampleCount;
+ /** Number of encoded bits for each sample in one channel. */
byte bitsPerSample;
+ /** Number of interleaved audio channels in each source sample frame. */
byte channels;
+ /**
+ * Payload codec, using @ref Mohawk::kCodecRaw,
+ * @ref Mohawk::kCodecADPCM, or @ref Mohawk::kCodecMPEG2.
+ */
uint16 encoding;
- uint16 loopCount; // 0 == no looping, 0xFFFF == infinite loop
+ /**
+ * Number of requested repeats for the embedded loop range.
+ *
+ * 0x0000 disables looping, 0xFFFF is an infinite loop.
+ */
+ uint16 loopCount;
+ /** Inclusive source sample frame at which an embedded loop begins. */
uint32 loopStart;
+ /** Exclusive source sample frame at which playback returns to @ref DataChunk::loopStart. */
uint32 loopEnd;
+ /**
+ * Stream containing only the encoded sample payload after the Data header.
+ *
+ * Ownership transfers to the codec-specific audio stream factory.
+ */
Common::SeekableReadStream *audioData;
};
-Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = nullptr);
+/**
+ * Embedded-loop range exported by the MHWK decoder.
+ *
+ * Both positions use source sample frames.
+ * @ref Mohawk::MohawkWaveLoopInfo::start is inclusive.
+ * @ref Mohawk::MohawkWaveLoopInfo::end is exclusive.
+ * An empty range means that the resource has no supported embedded loop.
+ */
+struct MohawkWaveLoopInfo {
+ uint32 start = 0;
+ uint32 end = 0;
+
+ bool isValid() const { return start < end; }
+};
+
+/**
+ * Decode an MHWK/WAVE resource as a seekable stream.
+ *
+ * This low-level decoder returns the linear sample stream and can optionally
+ * export a validated embedded-loop range. Zoombini's @ref Mohawk::Sound
+ * playback layer requests that range and wraps the decoded stream
+ * automatically.
+ *
+ * @param stream The MHWK resource stream, which is consumed and deleted.
+ * @param cueList Optional destination for parsed Cue# entries.
+ * @param loopInfo Optional destination for a validated embedded-loop range.
+ * @return The decoded stream, or nullptr when the resource cannot be decoded.
+ */
+Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream,
+ CueList *cueList = nullptr, MohawkWaveLoopInfo *loopInfo = nullptr);
class MohawkEngine;
class Sound {
public:
+ /**
+ * Create a common Mohawk sound manager.
+ */
explicit Sound(MohawkEngine *vm);
~Sound();
@@ -115,11 +231,12 @@ public:
private:
MohawkEngine *_vm;
- static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
+ static Audio::SeekableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
Common::Array<SndHandle> _handles;
SndHandle *getHandle();
- Audio::RewindableAudioStream *makeAudioStream(uint16 id, CueList *cueList = nullptr);
+ Audio::SeekableAudioStream *makeAudioStream(uint16 id, CueList *cueList = nullptr,
+ MohawkWaveLoopInfo *loopInfo = nullptr);
};
} // End of namespace Mohawk
Commit: 2eadd9b5db49b1d9e46e419f987e7b70be1df409
https://github.com/scummvm/scummvm/commit/2eadd9b5db49b1d9e46e419f987e7b70be1df409
Author: Hajin Jang (jb6804 at naver.com)
Date: 2026-09-28T12:21:52+03:00
Commit Message:
MOHAWK: Wrap makeMohawkWaveStream signature
Assisted-by: Codex:gpt-5.6
Changed paths:
engines/mohawk/sound.cpp
engines/mohawk/sound.h
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index acf1e25fc89..101a27aff9d 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -122,9 +122,7 @@ void scanAndFixAudioPops(DataChunk &dataChunk, uint32 &dataSize, Common::Seekabl
* @param loopInfo Optional destination for a validated embedded-loop range.
* @return The decoded seekable stream, or nullptr when decoding fails.
*/
-Audio::SeekableAudioStream *makeMohawkWaveStream(
- Common::SeekableReadStream *stream, CueList *cueList,
- MohawkWaveLoopInfo *loopInfo) {
+Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList, MohawkWaveLoopInfo *loopInfo) {
uint32 tag = 0;
ADPCMStatus adpcmStatus;
DataChunk dataChunk;
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 51bebc9d0c3..2c78dd48b4d 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -207,8 +207,7 @@ struct MohawkWaveLoopInfo {
* @param loopInfo Optional destination for a validated embedded-loop range.
* @return The decoded stream, or nullptr when the resource cannot be decoded.
*/
-Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream,
- CueList *cueList = nullptr, MohawkWaveLoopInfo *loopInfo = nullptr);
+Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = nullptr, MohawkWaveLoopInfo *loopInfo = nullptr);
class MohawkEngine;
Commit: e6ed831fa63ada4ee6c6a9ed01fe5d238b331b65
https://github.com/scummvm/scummvm/commit/e6ed831fa63ada4ee6c6a9ed01fe5d238b331b65
Author: Hajin Jang (jb6804 at naver.com)
Date: 2026-09-28T12:21:52+03:00
Commit Message:
MOHAWK: Zoombini - Clarify tSND loop comments
Changed paths:
engines/mohawk/sound.cpp
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 101a27aff9d..7ee6accc7e3 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -237,6 +237,10 @@ Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *str
scanAndFixAudioPops(dataChunk, dataSize, stream);
}
+ // 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 files and therefore does not contain
+ // any of this metadata and we have to specify whether or not to loop elsewhere.
+
dataChunk.audioData = stream->readStream(dataSize);
break;
default:
@@ -261,17 +265,14 @@ Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *str
else
flags |= Audio::FLAG_UNSIGNED;
- // Publish only the verified raw 8-bit infinite-loop form.
- // Available Zoombini looped SND resources use this form.
- // Finite loops are not published because
- // @ref Audio::SubLoopingAudioStream ends at the exclusive loop end
- // after its final iteration instead of continuing through the tail.
- // Validate after the optional pop fix so the exclusive loop end cannot
- // exceed a truncated sample payload.
- if (loopInfo && dataChunk.bitsPerSample == 8 &&
- dataChunk.loopCount == 0xFFFF &&
- dataChunk.loopStart < dataChunk.loopEnd &&
- dataChunk.loopEnd <= dataChunk.sampleCount) {
+ // Export only the raw 8-bit infinite loops used by Zoombini. Filter out finite loops.
+ // @ref Mohawk::Sound::playSound() passes the range to @ref Audio::SubLoopingAudioStream.
+ // - Mohawk infnite loop: head -> loop chunk (repeat until stopped by game logic)
+ // - Mohawk finite loop: head -> loop chunk (N times) -> tail -> EOF
+ // - @ref Audio::SubLoopingAudioStream finite: head -> loop chunk (N times) -> EOF
+ // @ref Audio::SubLoopingAudioStream does not support finite loop semantics, so filter them as a safeguard.
+ // Validate against sampleCount after the optional pop truncation.
+ if (loopInfo && dataChunk.bitsPerSample == 8 && dataChunk.loopCount == 0xFFFF && dataChunk.loopStart < dataChunk.loopEnd && dataChunk.loopEnd <= dataChunk.sampleCount) {
loopInfo->start = dataChunk.loopStart;
loopInfo->end = dataChunk.loopEnd;
}
Commit: aa209212aa9e59350ec43b2180d98b897d9e7e1d
https://github.com/scummvm/scummvm/commit/aa209212aa9e59350ec43b2180d98b897d9e7e1d
Author: Hajin Jang (jb6804 at naver.com)
Date: 2026-09-28T12:21:52+03:00
Commit Message:
MOHAWK: Zoombini - Infinite loop support on tSND (2)
- Do not filter out mohawk loop with bitness check.
- The only blocker behind the exporting loop data is a lack of finite loop support in Audio streams; not a bitness limitation.
Changed paths:
engines/mohawk/sound.cpp
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 7ee6accc7e3..9ddd66f20f5 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -272,7 +272,7 @@ Audio::SeekableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *str
// - @ref Audio::SubLoopingAudioStream finite: head -> loop chunk (N times) -> EOF
// @ref Audio::SubLoopingAudioStream does not support finite loop semantics, so filter them as a safeguard.
// Validate against sampleCount after the optional pop truncation.
- if (loopInfo && dataChunk.bitsPerSample == 8 && dataChunk.loopCount == 0xFFFF && dataChunk.loopStart < dataChunk.loopEnd && dataChunk.loopEnd <= dataChunk.sampleCount) {
+ if (loopInfo && dataChunk.loopCount == 0xFFFF && dataChunk.loopStart < dataChunk.loopEnd && dataChunk.loopEnd <= dataChunk.sampleCount) {
loopInfo->start = dataChunk.loopStart;
loopInfo->end = dataChunk.loopEnd;
}
More information about the Scummvm-git-logs
mailing list