From 33b991ee9d987acf013606341a60c8e3ff95ca77 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Tue, 22 Jun 2010 19:21:05 +0000 Subject: Groovie: Add support for the compressed MIDI files of T7G Mac. svn-id: r50163 --- engines/groovie/music.cpp | 63 ++++++++++++++++++++++++++++++++++++++++------- engines/groovie/music.h | 3 +++ 2 files changed, 57 insertions(+), 9 deletions(-) (limited to 'engines') diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index 7166432e02..7e8f21bbbc 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -703,20 +703,65 @@ bool MusicPlayerMac::load(uint32 fileref, bool loop) { Common::SeekableReadStream *file = _vm->_macResFork->getResource(MKID_BE('cmid'), fileref & 0x3FF); if (file) { - // TODO: A form of LZSS, not supported by the current Groovie decoder. - // The offset/length uint16 is BE, but not sure the amount of length bits - // nor whether the offset is absolute/relative. - warning("TODO: Mac Compressed MIDI: cmid 0x%04x", fileref & 0x3FF); + // Found the resource, decompress it + Common::SeekableReadStream *tmp = decompressMidi(file); delete file; + file = tmp; + } else { + // Otherwise, it's uncompressed + file = _vm->_macResFork->getResource(MKID_BE('Midi'), fileref & 0x3FF); + if (!file) + error("Groovie::Music: Couldn't find resource 0x%04X", fileref); return false; } - // Otherwise, it's uncompressed - file = _vm->_macResFork->getResource(MKID_BE('Midi'), fileref & 0x3FF); - if (!file) - error("Groovie::Music: Couldn't find resource 0x%04X", fileref); - return loadParser(file, loop); } +Common::SeekableReadStream *MusicPlayerMac::decompressMidi(Common::SeekableReadStream *stream) { + // Initialize an output buffer of the given size + uint32 size = stream->readUint32BE(); + byte *output = (byte *)malloc(size); + + byte *current = output; + uint32 decompBytes = 0; + while ((decompBytes < size) && !stream->eos()) { + // 8 flags + byte flags = stream->readByte(); + + for (byte i = 0; (i < 8) && !stream->eos(); i++) { + if (flags & 1) { + // 1: Next byte is a literal + *(current++) = stream->readByte(); + if (stream->eos()) + continue; + decompBytes++; + } else { + // 0: It's a reference to part of the history + uint16 args = stream->readUint16BE(); + if (stream->eos()) + continue; + + // Length = 4bit unsigned (3 minimal) + uint8 length = (args >> 12) + 3; + + // Offset = 12bit signed (all values are negative) + int16 offset = (args & 0xFFF) | 0xF000; + + // Copy from the past decompressed bytes + decompBytes += length; + while (length > 0) { + *(current) = *(current + offset); + current++; + length--; + } + } + flags = flags >> 1; + } + } + + // Return the output buffer wrapped in a MemoryReadStream + return new Common::MemoryReadStream(output, size, DisposeAfterUse::YES); +} + } // End of Groovie namespace diff --git a/engines/groovie/music.h b/engines/groovie/music.h index 2feef9cbf7..5b5f5bd346 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -161,6 +161,9 @@ public: protected: bool load(uint32 fileref, bool loop); + +private: + Common::SeekableReadStream *decompressMidi(Common::SeekableReadStream *stream); }; } // End of Groovie namespace -- cgit v1.2.3