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.
This commit is contained in:
Colin Snover 2016-08-19 10:05:05 -05:00
parent 0a4a2567a3
commit c4250c05d0
5 changed files with 75 additions and 19 deletions

View File

@ -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

View File

@ -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<IntMapResourceSource *>(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
}
}

View File

@ -296,6 +296,7 @@ protected:
typedef Common::HashMap<ResourceId, Resource *, ResourceIdHash> 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.

View File

@ -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<ResourceId> resources = listResources(kResourceTypeMap);
Common::List<ResourceId>::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));
}

View File

@ -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);