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

m_kiewitz at users.sourceforge.net m_kiewitz at users.sourceforge.net
Thu Apr 29 17:55:00 CEST 2010


Revision: 48856
          http://scummvm.svn.sourceforge.net/scummvm/?rev=48856&view=rev
Author:   m_kiewitz
Date:     2010-04-29 15:54:59 +0000 (Thu, 29 Apr 2010)

Log Message:
-----------
SCI: audio compression support

Modified Paths:
--------------
    scummvm/trunk/engines/sci/resource.cpp
    scummvm/trunk/engines/sci/resource.h
    scummvm/trunk/engines/sci/sound/audio.cpp

Modified: scummvm/trunk/engines/sci/resource.cpp
===================================================================
--- scummvm/trunk/engines/sci/resource.cpp	2010-04-29 15:30:09 UTC (rev 48855)
+++ scummvm/trunk/engines/sci/resource.cpp	2010-04-29 15:54:59 UTC (rev 48856)
@@ -57,6 +57,8 @@
 	const Common::FSNode *resourceFile;
 	int volume_number;
 	ResourceSource *associated_map;
+	uint32 audioCompressionType;
+	int32 *audioCompressionOffsetMapping;
 };
 
 //////////////////////////////////////////////////////////////////////
@@ -176,6 +178,10 @@
 	stream->write(data, size);
 }
 
+uint32 Resource::getAudioCompressionType() {
+	return _source->audioCompressionType;
+}
+
 //-- resMan helper functions --
 
 // Resource source list management
@@ -217,6 +223,10 @@
 	newsrc->resourceFile = 0;
 	newsrc->volume_number = number;
 	newsrc->associated_map = map;
+	newsrc->audioCompressionType = 0;
+	newsrc->audioCompressionOffsetMapping = NULL;
+	if (type == kSourceAudioVolume)
+		checkIfAudioVolumeIsCompressed(newsrc);
 
 	_sources.push_back(newsrc);
 	return newsrc;
@@ -231,6 +241,10 @@
 	newsrc->resourceFile = resFile;
 	newsrc->volume_number = number;
 	newsrc->associated_map = map;
+	newsrc->audioCompressionType = 0;
+	newsrc->audioCompressionOffsetMapping = NULL;
+	if (type == kSourceAudioVolume)
+		checkIfAudioVolumeIsCompressed(newsrc);
 
 	_sources.push_back(newsrc);
 	return newsrc;
@@ -260,6 +274,32 @@
 
 // Resource manager constructors and operations
 
+void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
+	Common::File *file = getVolumeFile(source->location_name.c_str());
+	if (!file) {
+		warning("Failed to open %s", source->location_name.c_str());
+		return;
+	}
+	file->seek(0, SEEK_SET);
+	uint32 compressionType = file->readUint32BE();
+	switch (compressionType) {
+	case MKID_BE('MP3 '):
+	case MKID_BE('OGG '):
+	case MKID_BE('FLAC'):
+		// Detected a compressed audio volume
+		source->audioCompressionType = compressionType;
+		// Now read the whole offset mapping table for later usage
+		uint32 recordCount = file->readUint32LE();
+		if (!recordCount)
+			error("compressed audio volume doesn't contain any entries!");
+		source->audioCompressionOffsetMapping = new int32[(recordCount + 1) * 4 * 2];
+		file->read(&source->audioCompressionOffsetMapping, recordCount * 4 * 2);
+		// Put ending zero
+		source->audioCompressionOffsetMapping[recordCount * 2] = 0;
+		source->audioCompressionOffsetMapping[recordCount * 2 + 1] = file->size();
+	}
+}
+
 bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
 	// We assume that the resource type matches res->type
 	file.seek(res->_fileOffset + 2, SEEK_SET);
@@ -408,17 +448,55 @@
 		res->unalloc();
 		return;
 	}
-	file->seek(res->_fileOffset, SEEK_SET);
 
-	if (res->_source->source_type == kSourceWave && loadFromWaveFile(res, *file))
+	switch(res->_source->source_type) {
+	case kSourceWave:
+		file->seek(res->_fileOffset, SEEK_SET);
+		loadFromWaveFile(res, *file);
 		return;
 
-	if (res->_source->source_type == kSourceAudioVolume) {
+	case kSourceAudioVolume:
+		if (res->_source->audioCompressionType) {
+			// this file is compressed, so lookup our offset in the offset-translation table and get the new offset
+			//  also calculate the compressed size by using the next offset
+			int32 *mappingTable = res->_source->audioCompressionOffsetMapping;
+			int32 compressedOffset = 0;
+
+			do {
+				if (*mappingTable == res->_fileOffset) {
+					mappingTable++;
+					compressedOffset = *mappingTable;
+					// Go to next compressed offset and use that to calculate size of compressed sample
+					mappingTable += 2;
+					res->size = *mappingTable - compressedOffset;
+					break;
+				}
+				mappingTable += 2;
+			} while (*mappingTable);
+
+			if (!compressedOffset)
+				error("could not translate offset to compressed offset in audio volume");
+			file->seek(compressedOffset, SEEK_SET);
+
+			switch (res->_id.type) {
+			case kResourceTypeAudio:
+			case kResourceTypeAudio36:
+				// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
+				loadFromAudioVolumeSCI1(res, *file);
+				return;
+			}
+		} else {
+			// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
+			file->seek(res->_fileOffset, SEEK_SET);
+		}
 		if (getSciVersion() < SCI_VERSION_1_1)
 			loadFromAudioVolumeSCI1(res, *file);
 		else
 			loadFromAudioVolumeSCI11(res, *file);
-	} else {
+		return;
+
+	default:
+		file->seek(res->_fileOffset, SEEK_SET);
 		int error = decompress(res, file);
 		if (error) {
 			warning("Error %d occured while reading %s from resource file: %s",

Modified: scummvm/trunk/engines/sci/resource.h
===================================================================
--- scummvm/trunk/engines/sci/resource.h	2010-04-29 15:30:09 UTC (rev 48855)
+++ scummvm/trunk/engines/sci/resource.h	2010-04-29 15:54:59 UTC (rev 48856)
@@ -185,6 +185,7 @@
 	uint32 _headerSize;
 
 	void writeToStream(Common::WriteStream *stream) const;
+	uint32 getAudioCompressionType();
 
 protected:
 	int32 _fileOffset; /**< Offset in file */
@@ -333,6 +334,12 @@
 	ResourceSource *addInternalMap(const char *name, int resNr);
 
 	/**
+	 * Checks, if an audio volume got compressed by our tool. If that's the case, it will set audioCompressionType
+	 *  and read in the offset translation table for later usage.
+	 */
+	void checkIfAudioVolumeIsCompressed(ResourceSource *source);
+
+	/**
 	 * Scans newly registered resource sources for resources, earliest addition first.
 	 * @param detected_version: Pointer to the detected version number,
 	 *					 used during startup. May be NULL.

Modified: scummvm/trunk/engines/sci/sound/audio.cpp
===================================================================
--- scummvm/trunk/engines/sci/sound/audio.cpp	2010-04-29 15:30:09 UTC (rev 48855)
+++ scummvm/trunk/engines/sci/sound/audio.cpp	2010-04-29 15:54:59 UTC (rev 48856)
@@ -36,6 +36,9 @@
 #include "sound/audiocd.h"
 #include "sound/decoders/raw.h"
 #include "sound/decoders/wave.h"
+#include "sound/decoders/flac.h"
+#include "sound/decoders/mp3.h"
+#include "sound/decoders/vorbis.h"
 
 namespace Sci {
 
@@ -224,37 +227,66 @@
 	}
 
 	byte audioFlags;
+	uint32 audioCompressionType = audioRes->getAudioCompressionType();
 
-	if (audioRes->_headerSize > 0) {
-		// SCI1.1
-		Common::MemoryReadStream headerStream(audioRes->_header, audioRes->_headerSize, DisposeAfterUse::NO);
+	if (audioCompressionType) {
+		// Compressed audio made by our tool
+		Common::MemoryReadStream *compressedStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::YES);
+		
+		switch (audioCompressionType) {
+		case MKID_BE('MP3 '):
+#ifdef USE_MAD
+			audioStream = Audio::makeMP3Stream(compressedStream, DisposeAfterUse::YES);
+#endif
+			break;
+		case MKID_BE('OGG '):
+#ifdef USE_VORBIS
+			audioStream = Audio::makeVorbisStream(compressedStream, DisposeAfterUse::YES);
+#endif
+			break;
+		case MKID_BE('FLAC'):
+#ifdef USE_FLAC
+			audioStream = Audio::makeFLACStream(compressedStream, DisposeAfterUse::YES);
+#endif
+			break;
+		}
 
-		if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags)) {
-			Common::MemoryReadStream dataStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
-			data = readSOLAudio(&dataStream, size, audioFlags, flags);
-		}
+		// Hopefully FLAC/OGG/MP3 are always 16-bit, otherwise we will get inaccuracies during sampleLen calculation
+		//  TODO: Check if this is true, otherwise implement support for getting 8-bit/16-bit from stream in common
+		flags = Audio::FLAG_16BITS;
 	} else {
-		// SCI1 or WAVE file
-		if (audioRes->size > 4) {
-			if (memcmp(audioRes->data, "RIFF", 4) == 0) {
-				// WAVE detected
-				Common::MemoryReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
-				audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
+		// Original source file
+		if (audioRes->_headerSize > 0) {
+			// SCI1.1
+			Common::MemoryReadStream headerStream(audioRes->_header, audioRes->_headerSize, DisposeAfterUse::NO);
+
+			if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags)) {
+				Common::MemoryReadStream dataStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+				data = readSOLAudio(&dataStream, size, audioFlags, flags);
 			}
+		} else {
+			// SCI1 or WAVE file
+			if (audioRes->size > 4) {
+				if (memcmp(audioRes->data, "RIFF", 4) == 0) {
+					// WAVE detected
+					Common::MemoryReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+					audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
+				}
+			}
+			if (!audioStream) {
+				// SCI1 raw audio
+				size = audioRes->size;
+				data = (byte *)malloc(size);
+				assert(data);
+				memcpy(data, audioRes->data, size);
+				flags = Audio::FLAG_UNSIGNED;
+			}
 		}
-		if (!audioStream) {
-			// SCI1 raw audio
-			size = audioRes->size;
-			data = (byte *)malloc(size);
-			assert(data);
-			memcpy(data, audioRes->data, size);
-			flags = Audio::FLAG_UNSIGNED;
-		}
+
+		if (data)
+			audioStream = Audio::makeRawStream(data, size, _audioRate, flags);
 	}
 
-	if (data)
-		audioStream = Audio::makeRawStream(data, size, _audioRate, flags);
-
 	if (audioStream) {
 		*sampleLen = (flags & Audio::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
 		return audioStream;


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