aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorWalter van Niftrik2009-06-09 19:18:48 +0000
committerWalter van Niftrik2009-06-09 19:18:48 +0000
commit5e68fbfe875686c6ab1fda0a85d2a878486656c2 (patch)
tree02856ec1adb966359a3779e75c69fe35cf9e9499 /engines
parent6f49d1576b54e333f8da9b87ecc0e8ce03c473e9 (diff)
downloadscummvm-rg350-5e68fbfe875686c6ab1fda0a85d2a878486656c2.tar.gz
scummvm-rg350-5e68fbfe875686c6ab1fda0a85d2a878486656c2.tar.bz2
scummvm-rg350-5e68fbfe875686c6ab1fda0a85d2a878486656c2.zip
SCI: Moved SCI1 audio map handling into the resource manager.
svn-id: r41408
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/engine/ksound.cpp2
-rw-r--r--engines/sci/resource.cpp356
-rw-r--r--engines/sci/resource.h52
3 files changed, 209 insertions, 201 deletions
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index b742c93a52..c912da020d 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -1027,7 +1027,7 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) {
// In SCI1.1: tests for digital audio support
return make_reg(0, 1);
} else {
- s->_sound._audioResource->setAudioLang(argv[1].toSint16());
+ s->resmgr->setAudioLanguage(argv[1].toSint16());
}
break;
default:
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 5edf1b7145..ce08280812 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -217,7 +217,7 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
return loadPatch(res, file);
}
-bool ResourceManager::loadFromAudioVolume(Resource *res, Common::File &file) {
+bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) {
ResourceType type = (ResourceType)(file.readByte() & 0x7f);
if (((res->id.type == kResourceTypeAudio || res->id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
|| ((res->id.type == kResourceTypeSync || res->id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
@@ -243,6 +243,21 @@ bool ResourceManager::loadFromAudioVolume(Resource *res, Common::File &file) {
return loadPatch(res, file);
}
+bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) {
+ res->data = new byte[res->size];
+
+ if (res->data == NULL) {
+ error("Can't allocate %d bytes needed for loading %s", res->size, res->id.toString().c_str());
+ }
+
+ unsigned int really_read = file.read(res->data, res->size);
+ if (really_read != res->size)
+ warning("Read %d bytes from %s but expected %d", really_read, res->id.toString().c_str(), res->size);
+
+ res->status = kResStatusAllocated;
+ return true;
+}
+
Common::File *ResourceManager::getVolumeFile(const char *filename) {
Common::List<Common::File *>::iterator it = _volumeFiles.begin();
Common::File *file;
@@ -292,7 +307,10 @@ void ResourceManager::loadResource(Resource *res) {
file->seek(res->file_offset, SEEK_SET);
if (res->source->source_type == kSourceAudioVolume) {
- loadFromAudioVolume(res, *file);
+ if (_sciVersion < SCI_VERSION_1_1)
+ loadFromAudioVolumeSCI1(res, *file);
+ else
+ loadFromAudioVolumeSCI11(res, *file);
} else {
int error = decompress(res, file);
if (error) {
@@ -436,8 +454,11 @@ void ResourceManager::scanNewSources() {
else
readResourceMapSCI1(source);
break;
+ case kSourceExtAudioMap:
+ readAudioMapSCI1(source);
+ break;
case kSourceIntMap:
- readMap(source);
+ readAudioMapSCI11(source);
break;
default:
break;
@@ -460,6 +481,7 @@ ResourceManager::ResourceManager(int version, int maxMemory) {
_LRU.clear();
_resMap.clear();
_sciVersion = version;
+ _audioMapSCI1 = NULL;
addAppropriateSources();
@@ -607,15 +629,10 @@ void ResourceManager::printLRU() {
debug("Total: %d entries, %d bytes (mgr says %d)", entries, mem, _memoryLRU);
}
-void ResourceManager::freeOldResources(int last_invulnerable) {
- while (_maxMemory < _memoryLRU && (!last_invulnerable || !_LRU.empty())) {
+void ResourceManager::freeOldResources() {
+ while (_maxMemory < _memoryLRU) {
+ assert(!_LRU.empty());
Resource *goner = *_LRU.reverse_begin();
- if (!goner) {
- debug("Internal error: mgr->lru_last is NULL!");
- debug("LRU-mem= %d", _memoryLRU);
- debug("lru_first = %p", (void *)*_LRU.begin());
- printLRU();
- }
removeFromLRU(goner);
goner->unalloc();
#ifdef SCI_VERBOSE_RESMGR
@@ -659,6 +676,8 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) {
// Unless an error occured, the resource is now either
// locked or allocated, but never queued or freed.
+ freeOldResources();
+
if (lock) {
if (retval->status == kResStatusAllocated) {
retval->status = kResStatusLocked;
@@ -671,8 +690,6 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) {
addToLRU(retval);
}
- freeOldResources(retval->status == kResStatusAllocated);
-
if (retval->data)
return retval;
else {
@@ -695,7 +712,7 @@ void ResourceManager::unlockResource(Resource *res) {
addToLRU(res);
}
- freeOldResources(0);
+ freeOldResources();
}
int ResourceManager::detectMapVersion() {
@@ -1077,6 +1094,22 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
}
}
+void ResourceManager::removeAudioResource(ResourceId resId) {
+ // Remove resource, unless it was loaded from a patch
+ if (_resMap.contains(resId)) {
+ Resource *res = _resMap.getVal(resId);
+
+ if (res->source->source_type == kSourceAudioVolume) {
+ if (res->lockers == 0) {
+ _resMap.erase(resId);
+ delete res;
+ } else {
+ warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
+ }
+ }
+ }
+}
+
// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
// =========
// 6-byte entries:
@@ -1112,7 +1145,7 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
// w syncSize (iff seq has bit 7 set)
// w syncAscSize (iff seq has bit 6 set)
-int ResourceManager::readMap(ResourceSource *map) {
+int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
bool isEarly = true;
uint32 offset = 0;
Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
@@ -1197,6 +1230,103 @@ int ResourceManager::readMap(ResourceSource *map) {
return 0;
}
+// AUDIOnnn.MAP contains 10-byte entries:
+// w nEntry
+// dw offset+volume (as in resource.map)
+// dw size
+// ending with 10 0xFFs
+
+int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
+ Common::File file;
+
+ if (!file.open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ while (1) {
+ uint16 n = file.readUint16LE();
+ uint32 offset = file.readUint32LE();
+ uint32 size = file.readUint32LE();
+
+ if (file.ioFailed()) {
+ warning("Error while reading %s", map->location_name.c_str());
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ if (n == 0xffff)
+ break;
+
+ byte volume_nr = offset >> 28; // most significant 4 bits
+ offset &= 0x0fffffff; // least significant 28 bits
+
+ ResourceSource *src = getVolume(map, volume_nr);
+
+ if (src) {
+ if (unload)
+ removeAudioResource(ResourceId(kResourceTypeAudio, n));
+ else
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ } else {
+ warning("Failed to find audio volume %i", volume_nr);
+ }
+ }
+
+ return 0;
+}
+
+void ResourceManager::setAudioLanguage(int language) {
+ if (_audioMapSCI1) {
+ if (_audioMapSCI1->volume_number == language) {
+ // This language is already loaded
+ return;
+ }
+
+ // We already have a map loaded, so we unload it first
+ readAudioMapSCI1(_audioMapSCI1, true);
+
+ // Remove all volumes that use this map from the source list
+ Common::List<ResourceSource *>::iterator it = _sources.begin();
+ while (it != _sources.end()) {
+ ResourceSource *src = *it;
+ if (src->associated_map == _audioMapSCI1) {
+ it = _sources.erase(it);
+ delete src;
+ } else {
+ ++it;
+ }
+ }
+
+ // Remove the map itself from the source list
+ _sources.remove(_audioMapSCI1);
+ delete _audioMapSCI1;
+
+ _audioMapSCI1 = NULL;
+ }
+
+ char filename[9];
+ snprintf(filename, 9, "AUDIO%03d", language);
+
+ Common::String fullname = Common::String(filename) + ".MAP";
+ if (!Common::File::exists(fullname)) {
+ warning("No audio map found for language %i", language);
+ return;
+ }
+
+ _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
+
+ // Search for audio volumes for this language and add them to the source list
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ const Common::String name = (*x)->getName();
+ const char *dot = strrchr(name.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
+ }
+
+ scanNewSources();
+}
+
int ResourceManager::readResourceInfo(Resource *res, Common::File *file,
uint32&szPacked, ResourceCompression &compression) {
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
@@ -1360,42 +1490,6 @@ AudioResource::AudioResource(ResourceManager *resMgr, int sciVersion) {
_resMgr = resMgr;
_sciVersion = sciVersion;
_audioRate = 11025;
- _lang = 0;
- _audioMapSCI1 = 0;
- _audioMapSCI11 = 0;
-}
-
-AudioResource::~AudioResource() {
- if (_sciVersion < SCI_VERSION_1_1) {
- if (_audioMapSCI1) {
- delete[] _audioMapSCI1;
- _audioMapSCI1 = 0;
- }
- } else {
- if (_audioMapSCI11)
- _resMgr->unlockResource(_audioMapSCI11);
- }
-}
-
-// Used in SCI1 games
-void AudioResource::setAudioLang(int16 lang) {
- if (lang != -1) {
- _lang = lang;
-
- char filename[40];
- sprintf(filename, "AUDIO%03d.MAP", _lang);
-
- Common::File* audioMapFile = new Common::File();
- if (audioMapFile->open(filename)) {
- // The audio map is freed in the destructor
- _audioMapSCI1 = new byte[audioMapFile->size()];
- audioMapFile->read(_audioMapSCI1, audioMapFile->size());
- audioMapFile->close();
- delete audioMapFile;
- } else {
- _audioMapSCI1 = 0;
- }
- }
}
int AudioResource::getAudioPosition() {
@@ -1406,33 +1500,6 @@ int AudioResource::getAudioPosition() {
}
}
-bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size) {
- // AUDIO00X.MAP contains 10-byte entries:
- // w nEntry
- // dw offset+volume (as in resource.map)
- // dw size
- // ending with 10 0xFFs
- uint16 n;
- uint32 off;
-
- if (_audioMapSCI1 == 0)
- return false;
-
- byte *ptr = _audioMapSCI1;
- while ((n = READ_LE_UINT16(ptr)) != 0xFFFF) {
- if (n == audioNumber) {
- off = READ_LE_UINT32(ptr + 2);
- size = READ_LE_UINT32(ptr + 6);
- volume = off >> 28;
- offset = off & 0x0FFFFFFF;
- return true;
- }
- ptr += 10;
- }
-
- return false;
-}
-
// FIXME: Move this to sound/adpcm.cpp?
// Note that the 16-bit version is also used in coktelvideo.cpp
static const uint16 tableDPCM16[128] = {
@@ -1535,115 +1602,56 @@ static byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 &size,
Audio::AudioStream* AudioResource::getAudioStream(uint32 audioNumber, uint32 volume, int *sampleLen) {
Audio::AudioStream *audioStream = 0;
- uint32 offset;
uint32 size;
- bool found = false;
byte *data = 0;
- char filename[40];
byte flags = 0;
- Sci::Resource* audioRes = NULL;
+ Sci::Resource* audioRes;
- // Try to load from resource manager
- if (volume == 65535)
+ if (volume == 65535) {
audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio, audioNumber), false);
- else
- audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio36, volume, audioNumber), false);
-
- if (audioRes) {
- if (_sciVersion < SCI_VERSION_1_1) {
- size = audioRes->size;
- data = audioRes->data;
- } else {
- byte audioFlags;
-
- Common::MemoryReadStream *headerStream =
- new Common::MemoryReadStream(audioRes->header, audioRes->headerSize, false);
-
- if (readSOLHeader(headerStream, audioRes->headerSize, size, _audioRate, audioFlags)) {
- Common::MemoryReadStream *dataStream =
- new Common::MemoryReadStream(audioRes->data, audioRes->size, false);
- data = readSOLAudio(dataStream, size, audioFlags, flags);
- delete dataStream;
- }
- delete headerStream;
- }
-
- if (data) {
- audioStream = Audio::makeLinearInputStream(data, size, _audioRate,
- flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
+ if (!audioRes) {
+ warning("Failed to find audio entry %i", audioNumber);
+ return NULL;
}
} else {
- // Load it from the audio file
- if (_sciVersion < SCI_VERSION_1_1) {
- byte sci1Volume;
- found = findAudEntrySCI1(audioNumber, sci1Volume, offset, size);
- sprintf(filename, "AUDIO%03d.%03d", _lang, sci1Volume);
- flags |= Audio::Mixer::FLAG_UNSIGNED;
+ audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio36, volume, audioNumber), false);
+ if (!audioRes) {
+ warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (audioNumber >> 24) & 0xff,
+ (audioNumber >> 16) & 0xff, (audioNumber >> 8) & 0xff, audioNumber & 0xff);
+ return NULL;
}
+ }
- if (found) {
- #if 0
- // TODO: This tries to load directly from the KQ5CD audio file with MP3/OGG/FLAC
- // compression. Once we got a tool to compress this file AND update the map file
- // at the same time, we can use this code to play compressed audio.
- if (_sciVersion < SCI_VERSION_1_1) {
- uint32 start = offset * 1000 / _audioRate;
- uint32 duration = size * 1000 / _audioRate;
-
- // Try to load compressed
- audioStream = Audio::AudioStream::openStreamFile(filename, start, duration);
- }
- #endif
-
- if (!audioStream) {
- // Compressed file load failed, try to load original raw data
- Common::File* audioFile = new Common::File();
- if (audioFile->open(filename)) {
- audioFile->seek(offset);
-
- if (_sciVersion < SCI_VERSION_1_1) {
- data = (byte *)malloc(size);
- audioFile->read(data, size);
- } else {
- byte type = audioFile->readByte() & 0x7f;
- byte audioFlags;
-
- if (type != kResourceTypeAudio) {
- warning("Resource type mismatch");
- delete audioFile;
- return NULL;
- }
-
- byte headerSize = audioFile->readByte();
-
- if (readSOLHeader(audioFile, headerSize, size, _audioRate, audioFlags))
- data = readSOLAudio(audioFile, size, audioFlags, flags);
-
- if (!data) {
- delete audioFile;
- return NULL;
- }
- }
-
- audioFile->close();
-
- if (data) {
- audioStream = Audio::makeLinearInputStream(data, size, _audioRate,
- flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
- }
- }
+ byte audioFlags;
- delete audioFile;
- }
- } else {
- warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (audioNumber >> 24) & 0xff,
- (audioNumber >> 16) & 0xff, (audioNumber >> 8) & 0xff, audioNumber & 0xff);
+ if (audioRes->headerSize > 0) {
+ // SCI1.1
+ Common::MemoryReadStream *headerStream =
+ new Common::MemoryReadStream(audioRes->header, audioRes->headerSize, false);
+
+ if (readSOLHeader(headerStream, audioRes->headerSize, size, _audioRate, audioFlags)) {
+ Common::MemoryReadStream *dataStream =
+ new Common::MemoryReadStream(audioRes->data, audioRes->size, false);
+ data = readSOLAudio(dataStream, size, audioFlags, flags);
+ delete dataStream;
}
+ delete headerStream;
+ } else {
+ // SCI1
+ size = audioRes->size;
+ data = (byte *)malloc(size);
+ assert(data);
+ memcpy(data, audioRes->data, size);
+ flags = Audio::Mixer::FLAG_UNSIGNED;
}
- if (audioStream) {
- *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
- return audioStream;
+ if (data) {
+ audioStream = Audio::makeLinearInputStream(data, size, _audioRate,
+ flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
+ if (audioStream) {
+ *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
+ return audioStream;
+ }
}
return NULL;
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index fc3f37f25c..e1a7dda921 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -72,19 +72,14 @@ enum {
enum ResSourceType {
kSourceDirectory = 0,
- kSourcePatch = 1,
- kSourceVolume = 2,
- kSourceExtMap = 3,
- kSourceIntMap = 4,
- kSourceAudioVolume = 5,
- kSourceMask = 127
+ kSourcePatch,
+ kSourceVolume,
+ kSourceExtMap,
+ kSourceIntMap,
+ kSourceAudioVolume,
+ kSourceExtAudioMap
};
-#define RESSOURCE_ADDRESSING_BASIC 0
-#define RESSOURCE_ADDRESSING_EXTENDED 128
-#define RESSOURCE_ADDRESSING_MASK 128
-
-#define RESOURCE_HASH(type, number) (uint32)((type<<16) | number)
#define SCI0_RESMAP_ENTRIES_SIZE 6
#define SCI1_RESMAP_ENTRIES_SIZE 6
#define SCI11_RESMAP_ENTRIES_SIZE 5
@@ -136,7 +131,6 @@ struct ResourceSource {
Common::String location_name; // FIXME: Replace by FSNode ?
int volume_number;
ResourceSource *associated_map;
- ResourceSource *next;
};
class ResourceManager;
@@ -270,6 +264,8 @@ public:
*/
Common::List<ResourceId> *listResources(ResourceType type, int mapNumber = -1);
+ void setAudioLanguage(int language);
+
protected:
int _maxMemory; //!< Config option: Maximum total byte number allocated
Common::List<ResourceSource *> _sources;
@@ -278,6 +274,7 @@ protected:
Common::List<Resource *> _LRU; //!< Last Resource Used list
ResourceMap _resMap;
Common::List<Common::File *> _volumeFiles; //!< list of opened volume files
+ ResourceSource *_audioMapSCI1; //!< Currently loaded audio map for SCI1
/**
* Add a path to the resource manager's list of sources.
@@ -325,11 +322,13 @@ protected:
void loadResource(Resource *res);
bool loadPatch(Resource *res, Common::File &file);
bool loadFromPatchFile(Resource *res);
- bool loadFromAudioVolume(Resource *res, Common::File &file);
- void freeOldResources(int last_invulnerable);
+ bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file);
+ bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file);
+ void freeOldResources();
int decompress(Resource *res, Common::File *file);
int readResourceInfo(Resource *res, Common::File *file, uint32&szPacked, ResourceCompression &compression);
void addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size = 0);
+ void removeAudioResource(ResourceId resId);
/**--- Resource map decoding functions ---*/
int detectMapVersion();
@@ -337,21 +336,32 @@ protected:
/**
* Reads the SCI0 resource.map file from a local directory.
+ * @param map The map
* @return 0 on success, an SCI_ERROR_* code otherwise
*/
int readResourceMapSCI0(ResourceSource *map);
/**
* Reads the SCI1 resource.map file from a local directory.
+ * @param map The map
* @return 0 on success, an SCI_ERROR_* code otherwise
*/
int readResourceMapSCI1(ResourceSource *map);
/**
- * Reads SCI1.1 MAP resources
+ * Reads SCI1.1 audio map resources
+ * @param map The map
* @return 0 on success, an SCI_ERROR_* code otherwise
*/
- int readMap(ResourceSource *map);
+ int readAudioMapSCI11(ResourceSource *map);
+
+ /**
+ * Reads SCI1 audio map files
+ * @param map The map
+ * @param unload Unload the map instead of loading it
+ * @return 0 on success, an SCI_ERROR_* code otherwise
+ */
+ int readAudioMapSCI1(ResourceSource *map, bool unload = false);
/**--- Patch management functions ---*/
@@ -393,10 +403,8 @@ protected:
class AudioResource {
public:
AudioResource(ResourceManager *resMgr, int sciVersion);
- ~AudioResource();
void setAudioRate(uint16 audioRate) { _audioRate = audioRate; }
- void setAudioLang(int16 lang);
Audio::SoundHandle* getAudioHandle() { return &_audioHandle; }
int getAudioPosition();
@@ -410,16 +418,8 @@ public:
private:
Audio::SoundHandle _audioHandle;
uint16 _audioRate;
- int16 _lang;
- byte *_audioMapSCI1;
- Resource *_audioMapSCI11;
ResourceManager *_resMgr;
int _sciVersion;
-
- bool findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size);
- bool findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync = false, uint32 *size = NULL);
- bool findAudEntrySCI11Late(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size);
- bool findAudEntrySCI11Early(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size);
};
} // End of namespace Sci