aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kiewitz2010-04-29 15:54:59 +0000
committerMartin Kiewitz2010-04-29 15:54:59 +0000
commit13ee099090f45a1e9383d71d3481247f669d984c (patch)
tree8d5ec55c52f72d89fb9a5e50279300213c472601
parentaa6217223bca3940f1342d35628733c868400be1 (diff)
downloadscummvm-rg350-13ee099090f45a1e9383d71d3481247f669d984c.tar.gz
scummvm-rg350-13ee099090f45a1e9383d71d3481247f669d984c.tar.bz2
scummvm-rg350-13ee099090f45a1e9383d71d3481247f669d984c.zip
SCI: audio compression support
svn-id: r48856
-rw-r--r--engines/sci/resource.cpp86
-rw-r--r--engines/sci/resource.h7
-rw-r--r--engines/sci/sound/audio.cpp82
3 files changed, 146 insertions, 29 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index eee7ba3a47..18d19456e4 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -57,6 +57,8 @@ struct ResourceSource {
const Common::FSNode *resourceFile;
int volume_number;
ResourceSource *associated_map;
+ uint32 audioCompressionType;
+ int32 *audioCompressionOffsetMapping;
};
//////////////////////////////////////////////////////////////////////
@@ -176,6 +178,10 @@ void Resource::writeToStream(Common::WriteStream *stream) const {
stream->write(data, size);
}
+uint32 Resource::getAudioCompressionType() {
+ return _source->audioCompressionType;
+}
+
//-- resMan helper functions --
// Resource source list management
@@ -217,6 +223,10 @@ ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType ty
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 @@ ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType ty
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 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) {
// 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 @@ void ResourceManager::loadResource(Resource *res) {
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",
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index eb1b844071..b9825011e5 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -185,6 +185,7 @@ public:
uint32 _headerSize;
void writeToStream(Common::WriteStream *stream) const;
+ uint32 getAudioCompressionType();
protected:
int32 _fileOffset; /**< Offset in file */
@@ -333,6 +334,12 @@ protected:
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.
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 935427c51a..96a3f1c577 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -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,36 +227,65 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
}
byte audioFlags;
-
- 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);
+ uint32 audioCompressionType = audioRes->getAudioCompressionType();
+
+ 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;
}
+
+ // 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;