From d59796fb544fea69d1b2f27f89d6eb30bf5d0780 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 25 May 2009 10:30:19 +0000 Subject: Objectified the AudioResource code (used for speech and digitized music in CD talkie games) svn-id: r40880 --- engines/sci/engine/ksound.cpp | 114 +++++++----------------------------------- engines/sci/resource.cpp | 109 ++++++++++++++++++++++++++++++++++++++++ engines/sci/resource.h | 29 +++++++++++ engines/sci/sfx/core.cpp | 7 +++ engines/sci/sfx/core.h | 3 +- 5 files changed, 166 insertions(+), 96 deletions(-) diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 74a62da356..a5b30d13b2 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -86,11 +86,6 @@ namespace Sci { #define _K_SCI1_SOUND_REVERB 19 /* Get/Set */ #define _K_SCI1_SOUND_UPDATE_VOL_PRI 20 -Audio::SoundHandle _audioHandle; -uint16 _audioRate; -int16 _lang; -byte *_audioMap; - enum AudioCommands { // TODO: find the difference between kSci1AudioWPlay and kSci1AudioPlay kSci1AudioWPlay = 1, /* Plays an audio stream */ @@ -999,33 +994,6 @@ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { return kDoSound_SCI0(s, funct_nr, argc, argv); } -bool findAudEntry(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 (_audioMap == 0) - return false; - - byte *ptr = _audioMap; - while ((n = READ_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; -} - // Used for speech playback in CD games reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) { Audio::Mixer *mixer = g_system->getMixer(); @@ -1034,94 +1002,50 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) { switch (UKPV(0)) { case kSci1AudioWPlay: case kSci1AudioPlay: { - mixer->stopHandle(_audioHandle); + 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); - Audio::AudioStream *audioStream = 0; if (audioRes) { - audioStream = Audio::makeLinearInputStream(audioRes->data, audioRes->size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0); - sampleLen = audioRes->size * 60 / _audioRate; + audioStream = s->sound.audioResource->getAudioStream(audioRes, &sampleLen); } else { // No patch file found, read it from the audio volume - byte volume; - uint32 offset; - uint32 size; - - if (findAudEntry(UKPV(1), volume, offset, size)) { - uint32 start = offset * 1000 / _audioRate; - uint32 duration = size * 1000 / _audioRate; - - char filename[40]; - sprintf(filename, "AUDIO%03d.%03d", _lang, volume); - - // 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; - - audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate, - Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0); - } - } - - sampleLen = size * 60 / _audioRate; - } + audioStream = s->sound.audioResource->getAudioStream(UKPV(1), &sampleLen); } if (audioStream) - mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); - } + mixer->playInputStream(Audio::Mixer::kSpeechSoundType, s->sound.audioResource->getAudioHandle(), audioStream); + } return make_reg(0, sampleLen); // return sample length in ticks case kSci1AudioStop: - mixer->stopHandle(_audioHandle); + s->sound.audioResource->stop(); break; case kSci1AudioPause: - mixer->pauseHandle(_audioHandle, true); + s->sound.audioResource->pause(); break; case kSci1AudioResume: - mixer->pauseHandle(_audioHandle, false); + s->sound.audioResource->resume(); break; case kSci1AudioPosition: - if (mixer->isSoundHandleActive(_audioHandle)) { - return make_reg(0, mixer->getSoundElapsedTime(_audioHandle) * 6 / 100); // return elapsed time in ticks - } else { - return make_reg(0, -1); // Sound finished - } + return make_reg(0, s->sound.audioResource->getAudioPosition()); case kSci1AudioRate: - _audioRate = UKPV(1); + s->sound.audioResource->setAudioRate(UKPV(1)); break; case kSci1AudioVolume: mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, UKPV(1)); break; case kSci1AudioLanguage: - // TODO: CD Audio (used for example in the end credits of KQ6CD) - if (SKPV(1) != -1) { - _lang = UKPV(1); - - char filename[40]; - sprintf(filename, "AUDIO%03d.MAP", _lang); - - Common::File* audioMapFile = new Common::File(); - if (audioMapFile->open(filename)) { - // TODO: This needs to be freed, right now we got a memory leak here! - _audioMap = new byte[audioMapFile->size()]; - audioMapFile->read(_audioMap, audioMapFile->size()); - audioMapFile->close(); - delete audioMapFile; - } else { - _audioMap = 0; - } - } + if (s->sound.audioResource) + delete s->sound.audioResource; + + // The audio resource is freed when freeing all resources + s->sound.audioResource = new AudioResource(); + s->sound.audioResource->setAudioLang(SKPV(1)); + break; default: warning("kDoAudio: Unhandled case %d", UKPV(0)); diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 576b2afc20..e65e1c89d4 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1159,4 +1159,113 @@ void ResourceSync::stopSync() { //syncStarted = false; // not used } + +AudioResource::AudioResource() { + _audioRate = 0; + _lang = 0; + _audioMap = 0; +} + +AudioResource::~AudioResource() { + delete _audioMap; + _audioMap = 0; +} + +void AudioResource::setAudioLang(int16 lang) { + // TODO: CD Audio (used for example in the end credits of KQ6CD) + 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 + _audioMap = new byte[audioMapFile->size()]; + audioMapFile->read(_audioMap, audioMapFile->size()); + audioMapFile->close(); + delete audioMapFile; + } else { + _audioMap = 0; + } + } +} + +int AudioResource::getAudioPosition() { + if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) { + return g_system->getMixer()->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks + } else { + return -1; // Sound finished + } +} + +bool AudioResource::findAudEntry(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 (_audioMap == 0) + return false; + + byte *ptr = _audioMap; + while ((n = READ_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; +} + +Audio::AudioStream* AudioResource::getAudioStream(uint16 audioNumber, int* sampleLen) { + Audio::AudioStream *audioStream = 0; + byte volume; + uint32 offset; + uint32 size; + + if (findAudEntry(audioNumber, volume, offset, size)) { + uint32 start = offset * 1000 / _audioRate; + uint32 duration = size * 1000 / _audioRate; + + char filename[40]; + sprintf(filename, "AUDIO%03d.%03d", _lang, volume); + + // 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; + + audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate, + Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0); + } + } + + *sampleLen = size * 60 / _audioRate; + } + + return audioStream; +} + +Audio::AudioStream* AudioResource::getAudioStream(Resource* audioRes, int* sampleLen) { + *sampleLen = audioRes->size * 60 / _audioRate; + return Audio::makeLinearInputStream(audioRes->data, audioRes->size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0); +} + } // End of namespace Sci diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 8899cbdc6b..f3593ded32 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -30,6 +30,9 @@ #include "common/file.h" #include "common/archive.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" // for SoundHandle + #include "sci/engine/vm.h" // for Object #include "sci/decompressor.h" @@ -299,6 +302,32 @@ protected: //bool _syncStarted; // not used }; +class AudioResource { +public: + AudioResource(); + ~AudioResource(); + + void setAudioRate(uint16 audioRate) { _audioRate = audioRate; } + void setAudioLang(int16 lang); + + Audio::SoundHandle* getAudioHandle() { return &_audioHandle; } + int getAudioPosition(); + Audio::AudioStream* getAudioStream(uint16 audioNumber, int* sampleLen); + Audio::AudioStream* getAudioStream(Resource* audioRes, int* sampleLen); + + void stop() { g_system->getMixer()->stopHandle(_audioHandle); } + void pause() { g_system->getMixer()->pauseHandle(_audioHandle, true); } + void resume() { g_system->getMixer()->pauseHandle(_audioHandle, false); } + +private: + Audio::SoundHandle _audioHandle; + uint16 _audioRate; + int16 _lang; + byte *_audioMap; + + bool findAudEntry(uint16 audioNumber, byte& volume, uint32& offset, uint32& size); +}; + } // End of namespace Sci #endif // SCI_SCICORE_RESOURCE_H diff --git a/engines/sci/sfx/core.cpp b/engines/sci/sfx/core.cpp index 1b4b7e7d96..ccf2052e85 100644 --- a/engines/sci/sfx/core.cpp +++ b/engines/sci/sfx/core.cpp @@ -367,6 +367,7 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) { self->flags = flags; self->debug = 0; /* Disable all debugging by default */ self->soundSync = NULL; + self->audioResource = NULL; if (flags & SFX_STATE_FLAG_NOSOUND) { player = NULL; @@ -443,6 +444,12 @@ void sfx_exit(sfx_state_t *self) { if (strcmp(player->name, "new") == 0) g_system->getMixer()->stopAll(); + + // Delete audio resources for CD talkie games + if (self->audioResource) { + delete self->audioResource; + self->audioResource = 0; + } } void sfx_suspend(sfx_state_t *self, int suspend) { diff --git a/engines/sci/sfx/core.h b/engines/sci/sfx/core.h index acf8c67d70..9c0d25862f 100644 --- a/engines/sci/sfx/core.h +++ b/engines/sci/sfx/core.h @@ -55,7 +55,8 @@ struct sfx_state_t { song_t *song; /* Active song, or start of active song chain */ int suspended; /* Whether we are suspended */ unsigned int debug; /* Debug flags */ - ResourceSync *soundSync; /* Used by kDoSync for speech syncing in talkie games */ + ResourceSync *soundSync; /* Used by kDoSync for speech syncing in CD talkie games */ + AudioResource *audioResource; /* Used for audio resources in CD talkie games */ }; /***********/ -- cgit v1.2.3