[Scummvm-cvs-logs] SF.net SVN: scummvm:[41408] scummvm/trunk/engines/sci

waltervn at users.sourceforge.net waltervn at users.sourceforge.net
Tue Jun 9 21:18:49 CEST 2009


Revision: 41408
          http://scummvm.svn.sourceforge.net/scummvm/?rev=41408&view=rev
Author:   waltervn
Date:     2009-06-09 19:18:48 +0000 (Tue, 09 Jun 2009)

Log Message:
-----------
SCI: Moved SCI1 audio map handling into the resource manager.

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/ksound.cpp
    scummvm/trunk/engines/sci/resource.cpp
    scummvm/trunk/engines/sci/resource.h

Modified: scummvm/trunk/engines/sci/engine/ksound.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/ksound.cpp	2009-06-09 18:53:35 UTC (rev 41407)
+++ scummvm/trunk/engines/sci/engine/ksound.cpp	2009-06-09 19:18:48 UTC (rev 41408)
@@ -1027,7 +1027,7 @@
 			// 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:

Modified: scummvm/trunk/engines/sci/resource.cpp
===================================================================
--- scummvm/trunk/engines/sci/resource.cpp	2009-06-09 18:53:35 UTC (rev 41407)
+++ scummvm/trunk/engines/sci/resource.cpp	2009-06-09 19:18:48 UTC (rev 41408)
@@ -217,7 +217,7 @@
 	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 @@
 	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 @@
 	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 @@
 				else
 					readResourceMapSCI1(source);
 				break;
+			case kSourceExtAudioMap:
+				readAudioMapSCI1(source);
+				break;
 			case kSourceIntMap:
-				readMap(source);
+				readAudioMapSCI11(source);
 				break;
 			default:
 				break;
@@ -460,6 +481,7 @@
 	_LRU.clear();
 	_resMap.clear();
 	_sciVersion = version;
+	_audioMapSCI1 = NULL;
 
 	addAppropriateSources();
 
@@ -607,15 +629,10 @@
 	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 @@
 	// 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 @@
 			addToLRU(retval);
 	}
 
-	freeOldResources(retval->status == kResStatusAllocated);
-
 	if (retval->data)
 		return retval;
 	else {
@@ -695,7 +712,7 @@
 		addToLRU(res);
 	}
 
-	freeOldResources(0);
+	freeOldResources();
 }
 
 int ResourceManager::detectMapVersion() {
@@ -1077,6 +1094,22 @@
 	}
 }
 
+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 @@
 // 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 @@
 	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,44 +1490,8 @@
 	_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() {
 	if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) {
 		return g_system->getMixer()->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks
@@ -1406,33 +1500,6 @@
 	}
 }
 
-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 @@
 
 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 (!audioRes) {
+			warning("Failed to find audio entry %i", audioNumber);
+			return NULL;
 		}
-
-		if (data) {
-			audioStream = Audio::makeLinearInputStream(data, size, _audioRate, 
-											flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
-		}
 	} 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
+	byte audioFlags;
 
-			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 (audioRes->headerSize > 0) {
+		// SCI1.1
+		Common::MemoryReadStream *headerStream = 
+			new Common::MemoryReadStream(audioRes->header, audioRes->headerSize, false);
 
-					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);
-					}
-				}
-
-				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 (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;

Modified: scummvm/trunk/engines/sci/resource.h
===================================================================
--- scummvm/trunk/engines/sci/resource.h	2009-06-09 18:53:35 UTC (rev 41407)
+++ scummvm/trunk/engines/sci/resource.h	2009-06-09 19:18:48 UTC (rev 41408)
@@ -72,19 +72,14 @@
 
 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 @@
 	Common::String location_name;	// FIXME: Replace by FSNode ?
 	int volume_number;
 	ResourceSource *associated_map;
-	ResourceSource *next;
 };
 
 class ResourceManager;
@@ -270,6 +264,8 @@
 	 */
 	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 @@
 	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 @@
 	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,22 +336,33 @@
 
 	/**
 	 * 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 @@
 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 @@
 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


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list