From c4250c05d02dc25fb20e8314ec960bec5ac59779 Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Fri, 19 Aug 2016 10:05:05 -0500 Subject: SCI32: Enable multi-disc audio resources Phant1, PQ:SWAT, GK2, and Phant2 all have different audio maps and audio volumes on each CD. In order to make this work within ScummVM, where CDs are never swapped, each RESOURCE.AUD for these games must be renamed to RESAUD.00x and each RESOURCE.SFX renamed to RESSFX.00x. --- engines/sci/detection.cpp | 4 ++-- engines/sci/resource.cpp | 38 ++++++++++++++++++++++++++++++++++++++ engines/sci/resource.h | 9 ++++++++- engines/sci/resource_audio.cpp | 38 ++++++++++++++++++++++++-------------- engines/sci/resource_intern.h | 5 +++-- 5 files changed, 75 insertions(+), 19 deletions(-) (limited to 'engines/sci') diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index f5797dc106..ad2b0f31a5 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -565,8 +565,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, // the file should be over 10MB, as it contains all the game speech and is usually // around 450MB+. The size check is for some floppy game versions like KQ6 floppy, which // also have a small resource.aud file - if (allFiles.contains("resource.aud") || allFiles.contains("audio001.002")) { - Common::FSNode file = allFiles.contains("resource.aud") ? allFiles["resource.aud"] : allFiles["audio001.002"]; + if (allFiles.contains("resource.aud") || allFiles.contains("resaud.001") || allFiles.contains("audio001.002")) { + Common::FSNode file = allFiles.contains("resource.aud") ? allFiles["resource.aud"] : (allFiles.contains("resaud.001") ? allFiles["resaud.001"] : allFiles["audio001.002"]); Common::SeekableReadStream *tmpStream = file.createReadStream(); if (tmpStream->size() > 10 * 1024 * 1024) { // We got a CD version, so set the CD flag accordingly diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 26b8a32861..f2321f5589 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -573,6 +573,9 @@ Resource *ResourceManager::testResource(ResourceId id) { } int ResourceManager::addAppropriateSources() { +#ifdef ENABLE_SCI32 + _multiDiscAudio = false; +#endif if (Common::File::exists("resource.map")) { // SCI0-SCI2 file naming scheme ResourceSource *map = addExternalMap("resource.map"); @@ -615,6 +618,10 @@ int ResourceManager::addAppropriateSources() { if (mapFiles.empty() || files.empty() || mapFiles.size() != files.size()) return 0; + if (Common::File::exists("resaud.001")) { + _multiDiscAudio = true; + } + for (Common::ArchiveMemberList::const_iterator mapIterator = mapFiles.begin(); mapIterator != mapFiles.end(); ++mapIterator) { Common::String mapName = (*mapIterator)->getName(); int mapNumber = atoi(strrchr(mapName.c_str(), '.') + 1); @@ -1747,11 +1754,42 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { // if we use the first entries in the resource file, half of the // game will be English and umlauts will also be missing :P if (resource->_source->getSourceType() == kSourceVolume) { + // Maps are read during the scanning process (below), so + // need to be treated as unallocated in order for the new + // data from this volume to be picked up and used + if (resId.getType() == kResourceTypeMap) { + resource->_status = kResStatusNoMalloc; + } resource->_source = source; resource->_fileOffset = fileOffset; resource->size = 0; } } + +#ifdef ENABLE_SCI32 + // Different CDs may have different audio maps on each disc. The + // ResourceManager does not know how to deal with this; it expects + // each resource ID to be unique across an entire game. To work + // around this problem, all audio maps from this disc must be + // processed immediately, since they will be replaced by the audio + // map from the next disc on the next call to readResourceMapSCI1 + if (_multiDiscAudio && resId.getType() == kResourceTypeMap) { + IntMapResourceSource *audioMap = static_cast(addSource(new IntMapResourceSource("MAP", mapVolumeNr, resId.getNumber()))); + Common::String volumeName; + if (resId.getNumber() == 65535) { + volumeName = Common::String::format("RESSFX.%03d", mapVolumeNr); + } else { + volumeName = Common::String::format("RESAUD.%03d", mapVolumeNr); + } + + ResourceSource *audioVolume = addSource(new AudioVolumeResourceSource(this, volumeName, audioMap, mapVolumeNr)); + if (!audioMap->_scanned) { + audioVolume->_scanned = true; + audioMap->_scanned = true; + audioMap->scanSource(this); + } + } +#endif } } diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 49cc52399e..70db5909b7 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -296,6 +296,7 @@ protected: typedef Common::HashMap ResourceMap; +class IntMapResourceSource; class ResourceManager { // FIXME: These 'friend' declarations are meant to be a temporary hack to // ease transition to the ResourceSource class system. @@ -414,6 +415,12 @@ private: */ int16 _currentDiscNo; + /** + * If true, the game has multiple audio volumes that contain different + * audio files for each disc. + */ + bool _multiDiscAudio; + public: #endif @@ -538,7 +545,7 @@ protected: * @param map The map * @return 0 on success, an SCI_ERROR_* code otherwise */ - int readAudioMapSCI11(ResourceSource *map); + int readAudioMapSCI11(IntMapResourceSource *map); /** * Reads SCI1 audio map files. diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 5ab443a16d..cbc4a02739 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -277,7 +277,7 @@ void ResourceManager::removeAudioResource(ResourceId resId) { // w syncSize (iff seq has bit 7 set) // w syncAscSize (iff seq has bit 6 set) -int ResourceManager::readAudioMapSCI11(ResourceSource *map) { +int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) { #ifndef ENABLE_SCI32 // SCI32 support is not built in. Check if this is a SCI32 game // and if it is abort here. @@ -286,17 +286,19 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { #endif uint32 offset = 0; - Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->_volumeNumber), false); + Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->_mapNumber), false); if (!mapRes) { - warning("Failed to open %i.MAP", map->_volumeNumber); + warning("Failed to open %i.MAP", map->_mapNumber); return SCI_ERROR_RESMAP_NOT_FOUND; } - ResourceSource *src = findVolume(map, 0); + ResourceSource *src = findVolume(map, map->_volumeNumber); - if (!src) + if (!src) { + warning("Failed to find volume for %i.MAP", map->_mapNumber); return SCI_ERROR_NO_RESOURCE_FILES_FOUND; + } byte *ptr = mapRes->data; @@ -309,7 +311,7 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { break; } - if (map->_volumeNumber == 65535) { + if (map->_mapNumber == 65535) { while (ptr < mapRes->data + mapRes->size) { uint16 n = READ_LE_UINT16(ptr); ptr += 2; @@ -327,7 +329,7 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { addResource(ResourceId(kResourceTypeAudio, n), src, offset); } - } else if (map->_volumeNumber == 0 && entrySize == 10 && ptr[3] == 0) { + } else if (map->_mapNumber == 0 && entrySize == 10 && ptr[3] == 0) { // QFG3 demo format // ptr[3] would be 'seq' in the normal format and cannot possibly be 0 while (ptr < mapRes->data + mapRes->size) { @@ -344,7 +346,7 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { addResource(ResourceId(kResourceTypeAudio, n), src, offset, size); } - } else if (map->_volumeNumber == 0 && entrySize == 8 && READ_LE_UINT16(ptr + 2) == 0xffff) { + } else if (map->_mapNumber == 0 && entrySize == 8 && READ_LE_UINT16(ptr + 2) == 0xffff) { // LB2 Floppy/Mother Goose SCI1.1 format Common::SeekableReadStream *stream = getVolumeFile(src); @@ -400,7 +402,7 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { // FIXME: The sync36 resource seems to be two bytes too big in KQ6CD // (bytes taken from the RAVE resource right after it) if (syncSize > 0) - addResource(ResourceId(kResourceTypeSync36, map->_volumeNumber, n & 0xffffff3f), src, offset, syncSize); + addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, n & 0xffffff3f), src, offset, syncSize); } if (n & 0x40) { @@ -410,12 +412,12 @@ int ResourceManager::readAudioMapSCI11(ResourceSource *map) { ptr += 2; if (kq6HiresSyncSize > 0) { - addResource(ResourceId(kResourceTypeRave, map->_volumeNumber, n & 0xffffff3f), src, offset + syncSize, kq6HiresSyncSize); + addResource(ResourceId(kResourceTypeRave, map->_mapNumber, n & 0xffffff3f), src, offset + syncSize, kq6HiresSyncSize); syncSize += kq6HiresSyncSize; } } - addResource(ResourceId(kResourceTypeAudio36, map->_volumeNumber, n & 0xffffff3f), src, offset + syncSize); + addResource(ResourceId(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f), src, offset + syncSize); } } @@ -937,13 +939,21 @@ void AudioVolumeResourceSource::loadResource(ResourceManager *resMan, Resource * } bool ResourceManager::addAudioSources() { +#ifdef ENABLE_SCI32 + // Multi-disc audio is added during addAppropriateSources for those titles + // that require it + if (_multiDiscAudio) { + return true; + } +#endif + Common::List resources = listResources(kResourceTypeMap); Common::List::iterator itr; for (itr = resources.begin(); itr != resources.end(); ++itr) { - ResourceSource *src = addSource(new IntMapResourceSource("MAP", itr->getNumber())); + ResourceSource *src = addSource(new IntMapResourceSource("MAP", 0, itr->getNumber())); - if ((itr->getNumber() == 65535) && Common::File::exists("RESOURCE.SFX")) + if (itr->getNumber() == 65535 && Common::File::exists("RESOURCE.SFX")) addSource(new AudioVolumeResourceSource(this, "RESOURCE.SFX", src, 0)); else if (Common::File::exists("RESOURCE.AUD")) addSource(new AudioVolumeResourceSource(this, "RESOURCE.AUD", src, 0)); @@ -991,7 +1001,7 @@ void ResourceManager::changeAudioDirectory(Common::String path) { if ((it->getNumber() == 65535)) continue; - ResourceSource *src = addSource(new IntMapResourceSource(mapName, it->getNumber())); + ResourceSource *src = addSource(new IntMapResourceSource(mapName, 0, it->getNumber())); addSource(new AudioVolumeResourceSource(this, audioResourceName, src, 0)); } diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h index 461d684005..fe4b0a97f4 100644 --- a/engines/sci/resource_intern.h +++ b/engines/sci/resource_intern.h @@ -134,8 +134,9 @@ public: class IntMapResourceSource : public ResourceSource { public: - IntMapResourceSource(const Common::String &name, int volNum) - : ResourceSource(kSourceIntMap, name, volNum) { + uint16 _mapNumber; + IntMapResourceSource(const Common::String &name, int volNum, int mapNum) + : ResourceSource(kSourceIntMap, name, volNum), _mapNumber(mapNum) { } virtual void scanSource(ResourceManager *resMan); -- cgit v1.2.3