aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2009-05-26 10:02:25 +0000
committerFilippos Karapetis2009-05-26 10:02:25 +0000
commit780899fb0e0be87bd87386fc5f6aeffb4bc30c42 (patch)
tree75c43c31d900466648eb8b0c99f012b39363c662
parent9900cbcb70859741e1df6fd26064a82cbc303302 (diff)
downloadscummvm-rg350-780899fb0e0be87bd87386fc5f6aeffb4bc30c42.tar.gz
scummvm-rg350-780899fb0e0be87bd87386fc5f6aeffb4bc30c42.tar.bz2
scummvm-rg350-780899fb0e0be87bd87386fc5f6aeffb4bc30c42.zip
Rewrote the Audio stream parser. The introduction of KQ6 should work more correctly now (apart from Cassima's speech)
svn-id: r40904
-rw-r--r--engines/sci/engine/ksound.cpp25
-rw-r--r--engines/sci/resource.cpp261
-rw-r--r--engines/sci/resource.h18
3 files changed, 161 insertions, 143 deletions
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 1f7ece33c3..b6ac628a6b 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -1001,37 +1001,18 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int sampleLen = 0;
if (!s->sound.audioResource)
- s->sound.audioResource = new AudioResource();
+ s->sound.audioResource = new AudioResource(s->resmgr, s->version);
switch (UKPV(0)) {
case kSci1AudioWPlay:
case kSci1AudioPlay: {
s->sound.audioResource->stop();
- Audio::AudioStream *audioStream = 0;
-
- // Try to load from an external patch file first
- Sci::Resource* audioRes = s->resmgr->findResource(kResourceTypeAudio, UKPV(1), 1);
-
- if (s->_gameName == "KQ5") {
- if (audioRes) {
- audioStream = s->sound.audioResource->getAudioStreamKQ5CD(audioRes, &sampleLen);
- } else {
- // No patch file found, read it from the audio volume
- audioStream = s->sound.audioResource->getAudioStreamKQ5CD(UKPV(1), &sampleLen);
- }
- } else if (s->_gameName == "Kq6") {
- if (audioRes) {
- audioStream = s->sound.audioResource->getAudioStreamKQ6Floppy(audioRes, &sampleLen);
- } else {
- // No patch file found, read it from the audio volume
- audioStream = s->sound.audioResource->getAudioStreamKQ6Floppy(UKPV(1), &sampleLen);
- }
- }
+ Audio::AudioStream *audioStream =
+ audioStream = s->sound.audioResource->getAudioStream(UKPV(1), &sampleLen);
if (audioStream)
mixer->playInputStream(Audio::Mixer::kSpeechSoundType, s->sound.audioResource->getAudioHandle(), audioStream);
-
}
return make_reg(0, sampleLen); // return sample length in ticks
case kSci1AudioStop:
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 73f4bf7bd2..63c3ee4e8c 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -56,6 +56,13 @@ const char *sci_version_types[] = {
const int sci_max_resource_nr[] = {65536, 1000, 2048, 2048, 2048, 65536, 65536, 65536};
+enum SolFlags {
+ kSolFlagCompressed = 1 << 0,
+ kSolFlagUnknown = 1 << 1,
+ kSolFlag16Bit = 1 << 2,
+ kSolFlagIsSigned = 1 << 3
+};
+
const char *sci_error_types[] = {
"No error",
"I/O error",
@@ -1168,19 +1175,28 @@ void ResourceSync::stopSync() {
}
-AudioResource::AudioResource() {
+AudioResource::AudioResource(ResourceManager *resMgr, int sciVersion) {
+ _resMgr = resMgr;
+ _sciVersion = sciVersion;
_audioRate = 0;
_lang = 0;
- _audioMap = 0;
+ _audioMapSCI1 = 0;
+ _audioMapSCI11 = 0;
}
-AudioResource::~AudioResource() {
- delete[] _audioMap;
- _audioMap = 0;
+AudioResource::~AudioResource() {
+ if (_sciVersion < SCI_VERSION_1_1) {
+ if (_audioMapSCI1) {
+ delete[] _audioMapSCI1;
+ _audioMapSCI1 = 0;
+ }
+ } else {
+ _resMgr->unlockResource(_audioMapSCI11, 65535, kResourceTypeMap);
+ }
}
+// Used in SCI1 games
void AudioResource::setAudioLang(int16 lang) {
- // TODO: CD Audio (used for example in the end credits of KQ6CD)
if (lang != -1) {
_lang = lang;
@@ -1190,12 +1206,12 @@ void AudioResource::setAudioLang(int16 lang) {
Common::File* audioMapFile = new Common::File();
if (audioMapFile->open(filename)) {
// The audio map is freed in the destructor
- _audioMap = new byte[audioMapFile->size()];
- audioMapFile->read(_audioMap, audioMapFile->size());
+ _audioMapSCI1 = new byte[audioMapFile->size()];
+ audioMapFile->read(_audioMapSCI1, audioMapFile->size());
audioMapFile->close();
delete audioMapFile;
} else {
- _audioMap = 0;
+ _audioMapSCI1 = 0;
}
}
}
@@ -1208,7 +1224,7 @@ int AudioResource::getAudioPosition() {
}
}
-bool AudioResource::findAudEntryKQ5CD(uint16 audioNumber, byte& volume, uint32& offset, uint32& size) {
+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)
@@ -1217,10 +1233,10 @@ bool AudioResource::findAudEntryKQ5CD(uint16 audioNumber, byte& volume, uint32&
uint16 n;
uint32 off;
- if (_audioMap == 0)
+ if (_audioMapSCI1 == 0)
return false;
- byte *ptr = _audioMap;
+ byte *ptr = _audioMapSCI1;
while ((n = READ_UINT16(ptr)) != 0xFFFF) {
if (n == audioNumber) {
off = READ_LE_UINT32(ptr + 2);
@@ -1235,131 +1251,154 @@ bool AudioResource::findAudEntryKQ5CD(uint16 audioNumber, byte& volume, uint32&
return false;
}
-Audio::AudioStream* AudioResource::getAudioStreamKQ5CD(uint16 audioNumber, int* sampleLen) {
- Audio::AudioStream *audioStream = 0;
- byte volume;
- uint32 offset;
- uint32 size;
+bool AudioResource::findAudEntrySCI11(uint16 audioNumber, uint32 &offset) {
+ // 65535.MAP contains 6-byte entries:
+ // w nEntry
+ // dw offset
+ // ending with 6 0xFFs
+ uint16 n;
+ offset = 0;
+ uint16 cur = 0;
- if (findAudEntryKQ5CD(audioNumber, volume, offset, size)) {
- uint32 start = offset * 1000 / _audioRate;
- uint32 duration = size * 1000 / _audioRate;
+ if (!_audioMapSCI11)
+ _audioMapSCI11 = _resMgr->findResource(kResourceTypeMap, 65535, 1);
- char filename[40];
- sprintf(filename, "AUDIO%03d.%03d", _lang, volume);
+ byte *ptr = _audioMapSCI11->data;
+ while (cur < _audioMapSCI11->size) {
+ n = READ_UINT16(ptr);
+ offset = READ_UINT32(ptr + 2);
- // Try to load compressed
- audioStream = Audio::AudioStream::openStreamFile(filename, start, duration);
- if (!audioStream) {
- // Compressed file load failed, try to load original raw data
- byte *soundbuff = (byte *)malloc(size);
- Common::File* audioFile = new Common::File();
- if (audioFile->open(filename)) {
- audioFile->seek(offset);
- audioFile->read(soundbuff, size);
- audioFile->close();
- delete audioFile;
+ // Check if we reached the end
+ if (n == 0xFF && offset == 0xFFFF)
+ return false;
- audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate,
- Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0);
- }
- }
+ if (n == audioNumber)
+ return true;
- *sampleLen = size * 60 / _audioRate;
+ ptr += 6;
+ cur += 6;
}
- return audioStream;
+ return false;
}
-bool AudioResource::findAudEntryKQ6Floppy(uint16 audioNumber, uint32& offset) {
- // 65535.MAP contains 8-byte entries:
- // w nEntry
- // dw offset
- // w unknown
- uint16 n;
- offset = 0;
- int cur = 0;
- int fileSize = 0;
-
- // Load audio map
- Common::File* audioMapFile = new Common::File();
- if (audioMapFile->open("65535.map")) {
- _audioMap = new byte[audioMapFile->size()];
- audioMapFile->read(_audioMap, audioMapFile->size());
- fileSize = audioMapFile->size();
- audioMapFile->close();
- delete audioMapFile;
- } else {
- _audioMap = 0;
- return false;
+// Sierra SOL audio file reader
+// Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio
+// TODO: improve this for later versions of the format, as this currently only reads
+// raw PCM encoded files (not ADPCM compressed ones)
+byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16 *audioRate, byte *flags) {
+ byte audioFlags;
+ byte version = audioStream->readByte();
+
+ if (version != 0x8D) {
+ warning("SOL audio version is newer than the expected one");
+ return NULL;
}
- byte *ptr = _audioMap;
- while (cur < fileSize) {
- n = READ_UINT16(ptr);
- if (n == audioNumber) {
- offset = READ_LE_UINT32(ptr + 2);
- delete[] _audioMap;
- _audioMap = 0;
- return true;
- }
- ptr += 8;
- cur += 8;
+ audioStream->readByte(); // skip header size (1 byte), usually 0B (11 bytes)
+ audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes)
+ *audioRate = audioStream->readUint16LE();
+ audioFlags = audioStream->readByte();
+
+ if (audioFlags & kSolFlagCompressed) {
+ warning("ADPCM compressed SOL files are not supported yet");
+ return NULL;
}
- delete[] _audioMap;
- _audioMap = 0;
- return false;
+ // Convert the SOL stream flags to our own format
+ *flags = 0;
+ if (audioFlags & kSolFlag16Bit)
+ *flags |= Audio::Mixer::FLAG_16BITS;
+ if (!(audioFlags & kSolFlagIsSigned))
+ *flags |= Audio::Mixer::FLAG_UNSIGNED;
+
+ *size = audioStream->readUint16LE();
+
+ // We assume that the sound data is raw PCM
+ byte *buffer = new byte[*size];
+ audioStream->read(buffer, *size);
+ return buffer;
}
-Audio::AudioStream* AudioResource::getAudioStreamKQ6Floppy(uint16 audioNumber, int* sampleLen) {
+Audio::AudioStream* AudioResource::getAudioStream(uint16 audioNumber, int *sampleLen) {
Audio::AudioStream *audioStream = 0;
+ byte volume;
uint32 offset;
uint32 size;
+ bool found = false;
+ byte *data = 0;
+ char filename[40];
+ byte flags;
+
+ // Try to load from an external patch file first
+ Sci::Resource* audioRes = _resMgr->findResource(kResourceTypeAudio, audioNumber, 1);
+ if (audioRes) {
+ if (_sciVersion < SCI_VERSION_1_1) {
+ size = audioRes->size;
+ data = audioRes->data;
+ } else {
+ // TODO: this is disabled for now, as for some reason the resource manager returns
+ // only the data chunk of the audio file, and not its headers
+ /*
+ Common::MemoryReadStream *memStream =
+ new Common::MemoryReadStream(audioRes->data, audioRes->size, true);
+ data = readSOLAudio(memStream, &size, &_audioRate, &flags);
+ delete memStream;
+ */
+ }
- if (findAudEntryKQ6Floppy(audioNumber, offset)) {
- Common::File* audioFile = new Common::File();
- if (audioFile->open("resource.aud")) {
- audioFile->seek(offset);
- // Read audio file info
- // Audio files are actually Sierra Audio files.
- // Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio
- audioFile->readByte(); // skip version
- audioFile->readByte(); // skip header size
- audioFile->readUint32LE(); // skip "SOL" + 0
- _audioRate = audioFile->readUint16LE();
- audioFile->readByte(); // skip flags
- size = audioFile->readUint16LE();
- byte *soundbuff = (byte *)malloc(size);
- audioFile->read(soundbuff, size);
- audioFile->close();
- delete audioFile;
-
- audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate,
- Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0);
+ if (data) {
+ *sampleLen = size * 60 / _audioRate;
+ return Audio::makeLinearInputStream(data, size, _audioRate,
+ flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
}
+ }
- *sampleLen = size * 60 / _audioRate;
+ // Patch file not found, load it from the audio file
+ if (_sciVersion < SCI_VERSION_1_1) {
+ found = findAudEntrySCI1(audioNumber, volume, offset, size);
+ sprintf(filename, "AUDIO%03d.%03d", _lang, volume);
+ } else {
+ found = findAudEntrySCI11(audioNumber, offset);
+ strcpy(filename, "RESOURCE.AUD");
}
- return audioStream;
-}
+ if (found) {
+ 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);
+ }
-Audio::AudioStream* AudioResource::getAudioStreamKQ5CD(Resource* audioRes, int* sampleLen) {
- *sampleLen = audioRes->size * 60 / _audioRate;
- return Audio::makeLinearInputStream(audioRes->data, audioRes->size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0);
-}
+ 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);
-Audio::AudioStream* AudioResource::getAudioStreamKQ6Floppy(Resource* audioRes, int* sampleLen) {
- // Read audio file info
- // Audio files are actually Sierra Audio files.
- // Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio
- _audioRate = READ_UINT16(audioRes->data + 6);
- uint32 size = READ_UINT16(audioRes->data + 9);
+ if (_sciVersion < SCI_VERSION_1_1) {
+ data = (byte *)malloc(size);
+ audioFile->read(data, size);
+ } else {
+ data = readSOLAudio(audioFile, &size, &_audioRate, &flags);
+ }
- *sampleLen = size * 60 / _audioRate;
- return Audio::makeLinearInputStream(audioRes->data + 11, size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0);
-}
+ audioFile->close();
+ delete audioFile;
+ if (data) {
+ audioStream = Audio::makeLinearInputStream(data, size, _audioRate,
+ flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
+ }
+ }
+ }
+
+ *sampleLen = size * 60 / _audioRate;
+ }
+
+ return audioStream;
+}
} // End of namespace Sci
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 6f527645a7..60f3ea1d26 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -304,7 +304,7 @@ protected:
class AudioResource {
public:
- AudioResource();
+ AudioResource(ResourceManager *resMgr, int sciVersion);
~AudioResource();
void setAudioRate(uint16 audioRate) { _audioRate = audioRate; }
@@ -313,11 +313,7 @@ public:
Audio::SoundHandle* getAudioHandle() { return &_audioHandle; }
int getAudioPosition();
- // TODO: these need better names
- Audio::AudioStream* getAudioStreamKQ5CD(uint16 audioNumber, int* sampleLen);
- Audio::AudioStream* getAudioStreamKQ5CD(Resource* audioRes, int* sampleLen);
- Audio::AudioStream* getAudioStreamKQ6Floppy(uint16 audioNumber, int* sampleLen);
- Audio::AudioStream* getAudioStreamKQ6Floppy(Resource* audioRes, int* sampleLen);
+ Audio::AudioStream* getAudioStream(uint16 audioNumber, int *sampleLen);
void stop() { g_system->getMixer()->stopHandle(_audioHandle); }
void pause() { g_system->getMixer()->pauseHandle(_audioHandle, true); }
@@ -327,11 +323,13 @@ private:
Audio::SoundHandle _audioHandle;
uint16 _audioRate;
int16 _lang;
- byte *_audioMap;
+ byte *_audioMapSCI1;
+ Resource *_audioMapSCI11;
+ ResourceManager *_resMgr;
+ int _sciVersion;
- // TODO: these need better names
- bool findAudEntryKQ5CD(uint16 audioNumber, byte& volume, uint32& offset, uint32& size);
- bool findAudEntryKQ6Floppy(uint16 audioNumber, uint32& offset);
+ bool findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size);
+ bool findAudEntrySCI11(uint16 audioNumber, uint32 &offset);
};
} // End of namespace Sci