From 9780c8e56e01308b1b4c5e97079c0320bb308845 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 9 Sep 2012 12:32:34 -0400 Subject: GROOVIE: Add StuffIt archive code for 11H Mac --- engines/groovie/module.mk | 1 + engines/groovie/stuffit.cpp | 537 ++++++++++++++++++++++++++++++++++++++++++++ engines/groovie/stuffit.h | 43 ++++ 3 files changed, 581 insertions(+) create mode 100644 engines/groovie/stuffit.cpp create mode 100644 engines/groovie/stuffit.h (limited to 'engines/groovie') diff --git a/engines/groovie/module.mk b/engines/groovie/module.mk index 1e89ff66f5..b47eed912b 100644 --- a/engines/groovie/module.mk +++ b/engines/groovie/module.mk @@ -15,6 +15,7 @@ MODULE_OBJS := \ roq.o \ saveload.o \ script.o \ + stuffit.o \ vdx.o # This module can be built as a plugin diff --git a/engines/groovie/stuffit.cpp b/engines/groovie/stuffit.cpp new file mode 100644 index 0000000000..03fa300e49 --- /dev/null +++ b/engines/groovie/stuffit.cpp @@ -0,0 +1,537 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Based on the StuffIt code in ResidualVM +// StuffIt parsing based on http://code.google.com/p/theunarchiver/wiki/StuffItFormat +// Compression 14 based on libxad (http://sourceforge.net/projects/libxad/) + +#include "groovie/stuffit.h" + +#include "common/archive.h" +#include "common/bitstream.h" +#include "common/debug.h" +#include "common/hash-str.h" +#include "common/hashmap.h" +#include "common/memstream.h" +#include "common/substream.h" + +namespace Groovie { + +struct SIT14Data; + +class StuffItArchive : public Common::Archive { +public: + StuffItArchive(); + ~StuffItArchive(); + + bool open(const Common::String &filename); + void close(); + bool isOpen() const { return _stream != 0; } + + // Common::Archive API implementation + bool hasFile(const Common::String &name) const; + int listMembers(Common::ArchiveMemberList &list) const; + const Common::ArchiveMemberPtr getMember(const Common::String &name) const; + Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; + +private: + struct FileEntry { + byte compression; + uint32 uncompressedSize; + uint32 compressedSize; + uint32 offset; + }; + + Common::SeekableReadStream *_stream; + + typedef Common::HashMap FileMap; + FileMap _map; + + // Decompression Functions + Common::SeekableReadStream *decompress14(Common::SeekableReadStream *src, uint32 uncompressedSize) const; + + // Decompression Helpers + void update14(uint16 first, uint16 last, byte *code, uint16 *freq) const; + void readTree14(Common::BitStream *bits, SIT14Data *dat, uint16 codesize, uint16 *result) const; +}; + +StuffItArchive::StuffItArchive() : Common::Archive() { + _stream = 0; +} + +StuffItArchive::~StuffItArchive() { + close(); +} + +// Some known values of StuffIt FourCC's +// 11H Mac in particular uses ST46 +static const uint32 s_magicNumbers[] = { + MKTAG('S', 'I', 'T', '!'), MKTAG('S', 'T', '6', '5'), MKTAG('S', 'T', '5', '0'), + MKTAG('S', 'T', '6', '0'), MKTAG('S', 'T', 'i', 'n'), MKTAG('S', 'T', 'i', '2'), + MKTAG('S', 'T', 'i', '3'), MKTAG('S', 'T', 'i', '4'), MKTAG('S', 'T', '4', '6') +}; + +bool StuffItArchive::open(const Common::String &filename) { + close(); + + _stream = SearchMan.createReadStreamForMember(filename); + + if (!_stream) + return false; + + uint32 tag = _stream->readUint32BE(); + + // Check all the possible FourCC's + bool found = false; + for (int i = 0; i < ARRAYSIZE(s_magicNumbers); i++) { + if (tag == s_magicNumbers[i]) { + found = true; + break; + } + } + + // Didn't find one, let's bail out + if (!found) { + close(); + return false; + } + + /* uint16 fileCount = */ _stream->readUint16BE(); + /* uint32 archiveSize = */ _stream->readUint32BE(); + + // Some sort of second magic number + if (_stream->readUint32BE() != MKTAG('r', 'L', 'a', 'u')) { + close(); + return false; + } + + /* byte version = */ _stream->readByte(); // meaning not clear + + _stream->skip(7); // unknown + + while (_stream->pos() < _stream->size() && !_stream->eos()) { + byte resForkCompression = _stream->readByte(); + byte dataForkCompression = _stream->readByte(); + + byte fileNameLength = _stream->readByte(); + Common::String name; + + for (byte i = 0; i < fileNameLength; i++) + name += (char)_stream->readByte(); + + // Skip remaining bytes + _stream->skip(63 - fileNameLength); + + /* uint32 fileType = */ _stream->readUint32BE(); + /* uint32 fileCreator = */ _stream->readUint32BE(); + /* uint16 finderFlags = */ _stream->readUint16BE(); + /* uint32 creationDate = */ _stream->readUint32BE(); + /* uint32 modificationDate = */ _stream->readUint32BE(); + uint32 resForkUncompressedSize = _stream->readUint32BE(); + uint32 dataForkUncompressedSize = _stream->readUint32BE(); + uint32 resForkCompressedSize = _stream->readUint32BE(); + uint32 dataForkCompressedSize = _stream->readUint32BE(); + /* uint16 resForkCRC = */ _stream->readUint16BE(); + /* uint16 dataForkCRC = */ _stream->readUint16BE(); + _stream->skip(6); // unknown + /* uint16 headerCRC = */ _stream->readUint16BE(); + + // Ignore directories for now + if (dataForkCompression == 32 || dataForkCompression == 33) + continue; + + if (dataForkUncompressedSize != 0) { + // We have a data fork + + FileEntry entry; + entry.compression = dataForkCompression; + entry.uncompressedSize = dataForkUncompressedSize; + entry.compressedSize = dataForkCompressedSize; + entry.offset = _stream->pos() + resForkCompressedSize; + _map[name] = entry; + + debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression); + } + + if (resForkUncompressedSize != 0) { + // We have a resource fork + + // Add a .rsrc extension so we know it's the resource fork + name += ".rsrc"; + + FileEntry entry; + entry.compression = resForkCompression; + entry.uncompressedSize = resForkUncompressedSize; + entry.compressedSize = resForkCompressedSize; + entry.offset = _stream->pos(); + _map[name] = entry; + + debug(0, "StuffIt file '%s', Compression = %d", name.c_str(), entry.compression); + } + + // Go to the next entry + _stream->skip(dataForkCompressedSize + resForkCompressedSize); + } + + return true; +} + +void StuffItArchive::close() { + delete _stream; _stream = 0; + _map.clear(); +} + +bool StuffItArchive::hasFile(const Common::String &name) const { + return _map.contains(name); +} + +int StuffItArchive::listMembers(Common::ArchiveMemberList &list) const { + for (FileMap::const_iterator it = _map.begin(); it != _map.end(); it++) + list.push_back(getMember(it->_key)); + + return _map.size(); +} + +const Common::ArchiveMemberPtr StuffItArchive::getMember(const Common::String &name) const { + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *StuffItArchive::createReadStreamForMember(const Common::String &name) const { + if (!_stream || !_map.contains(name)) + return 0; + + const FileEntry &entry = _map[name]; + + if (entry.compression & 0xF0) + error("Unhandled StuffIt encryption"); + + Common::SeekableSubReadStream subStream(_stream, entry.offset, entry.offset + entry.compressedSize); + + // We currently only support type 14 compression + switch (entry.compression) { + case 0: // Uncompressed + return subStream.readStream(subStream.size()); + case 14: // Installer + return decompress14(&subStream, entry.uncompressedSize); + default: + error("Unhandled StuffIt compression %d", entry.compression); + } + + return 0; +} + +void StuffItArchive::update14(uint16 first, uint16 last, byte *code, uint16 *freq) const { + uint16 i, j; + + while (last - first > 1) { + i = first; + j = last; + + do { + while (++i < last && code[first] > code[i]) + ; + + while (--j > first && code[first] < code[j]) + ; + + if (j > i) { + SWAP(code[i], code[j]); + SWAP(freq[i], freq[j]); + } + } while (j > i); + + if (first != j) { + SWAP(code[first], code[j]); + SWAP(freq[first], freq[j]); + + i = j + 1; + + if (last - i <= j - first) { + update14(i, last, code, freq); + last = j; + } else { + update14(first, j, code, freq); + first = i; + } + } else { + ++first; + } + } +} + +struct SIT14Data { + byte code[308]; + byte codecopy[308]; + uint16 freq[308]; + uint32 buff[308]; + + byte var1[52]; + uint16 var2[52]; + uint16 var3[75 * 2]; + + byte var4[76]; + uint32 var5[75]; + byte var6[1024]; + uint16 var7[308 * 2]; + byte var8[0x4000]; + + byte window[0x40000]; +}; + +// Realign to a byte boundary +#define ALIGN_BITS(b) \ + if (b->pos() & 7) \ + b->skip(8 - (b->pos() & 7)) + +void StuffItArchive::readTree14(Common::BitStream *bits, SIT14Data *dat, uint16 codesize, uint16 *result) const { + uint32 i, l, n; + uint32 k = bits->getBit(); + uint32 j = bits->getBits(2) + 2; + uint32 o = bits->getBits(3) + 1; + uint32 size = 1 << j; + uint32 m = size - 1; + k = k ? (m - 1) : 0xFFFFFFFF; + + if (bits->getBits(2) & 1) { // skip 1 bit! + // requirements for this call: dat->buff[32], dat->code[32], dat->freq[32*2] + readTree14(bits, dat, size, dat->freq); + + for (i = 0; i < codesize; ) { + l = 0; + + do { + l = dat->freq[l + bits->getBit()]; + n = size << 1; + } while (n > l); + + l -= n; + + if (k != l) { + if (l == m) { + l = 0; + + do { + l = dat->freq[l + bits->getBit()]; + n = size << 1; + } while (n > l); + + l += 3 - n; + + while (l--) { + dat->code[i] = dat->code[i - 1]; + ++i; + } + } else { + dat->code[i++] = l + o; + } + } else { + dat->code[i++] = 0; + } + } + } else { + for (i = 0; i < codesize; ) { + l = bits->getBits(j); + + if (k != l) { + if (l == m) { + l = bits->getBits(j) + 3; + + while (l--) { + dat->code[i] = dat->code[i - 1]; + ++i; + } + } else { + dat->code[i++] = l+o; + } + } else { + dat->code[i++] = 0; + } + } + } + + for (i = 0; i < codesize; ++i) { + dat->codecopy[i] = dat->code[i]; + dat->freq[i] = i; + } + + update14(0, codesize, dat->codecopy, dat->freq); + + for (i = 0; i < codesize && !dat->codecopy[i]; ++i) + ; // find first nonempty + + for (j = 0; i < codesize; ++i, ++j) { + if (i) + j <<= (dat->codecopy[i] - dat->codecopy[i - 1]); + + k = dat->codecopy[i]; m = 0; + + for (l = j; k--; l >>= 1) + m = (m << 1) | (l & 1); + + dat->buff[dat->freq[i]] = m; + } + + for (i = 0; i < (uint32)codesize * 2; ++i) + result[i] = 0; + + j = 2; + + for (i = 0; i < codesize; ++i) { + l = 0; + m = dat->buff[i]; + + for (k = 0; k < dat->code[i]; ++k) { + l += (m & 1); + + if (dat->code[i] - 1 <= (int32)k) { + result[l] = codesize * 2 + i; + } else { + if (!result[l]) { + result[l] = j; + j += 2; + } + + l = result[l]; + } + + m >>= 1; + } + } + + ALIGN_BITS(bits); +} + +#define OUTPUT_VAL(x) \ + out.writeByte(x); \ + dat->window[j++] = x; \ + j &= 0x3FFFF + +Common::SeekableReadStream *StuffItArchive::decompress14(Common::SeekableReadStream *src, uint32 uncompressedSize) const { + byte *dst = (byte *)malloc(uncompressedSize); + Common::MemoryWriteStream out(dst, uncompressedSize); + + Common::BitStream *bits = new Common::BitStream8LSB(src); + + uint32 i, j, k, l, m, n; + + SIT14Data *dat = new SIT14Data(); + + // initialization + for (i = k = 0; i < 52; ++i) { + dat->var2[i] = k; + k += (1 << (dat->var1[i] = ((i >= 4) ? ((i - 4) >> 2) : 0))); + } + + for (i = 0; i < 4; ++i) + dat->var8[i] = i; + + for (m = 1, l = 4; i < 0x4000; m <<= 1) // i is 4 + for (n = l+4; l < n; ++l) + for (j = 0; j < m; ++j) + dat->var8[i++] = l; + + for (i = 0, k = 1; i < 75; ++i) { + dat->var5[i] = k; + k += (1 << (dat->var4[i] = (i >= 3 ? ((i - 3) >> 2) : 0))); + } + + for (i = 0; i < 4; ++i) + dat->var6[i] = i - 1; + + for (m = 1, l = 3; i < 0x400; m <<= 1) // i is 4 + for (n = l + 4; l < n; ++l) + for (j = 0; j < m; ++j) + dat->var6[i++] = l; + + m = bits->getBits(16); // number of blocks + j = 0; // window position + + while (m-- && !bits->eos()) { + bits->getBits(16); // skip crunched block size + bits->getBits(16); + n = bits->getBits(16); // number of uncrunched bytes + n |= bits->getBits(16) << 16; + readTree14(bits, dat, 308, dat->var7); + readTree14(bits, dat, 75, dat->var3); + + while (n && !bits->eos()) { + for (i = 0; i < 616;) + i = dat->var7[i + bits->getBit()]; + + i -= 616; + + if (i < 0x100) { + OUTPUT_VAL(i); + --n; + } else { + i -= 0x100; + k = dat->var2[i]+4; + i = dat->var1[i]; + + if (i) + k += bits->getBits(i); + + for (i = 0; i < 150;) + i = dat->var3[i + bits->getBit()]; + + i -= 150; + l = dat->var5[i]; + i = dat->var4[i]; + + if (i) + l += bits->getBits(i); + + n -= k; + l = j + 0x40000 - l; + + while (k--) { + l &= 0x3FFFF; + OUTPUT_VAL(dat->window[l]); + l++; + } + } + } + + ALIGN_BITS(bits); + } + + delete dat; + delete bits; + + return new Common::MemoryReadStream(dst, uncompressedSize, DisposeAfterUse::YES); +} + +#undef OUTPUT_VAL +#undef ALIGN_BITS + +Common::Archive *createStuffItArchive(const Common::String &fileName) { + StuffItArchive *archive = new StuffItArchive(); + + if (!archive->open(fileName)) { + delete archive; + return 0; + } + + return archive; +} + +} // End of namespace Groovie diff --git a/engines/groovie/stuffit.h b/engines/groovie/stuffit.h new file mode 100644 index 0000000000..44f593dbea --- /dev/null +++ b/engines/groovie/stuffit.h @@ -0,0 +1,43 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GROOVIE_STUFFIT_H +#define GROOVIE_STUFFIT_H + +namespace Common { +class Archive; +class String; +} + +namespace Groovie { + +/** + * This factory method creates an Archive instance corresponding to the content + * of the StuffIt compressed file. + * + * May return 0 in case of a failure. + */ +Common::Archive *createStuffItArchive(const Common::String &fileName); + +} // End of namespace Groovie + +#endif -- cgit v1.2.3 From 72a1140d572ce46a820cddb6ac85b748cb7a066d Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 9 Sep 2012 12:43:29 -0400 Subject: GROOVIE: Rename MusicPlayerMac to MusicPlayerMac_t7g --- engines/groovie/groovie.cpp | 2 +- engines/groovie/music.cpp | 8 ++++---- engines/groovie/music.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'engines/groovie') diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 726e7cbede..42501afa02 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -163,7 +163,7 @@ Common::Error GroovieEngine::run() { // TODO: The 11th Hour Mac uses QuickTime MIDI files // Right now, since the XMIDI are present and it is still detected as // the DOS version, we don't have to do anything here. - _musicPlayer = new MusicPlayerMac(this); + _musicPlayer = new MusicPlayerMac_t7g(this); break; case Common::kPlatformIOS: _musicPlayer = new MusicPlayerIOS(this); diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index af929d439b..b4afca527f 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -678,9 +678,9 @@ void MusicPlayerXMI::setTimbreMT(byte channel, const Timbre &timbre) { } -// MusicPlayerMac +// MusicPlayerMac_t7g -MusicPlayerMac::MusicPlayerMac(GroovieEngine *vm) : MusicPlayerMidi(vm) { +MusicPlayerMac_t7g::MusicPlayerMac_t7g(GroovieEngine *vm) : MusicPlayerMidi(vm) { // Create the parser _midiParser = MidiParser::createParser_SMF(); @@ -701,7 +701,7 @@ MusicPlayerMac::MusicPlayerMac(GroovieEngine *vm) : MusicPlayerMidi(vm) { assert(_vm->_macResFork); } -bool MusicPlayerMac::load(uint32 fileref, bool loop) { +bool MusicPlayerMac_t7g::load(uint32 fileref, bool loop) { debugC(1, kGroovieDebugMIDI | kGroovieDebugAll, "Groovie::Music: Starting the playback of song: %04X", fileref); // First try for compressed MIDI @@ -722,7 +722,7 @@ bool MusicPlayerMac::load(uint32 fileref, bool loop) { return loadParser(file, loop); } -Common::SeekableReadStream *MusicPlayerMac::decompressMidi(Common::SeekableReadStream *stream) { +Common::SeekableReadStream *MusicPlayerMac_t7g::decompressMidi(Common::SeekableReadStream *stream) { // Initialize an output buffer of the given size uint32 size = stream->readUint32BE(); byte *output = (byte *)malloc(size); diff --git a/engines/groovie/music.h b/engines/groovie/music.h index cc852aa8dc..0342bf16c9 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -150,9 +150,9 @@ private: void setTimbreMT(byte channel, const Timbre &timbre); }; -class MusicPlayerMac : public MusicPlayerMidi { +class MusicPlayerMac_t7g : public MusicPlayerMidi { public: - MusicPlayerMac(GroovieEngine *vm); + MusicPlayerMac_t7g(GroovieEngine *vm); protected: bool load(uint32 fileref, bool loop); -- cgit v1.2.3 From 7d684d1166744cffd04e7e016fdf05de0b984a8e Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 12 Sep 2012 18:02:58 -0400 Subject: GROOVIE: Add a MusicPlayerMac_v2 for 11H Mac --- engines/groovie/groovie.cpp | 9 +++++---- engines/groovie/music.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ engines/groovie/music.h | 8 ++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) (limited to 'engines/groovie') diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 42501afa02..0f05d73599 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -56,6 +56,7 @@ GroovieEngine::GroovieEngine(OSystem *syst, const GroovieGameDescription *gd) : SearchMan.addSubDirectoryMatching(gameDataDir, "groovie"); SearchMan.addSubDirectoryMatching(gameDataDir, "media"); SearchMan.addSubDirectoryMatching(gameDataDir, "system"); + SearchMan.addSubDirectoryMatching(gameDataDir, "MIDI"); _modeSpeed = kGroovieSpeedNormal; if (ConfMan.hasKey("t7g_speed")) { @@ -160,10 +161,10 @@ Common::Error GroovieEngine::run() { // Create the music player switch (getPlatform()) { case Common::kPlatformMacintosh: - // TODO: The 11th Hour Mac uses QuickTime MIDI files - // Right now, since the XMIDI are present and it is still detected as - // the DOS version, we don't have to do anything here. - _musicPlayer = new MusicPlayerMac_t7g(this); + if (_gameDescription->version == kGroovieT7G) + _musicPlayer = new MusicPlayerMac_t7g(this); + else + _musicPlayer = new MusicPlayerMac_v2(this); break; case Common::kPlatformIOS: _musicPlayer = new MusicPlayerIOS(this); diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index b4afca527f..95637fc407 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -768,6 +768,52 @@ Common::SeekableReadStream *MusicPlayerMac_t7g::decompressMidi(Common::SeekableR return new Common::MemoryReadStream(output, size, DisposeAfterUse::YES); } +// MusicPlayerMac_v2 + +MusicPlayerMac_v2::MusicPlayerMac_v2(GroovieEngine *vm) : MusicPlayerMidi(vm) { + // Create the parser + _midiParser = MidiParser::createParser_QT(); + + // Create the driver + MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); + _driver = MidiDriver::createMidi(dev); + assert(_driver); + + _driver->open(); // TODO: Handle return value != 0 (indicating an error) + + // Set the parser's driver + _midiParser->setMidiDriver(this); + + // Set the timer rate + _midiParser->setTimerRate(_driver->getBaseTempo()); +} + +bool MusicPlayerMac_v2::load(uint32 fileref, bool loop) { + debugC(1, kGroovieDebugMIDI | kGroovieDebugAll, "Groovie::Music: Starting the playback of song: %04X", fileref); + + // Find correct filename + ResInfo info; + _vm->_resMan->getResInfo(fileref, info); + uint len = info.filename.size(); + if (len < 4) + return false; // This shouldn't actually occur + + // Remove the extension and add ".mov" + info.filename.deleteLastChar(); + info.filename.deleteLastChar(); + info.filename.deleteLastChar(); + info.filename += "mov"; + + Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(info.filename); + + if (!file) { + warning("Could not find file '%s'", info.filename.c_str()); + return false; + } + + return loadParser(file, loop); +} + MusicPlayerIOS::MusicPlayerIOS(GroovieEngine *vm) : MusicPlayer(vm) { vm->getTimerManager()->installTimerProc(&onTimer, 50 * 1000, this, "groovieMusic"); } diff --git a/engines/groovie/music.h b/engines/groovie/music.h index 0342bf16c9..92e9c8b487 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -161,6 +161,14 @@ private: Common::SeekableReadStream *decompressMidi(Common::SeekableReadStream *stream); }; +class MusicPlayerMac_v2 : public MusicPlayerMidi { +public: + MusicPlayerMac_v2(GroovieEngine *vm); + +protected: + bool load(uint32 fileref, bool loop); +}; + class MusicPlayerIOS : public MusicPlayer { public: MusicPlayerIOS(GroovieEngine *vm); -- cgit v1.2.3 From 1d98435d34a9a1a1b3e751fb9af4b4ebd106b243 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 12 Sep 2012 18:07:00 -0400 Subject: GROOVIE: Add detection for 11H Mac --- engines/groovie/detection.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'engines/groovie') diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index 1a3b313649..abafbf9f62 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -137,6 +137,36 @@ static const GroovieGameDescription gameDescriptions[] = { kGroovieV2, 1 }, + // The 11th Hour Macintosh English + { + { + "11h", "", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 1 + }, + + // The 11th Hour Macintosh English (Installed) + { + { + "11h", "Installed", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 1 + }, + // The 11th Hour DOS Demo English { { @@ -159,6 +189,36 @@ static const GroovieGameDescription gameDescriptions[] = { kGroovieV2, 2 }, + // The Making of The 11th Hour Macintosh English + { + { + "11h", "Making Of", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 2 + }, + + // The Making of The 11th Hour Macintosh English (Installed) + { + { + "11h", "Making Of (Installed)", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 2 + }, + // Clandestiny Trailer DOS English { { @@ -170,6 +230,36 @@ static const GroovieGameDescription gameDescriptions[] = { kGroovieV2, 3 }, + // Clandestiny Trailer Macintosh English + { + { + "clandestiny", "Trailer", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 3 + }, + + // Clandestiny Trailer Macintosh English (Installed) + { + { + "clandestiny", "Trailer (Installed)", + { + { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 }, + { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, + GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + }, + kGroovieV2, 3 + }, + // Clandestiny DOS English { { @@ -207,6 +297,11 @@ static const GroovieGameDescription gameDescriptions[] = { {AD_TABLE_END_MARKER, kGroovieT7G, 0} }; +static const char *directoryGlobs[] = { + "MIDI", + 0 +}; + class GroovieMetaEngine : public AdvancedMetaEngine { public: GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames) { @@ -222,6 +317,10 @@ public: // replaced with an according explanation. _flags = kADFlagUseExtraAsHint; _guioptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT); + + // Need MIDI directory to detect 11H Mac Installed + _maxScanDepth = 2; + _directoryGlobs = directoryGlobs; } const char *getName() const { -- cgit v1.2.3 From 77ef097723a869d85c2c7addba6afff85e3447ca Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 12 Sep 2012 18:12:28 -0400 Subject: GROOVIE: Load the 11H Mac installer file when present --- engines/groovie/groovie.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'engines/groovie') diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 0f05d73599..16358bfa28 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -30,6 +30,7 @@ #include "groovie/music.h" #include "groovie/resource.h" #include "groovie/roq.h" +#include "groovie/stuffit.h" #include "groovie/vdx.h" #include "common/config-manager.h" @@ -94,6 +95,15 @@ GroovieEngine::~GroovieEngine() { } Common::Error GroovieEngine::run() { + if (_gameDescription->version == kGroovieV2 && getPlatform() == Common::kPlatformMacintosh) { + // Load the Mac installer with the lowest priority (in case the user has installed + // the game and has the MIDI folder present; faster to just load them) + Common::Archive *archive = createStuffItArchive("The 11th Hour Installer"); + + if (archive) + SearchMan.add("The 11th Hour Installer", archive); + } + _script = new Script(this, _gameDescription->version); // Initialize the graphics -- cgit v1.2.3 From 542b99bfe7afabe838e207795ceccc56b05ee73b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 15 Nov 2012 18:26:15 +0200 Subject: GROOVIE: Added documentation for the GameSpeed enum --- engines/groovie/groovie.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'engines/groovie') diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h index df2f062757..c66e54b500 100644 --- a/engines/groovie/groovie.h +++ b/engines/groovie/groovie.h @@ -72,6 +72,13 @@ enum DebugLevels { // the current limitation is 32 debug levels (1 << 31 is the last one) }; +/** + * This enum reflects the available movie speed settings: + * - Normal: both movies and 'teeth' animations are played at a normal speed + * - Tweaked: movies are played at a normal speed, 'teeth' animations at + increased speed + * - iOS: both movies and 'teeth' animations are played at increased speed + */ enum GameSpeed { kGroovieSpeedNormal, kGroovieSpeediOS, -- cgit v1.2.3 From f65b22923420cad2d7ece7c2c66617585228ffd1 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 3 Dec 2012 09:16:58 -0500 Subject: GROOVIE: Fix some indentation in StuffIt --- engines/groovie/stuffit.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'engines/groovie') diff --git a/engines/groovie/stuffit.cpp b/engines/groovie/stuffit.cpp index 03fa300e49..37f12585e7 100644 --- a/engines/groovie/stuffit.cpp +++ b/engines/groovie/stuffit.cpp @@ -435,7 +435,7 @@ Common::SeekableReadStream *StuffItArchive::decompress14(Common::SeekableReadStr SIT14Data *dat = new SIT14Data(); - // initialization + // initialization for (i = k = 0; i < 52; ++i) { dat->var2[i] = k; k += (1 << (dat->var1[i] = ((i >= 4) ? ((i - 4) >> 2) : 0))); @@ -449,10 +449,10 @@ Common::SeekableReadStream *StuffItArchive::decompress14(Common::SeekableReadStr for (j = 0; j < m; ++j) dat->var8[i++] = l; - for (i = 0, k = 1; i < 75; ++i) { + for (i = 0, k = 1; i < 75; ++i) { dat->var5[i] = k; k += (1 << (dat->var4[i] = (i >= 3 ? ((i - 3) >> 2) : 0))); - } + } for (i = 0; i < 4; ++i) dat->var6[i] = i - 1; @@ -462,8 +462,8 @@ Common::SeekableReadStream *StuffItArchive::decompress14(Common::SeekableReadStr for (j = 0; j < m; ++j) dat->var6[i++] = l; - m = bits->getBits(16); // number of blocks - j = 0; // window position + m = bits->getBits(16); // number of blocks + j = 0; // window position while (m-- && !bits->eos()) { bits->getBits(16); // skip crunched block size -- cgit v1.2.3 From 3249278a51c666ae75a92d7119790ea551a81351 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 2 Jan 2013 12:11:22 +0200 Subject: GROOVIE: Simplify the movie speed settings and add a GUI option This removes the "iOS" speed setting, where some movies could get out of sync. Two movie options are now available, "normal" and "fast" movie speed, which is the old "tweaked" setting. With the "fast" movie speed, the movie speed is changed to match that of the iOS version, but only in movies with sound. Movies without sound (like the supernatural animations, i.e. the "teeth" icon in-game) are still played at their regular speed, to avoid music sync issues. --- engines/groovie/detection.cpp | 31 ++++++++++++++++++++++++------- engines/groovie/groovie.cpp | 9 ++------- engines/groovie/groovie.h | 11 +++++------ engines/groovie/vdx.cpp | 2 +- 4 files changed, 32 insertions(+), 21 deletions(-) (limited to 'engines/groovie') diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index e06dace0d7..65452f5cf3 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -25,9 +25,12 @@ #include "groovie/saveload.h" #include "common/system.h" +#include "common/translation.h" namespace Groovie { +#define GAMEOPTION_T7G_FAST_MOVIE_SPEED GUIO_GAMEOPTIONS1 + static const PlainGameDescriptor groovieGames[] = { // Games {"t7g", "The 7th Guest"}, @@ -52,7 +55,7 @@ static const GroovieGameDescription gameDescriptions[] = { "t7g", "", AD_ENTRY1s("script.grv", "d1b8033b40aa67c076039881eccce90d", 16659), Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -63,7 +66,7 @@ static const GroovieGameDescription gameDescriptions[] = { "t7g", "", AD_ENTRY1s("T7GMac", "acdc4a58dd3f007f65e99b99d78e0bce", 1814029), Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, - GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -79,7 +82,7 @@ static const GroovieGameDescription gameDescriptions[] = { "t7g", "", AD_ENTRY1s("T7GMac", "6bdee8d0f9eef6d58d02fcd7deec3fb2", 1830783), Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, - GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -90,7 +93,7 @@ static const GroovieGameDescription gameDescriptions[] = { "t7g", "", AD_ENTRY1s("T7GMac", "0d595d4b44ae1814082938d051e5174e", 1830783), Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, - GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -106,7 +109,7 @@ static const GroovieGameDescription gameDescriptions[] = { { NULL, 0, NULL, 0} }, Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT) + GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -120,7 +123,7 @@ static const GroovieGameDescription gameDescriptions[] = { { NULL, 0, NULL, 0} }, Common::EN_ANY, Common::kPlatformIOS, ADGF_NO_FLAGS, - GUIO2(GUIO_NOMIDI, GUIO_NOASPECT) + GUIO3(GUIO_NOMIDI, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED) }, kGroovieT7G, 0 }, @@ -302,9 +305,23 @@ static const char *directoryGlobs[] = { 0 }; +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_T7G_FAST_MOVIE_SPEED, + { + _s("Fast movie speed"), + _s("Play movies at an increased speed"), + "fast_movie_speed", + false + } + }, + + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; + class GroovieMetaEngine : public AdvancedMetaEngine { public: - GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames) { + GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames, optionsList) { _singleid = "groovie"; // Use kADFlagUseExtraAsHint in order to distinguish the 11th hour from diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 16358bfa28..5ade442742 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -60,13 +60,8 @@ GroovieEngine::GroovieEngine(OSystem *syst, const GroovieGameDescription *gd) : SearchMan.addSubDirectoryMatching(gameDataDir, "MIDI"); _modeSpeed = kGroovieSpeedNormal; - if (ConfMan.hasKey("t7g_speed")) { - Common::String speed = ConfMan.get("t7g_speed"); - if (speed.equals("im_an_ios")) - _modeSpeed = kGroovieSpeediOS; - else if (speed.equals("tweaked")) - _modeSpeed = kGroovieSpeedTweaked; - } + if (ConfMan.hasKey("fast_movie_speed") && ConfMan.getBool("fast_movie_speed")) + _modeSpeed = kGroovieSpeedFast; // Initialize the custom debug levels DebugMan.addDebugChannel(kGroovieDebugAll, "All", "Debug everything"); diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h index c66e54b500..79abc13b1c 100644 --- a/engines/groovie/groovie.h +++ b/engines/groovie/groovie.h @@ -74,15 +74,14 @@ enum DebugLevels { /** * This enum reflects the available movie speed settings: - * - Normal: both movies and 'teeth' animations are played at a normal speed - * - Tweaked: movies are played at a normal speed, 'teeth' animations at - increased speed - * - iOS: both movies and 'teeth' animations are played at increased speed + * - Normal: play videos at a normal speed + * - Fast: play videos with audio at a fast speed. Videos without audio, + * like teeth animations, are played at their regular speed to avoid + * audio sync issues */ enum GameSpeed { kGroovieSpeedNormal, - kGroovieSpeediOS, - kGroovieSpeedTweaked + kGroovieSpeedFast }; struct GroovieGameDescription; diff --git a/engines/groovie/vdx.cpp b/engines/groovie/vdx.cpp index b3fcf462b2..8786e75488 100644 --- a/engines/groovie/vdx.cpp +++ b/engines/groovie/vdx.cpp @@ -88,7 +88,7 @@ uint16 VDXPlayer::loadInternal() { // Enable highspeed if we're not obeying fps, and not marked as special // This will be disabled in chunk audio if we're actually an audio vdx - if ( _vm->_modeSpeed == kGroovieSpeediOS || (_vm->_modeSpeed == kGroovieSpeedTweaked && ((_flags & (1 << 15)) == 0))) + if (_vm->_modeSpeed == kGroovieSpeedFast && ((_flags & (1 << 15)) == 0)) setOverrideSpeed(true); if (_flagOnePrev && !_flagOne && !_flagEight) { -- cgit v1.2.3