diff --git a/scumm/imuse_digi/dimuse.cpp b/scumm/imuse_digi/dimuse.cpp index 1f9b702282b..bb6000145dd 100644 --- a/scumm/imuse_digi/dimuse.cpp +++ b/scumm/imuse_digi/dimuse.cpp @@ -116,6 +116,7 @@ void IMuseDigital::saveOrLoad(Serializer *ser) { MKLINE(Track, mixerFlags, sleInt32, VER(31)), MK_OBSOLETE(Track, mixerVol, sleInt32, VER(31), VER(42)), MK_OBSOLETE(Track, mixerPan, sleInt32, VER(31), VER(42)), + MKLINE(Track, compressed, sleByte, VER(45)), MKEND() }; @@ -143,6 +144,10 @@ void IMuseDigital::saveOrLoad(Serializer *ser) { track->soundName, track->soundType, track->volGroupId, -1); assert(track->soundHandle); + if (track->compressed) { + track->regionOffset = 0; + track->dataOffset = _sound->getRegionOffset(track->soundHandle, track->curRegion); + } int32 streamBufferSize = track->iteration; int freq = _sound->getFreq(track->soundHandle); track->stream2 = NULL; @@ -282,8 +287,8 @@ void IMuseDigital::callback() { _vm->_mixer->setChannelBalance(track->handle, pan); track->stream->append(data, result); track->regionOffset += result; - free(data); } + free(data); if (_sound->isEndOfRegion(track->soundHandle, track->curRegion)) { switchToNextRegion(track); diff --git a/scumm/imuse_digi/dimuse.h b/scumm/imuse_digi/dimuse.h index 94d7877e83d..8a6e95519a7 100644 --- a/scumm/imuse_digi/dimuse.h +++ b/scumm/imuse_digi/dimuse.h @@ -64,6 +64,7 @@ private: bool readyToRemove; bool started; bool souStream; + bool compressed; int32 priority; int32 regionOffset; int32 dataOffset; diff --git a/scumm/imuse_digi/dimuse_bndmgr.cpp b/scumm/imuse_digi/dimuse_bndmgr.cpp index 2e1481caa1d..5a7de3dfd7a 100644 --- a/scumm/imuse_digi/dimuse_bndmgr.cpp +++ b/scumm/imuse_digi/dimuse_bndmgr.cpp @@ -30,6 +30,7 @@ BundleDirCache::BundleDirCache() { _budleDirCache[fileId].bundleTable = NULL; _budleDirCache[fileId].fileName[0] = 0; _budleDirCache[fileId].numFiles = 0; + _budleDirCache[fileId].compressedBun = false; } } @@ -40,18 +41,18 @@ BundleDirCache::~BundleDirCache() { } } -BundleDirCache::AudioTable *BundleDirCache::getTable(const char *filename) { - int slot = matchFile(filename); - assert(slot != -1); +BundleDirCache::AudioTable *BundleDirCache::getTable(const char *filename, int slot) { return _budleDirCache[slot].bundleTable; } -int32 BundleDirCache::getNumFiles(const char *filename) { - int slot = matchFile(filename); - assert(slot != -1); +int32 BundleDirCache::getNumFiles(const char *filename, int slot) { return _budleDirCache[slot].numFiles; } +bool BundleDirCache::isCompressed(int slot) { + return _budleDirCache[slot].compressedBun; +} + int BundleDirCache::matchFile(const char *filename) { int32 tag, offset; bool found = false; @@ -80,6 +81,8 @@ int BundleDirCache::matchFile(const char *filename) { error("BundleDirCache::matchFileFile() Can't find free slot for file bundle dir cache"); tag = file.readUint32BE(); + if (tag == 'LB23') + _budleDirCache[freeSlot].compressedBun = true; offset = file.readUint32BE(); strcpy(_budleDirCache[freeSlot].fileName, filename); @@ -89,22 +92,26 @@ int BundleDirCache::matchFile(const char *filename) { file.seek(offset, SEEK_SET); for (int32 i = 0; i < _budleDirCache[freeSlot].numFiles; i++) { - char name[13], c; + char name[24], c; int32 z = 0; int32 z2; - for (z2 = 0; z2 < 8; z2++) - if ((c = file.readByte()) != 0) - name[z++] = c; - name[z++] = '.'; - for (z2 = 0; z2 < 4; z2++) - if ((c = file.readByte()) != 0) - name[z++] = c; + if (tag == 'LB23') { + file.read(_budleDirCache[freeSlot].bundleTable[i].filename, 24); + } else { + for (z2 = 0; z2 < 8; z2++) + if ((c = file.readByte()) != 0) + name[z++] = c; + name[z++] = '.'; + for (z2 = 0; z2 < 4; z2++) + if ((c = file.readByte()) != 0) + name[z++] = c; - name[z] = '\0'; - strcpy(_budleDirCache[freeSlot].bundleTable[i].filename, name); + name[z] = '\0'; + strcpy(_budleDirCache[freeSlot].bundleTable[i].filename, name); + } _budleDirCache[freeSlot].bundleTable[i].offset = file.readUint32BE(); - file.seek(4, SEEK_CUR); + _budleDirCache[freeSlot].bundleTable[i].size = file.readUint32BE(); } return freeSlot; } else { @@ -124,10 +131,22 @@ BundleMgr::BundleMgr(BundleDirCache *cache) { } BundleMgr::~BundleMgr() { - closeFile(); + close(); } -bool BundleMgr::openFile(const char *filename) { +File *BundleMgr::getFile(const char *filename, int32 &offset, int32 &size) { + for (int i = 0; i < _numFiles; i++) { + if (!scumm_stricmp(filename, _bundleTable[i].filename)) { + _file.seek(_bundleTable[i].offset, SEEK_SET); + offset = _bundleTable[i].offset; + size = _bundleTable[i].size; + break; + } + } + return &_file; +} + +bool BundleMgr::open(const char *filename, bool &compressed) { if (_file.isOpen()) return true; @@ -136,9 +155,12 @@ bool BundleMgr::openFile(const char *filename) { return false; } - _numFiles = _cache->getNumFiles(filename); + int slot = _cache->matchFile(filename); + assert(slot != -1); + compressed = _cache->isCompressed(slot); + _numFiles = _cache->getNumFiles(filename, slot); assert(_numFiles); - _bundleTable = _cache->getTable(filename); + _bundleTable = _cache->getTable(filename, slot); assert(_bundleTable); _compTableLoaded = false; _outputSize = 0; @@ -147,7 +169,7 @@ bool BundleMgr::openFile(const char *filename) { return true; } -void BundleMgr::closeFile() { +void BundleMgr::close() { if (_file.isOpen()) { _file.close(); _bundleTable = NULL; diff --git a/scumm/imuse_digi/dimuse_bndmgr.h b/scumm/imuse_digi/dimuse_bndmgr.h index c79232efdc8..5457ae20b83 100644 --- a/scumm/imuse_digi/dimuse_bndmgr.h +++ b/scumm/imuse_digi/dimuse_bndmgr.h @@ -29,8 +29,9 @@ namespace Scumm { class BundleDirCache { public: struct AudioTable { - char filename[13]; + char filename[24]; int32 offset; + int32 size; }; private: @@ -38,16 +39,17 @@ private: char fileName[20]; AudioTable *bundleTable; int32 numFiles; + bool compressedBun; } _budleDirCache[4]; - int matchFile(const char *filename); - public: BundleDirCache(); ~BundleDirCache(); - AudioTable *getTable(const char *filename); - int32 getNumFiles(const char *filename); + int matchFile(const char *filename); + AudioTable *getTable(const char *filename, int slot); + int32 getNumFiles(const char *filename, int slot); + bool isCompressed(int slot); }; class BundleMgr { @@ -80,8 +82,9 @@ public: BundleMgr(BundleDirCache *_cache); ~BundleMgr(); - bool openFile(const char *filename); - void closeFile(); + bool open(const char *filename, bool &compressed); + void close(); + File *getFile(const char *filename, int32 &offset, int32 &size); int32 decompressSampleByName(const char *name, int32 offset, int32 size, byte **comp_final, bool header_outside); int32 decompressSampleByIndex(int32 index, int32 offset, int32 size, byte **comp_final, int header_size, bool header_outside); int32 decompressSampleByCurIndex(int32 offset, int32 size, byte **comp_final, int header_size, bool header_outside); diff --git a/scumm/imuse_digi/dimuse_sndmgr.cpp b/scumm/imuse_digi/dimuse_sndmgr.cpp index d0eb9ff5252..cc9ca79de28 100644 --- a/scumm/imuse_digi/dimuse_sndmgr.cpp +++ b/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -22,6 +22,7 @@ #include "common/scummsys.h" #include "common/util.h" #include "sound/voc.h" +#include "sound/vorbis.h" #include "scumm/scumm.h" #include "scumm/imuse_digi/dimuse.h" #include "scumm/imuse_digi/dimuse_sndmgr.h" @@ -79,6 +80,39 @@ void ImuseDigiSndMgr::countElements(byte *ptr, int &numRegions, int &numJumps, i } while (tag != MKID_BE('DATA')); } +void ImuseDigiSndMgr::prepareSoundFromRMAP(File *file, soundStruct *sound, int32 offset, int32 size) { + int l; + + file->seek(offset, SEEK_SET); + uint32 tag = file->readUint32BE(); + assert(tag == 'RMAP'); + assert(file->readUint32BE() == 1); // version + sound->bits = 16; + sound->freq = 22050; + sound->channels = 2; + sound->numRegions = file->readUint32BE(); + sound->numJumps = file->readUint32BE(); + sound->numSyncs = file->readUint32BE(); + sound->region = (_region *)malloc(sizeof(_region) * sound->numRegions); + sound->jump = (_jump *)malloc(sizeof(_jump) * sound->numJumps); + sound->sync = (_sync *)malloc(sizeof(_sync) * sound->numSyncs); + for (l = 0; l < sound->numRegions; l++) { + sound->region[l].offset = file->readUint32BE(); + sound->region[l].length = file->readUint32BE(); + } + for (l = 0; l < sound->numJumps; l++) { + sound->jump[l].offset = file->readUint32BE(); + sound->jump[l].dest = file->readUint32BE(); + sound->jump[l].hookId = file->readUint32BE(); + sound->jump[l].fadeDelay = file->readUint32BE(); + } + for (l = 0; l < sound->numSyncs; l++) { + sound->sync[l].size = file->readUint32BE(); + sound->sync[l].ptr = (byte *)malloc(sound->sync[l].size); + file->read(sound->sync[l].ptr, sound->sync[l].size); + } +} + void ImuseDigiSndMgr::prepareSound(byte *ptr, soundStruct *sound) { if (READ_UINT32(ptr) == MKID('Crea')) { bool quit = false; @@ -224,7 +258,7 @@ bool ImuseDigiSndMgr::openMusicBundle(soundStruct *sound, int disk) { sound->bundle = new BundleMgr(_cacheBundleDir); if (_vm->_gameId == GID_CMI) { if (_vm->_features & GF_DEMO) { - result = sound->bundle->openFile("music.bun"); + result = sound->bundle->open("music.bun", sound->compressed); } else { char musicfile[20]; if (disk == -1) @@ -237,13 +271,13 @@ bool ImuseDigiSndMgr::openMusicBundle(soundStruct *sound, int disk) { // sound->bundle->closeFile(); // } - result = sound->bundle->openFile(musicfile); + result = sound->bundle->open(musicfile, sound->compressed); // FIXME: Shouldn't we only set _disk if result == true? _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); } } else if (_vm->_gameId == GID_DIG) - result = sound->bundle->openFile("digmusic.bun"); + result = sound->bundle->open("digmusic.bun", sound->compressed); else error("ImuseDigiSndMgr::openMusicBundle() Don't know which bundle file to load"); @@ -258,7 +292,7 @@ bool ImuseDigiSndMgr::openVoiceBundle(soundStruct *sound, int disk) { sound->bundle = new BundleMgr(_cacheBundleDir); if (_vm->_gameId == GID_CMI) { if (_vm->_features & GF_DEMO) { - result = sound->bundle->openFile("voice.bun"); + result = sound->bundle->open("voice.bun", sound->compressed); } else { char voxfile[20]; if (disk == -1) @@ -271,13 +305,13 @@ bool ImuseDigiSndMgr::openVoiceBundle(soundStruct *sound, int disk) { // sound->bundle->closeFile(); // } - result = sound->bundle->openFile(voxfile); + result = sound->bundle->open(voxfile, sound->compressed); // FIXME: Shouldn't we only set _disk if result == true? _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); } } else if (_vm->_gameId == GID_DIG) - result = sound->bundle->openFile("digvoice.bun"); + result = sound->bundle->open("digvoice.bun", sound->compressed); else error("ImuseDigiSndMgr::openVoiceBundle() Don't know which bundle file to load"); @@ -323,7 +357,19 @@ ImuseDigiSndMgr::soundStruct *ImuseDigiSndMgr::openSound(int32 soundId, const ch closeSound(sound); return NULL; } - if (soundName[0] == 0) { + if (sound->compressed) { + char fileName[24]; + int32 offset = 0, size = 0; + sprintf(fileName, "%s.map", soundName); + File *rmapFile = sound->bundle->getFile(fileName, offset, size); + prepareSoundFromRMAP(rmapFile, sound, offset, size); + strcpy(sound->name, soundName); + sound->soundId = soundId; + sound->type = soundType; + sound->volGroupId = volGroupId; + sound->disk = _disk; + return sound; + } else if (soundName[0] == 0) { if (sound->bundle->decompressSampleByIndex(soundId, 0, 0x2000, &ptr, 0, header_outside) == 0 || ptr == NULL) { closeSound(sound); return NULL; @@ -362,7 +408,11 @@ void ImuseDigiSndMgr::closeSound(soundStruct *soundHandle) { _vm->unlock(rtSound, soundHandle->soundId); } + if (soundHandle->compressedStream) + delete soundHandle->compressedStream; + delete soundHandle->bundle; + for (int r = 0; r < soundHandle->numSyncs; r++) free(soundHandle->sync[r].ptr); free(soundHandle->region); @@ -387,6 +437,11 @@ bool ImuseDigiSndMgr::checkForProperHandle(soundStruct *soundHandle) { return false; } +bool ImuseDigiSndMgr::isCompressed(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->compressed; +} + int ImuseDigiSndMgr::getFreq(soundStruct *soundHandle) { assert(checkForProperHandle(soundHandle)); return soundHandle->freq; @@ -500,13 +555,33 @@ int32 ImuseDigiSndMgr::getDataFromRegion(soundStruct *soundHandle, int region, b int header_size = soundHandle->offsetData; bool header_outside = ((_vm->_gameId == GID_CMI) && !(_vm->_features & GF_DEMO)); - if (soundHandle->bundle) { + if ((soundHandle->bundle) && (!soundHandle->compressed)) { size = soundHandle->bundle->decompressSampleByCurIndex(start + offset, size, buf, header_size, header_outside); } else if (soundHandle->resPtr) { *buf = (byte *)malloc(size); memcpy(*buf, soundHandle->resPtr + start + offset + header_size, size); + } else if ((soundHandle->bundle) && (soundHandle->compressed)) { + *buf = (byte *)malloc(size); + char fileName[24]; + sprintf(fileName, "%s_reg%03d.ogg", soundHandle->name, region); + if (scumm_stricmp(fileName, soundHandle->lastFileName) != 0) { + int32 offset = 0, size = 0; + File *oggFile = soundHandle->bundle->getFile(fileName, offset, size); + if (!soundHandle->compressedStream) { + soundHandle->compressedStream = makeVorbisStream(oggFile, size); + assert(soundHandle->compressedStream); + assert(soundHandle->compressedStream->getRate() == 22050); + assert(soundHandle->compressedStream->isStereo()); + } + strcpy(soundHandle->lastFileName, fileName); + } + size = soundHandle->compressedStream->readBuffer((int16 *)*buf, size / 2) * 2; + if (soundHandle->compressedStream->endOfData()) { + delete soundHandle->compressedStream; + soundHandle->compressedStream = NULL; + } } - + return size; } diff --git a/scumm/imuse_digi/dimuse_sndmgr.h b/scumm/imuse_digi/dimuse_sndmgr.h index 3435e256b2a..3e6713a290a 100644 --- a/scumm/imuse_digi/dimuse_sndmgr.h +++ b/scumm/imuse_digi/dimuse_sndmgr.h @@ -23,6 +23,7 @@ #include "stdafx.h" #include "common/scummsys.h" +#include "sound/audiostream.h" #include "scumm/imuse_digi/dimuse_bndmgr.h" namespace Scumm { @@ -83,6 +84,9 @@ public: int type; int volGroupId; int disk; + AudioStream *compressedStream; + bool compressed; + char lastFileName[24]; }; private: @@ -92,6 +96,7 @@ private: bool checkForProperHandle(soundStruct *soundHandle); soundStruct *allocSlot(); void prepareSound(byte *ptr, soundStruct *sound); + void prepareSoundFromRMAP(File *file, soundStruct *sound, int32 offset, int32 size); ScummEngine *_vm; byte _disk; @@ -111,6 +116,7 @@ public: void closeSound(soundStruct *soundHandle); soundStruct *cloneSound(soundStruct *soundHandle); + bool isCompressed(soundStruct *soundHandle); int getFreq(soundStruct *soundHandle); int getBits(soundStruct *soundHandle); int getChannels(soundStruct *soundHandle); diff --git a/scumm/imuse_digi/dimuse_track.cpp b/scumm/imuse_digi/dimuse_track.cpp index 4aeaaba6518..7ee5fd1bebf 100644 --- a/scumm/imuse_digi/dimuse_track.cpp +++ b/scumm/imuse_digi/dimuse_track.cpp @@ -119,6 +119,8 @@ void IMuseDigital::startSound(int soundId, const char *soundName, int soundType, if (track->soundHandle == NULL) return; + track->compressed = _sound->isCompressed(track->soundHandle); + bits = _sound->getBits(track->soundHandle); channels = _sound->getChannels(track->soundHandle); freq = _sound->getFreq(track->soundHandle); @@ -147,6 +149,9 @@ void IMuseDigital::startSound(int soundId, const char *soundName, int soundType, track->mixerFlags |= SoundMixer::FLAG_UNSIGNED; } else error("IMuseDigital::startSound(): Can't handle %d bit samples", bits); + + if (track->compressed) + track->mixerFlags |= SoundMixer::FLAG_LITTLE_ENDIAN; } if (input) { diff --git a/scumm/saveload.h b/scumm/saveload.h index deb4cc20bdb..747e06799fa 100644 --- a/scumm/saveload.h +++ b/scumm/saveload.h @@ -32,7 +32,7 @@ namespace Scumm { // Can be useful for other ports too :) #define VER(x) x -#define CURRENT_VER 44 +#define CURRENT_VER 45 // To work around a warning in GCC 3.2 (and 3.1 ?) regarding non-POD types, // we use a small trick: instead of 0 we use 42. Why? Well, it seems newer GCC