diff options
-rw-r--r-- | engines/kyra/kyra_mr.cpp | 8 | ||||
-rw-r--r-- | engines/kyra/resource.cpp | 43 | ||||
-rw-r--r-- | engines/kyra/resource.h | 4 | ||||
-rw-r--r-- | engines/kyra/sound.cpp | 12 | ||||
-rw-r--r-- | engines/kyra/sound.h | 17 | ||||
-rw-r--r-- | engines/kyra/sound_digital.cpp | 164 |
6 files changed, 187 insertions, 61 deletions
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index c842e318ec..8a49b8e155 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -59,7 +59,7 @@ const KyraEngine_v2::EngineDesc KyraEngine_MR::_mrEngineDesc = { KyraEngine_MR::KyraEngine_MR(OSystem *system, const GameFlags &flags) : KyraEngine_v2(system, flags, _mrEngineDesc) { _soundDigital = 0; _musicSoundChannel = -1; - _menuAudioFile = "TITLE1.AUD"; + _menuAudioFile = "TITLE1"; _lastMusicCommand = -1; _itemBuffer1 = _itemBuffer2 = 0; _scoreFile = 0; @@ -425,7 +425,7 @@ void KyraEngine_MR::snd_playWanderScoreViaMap(int track, int force) { assert(track < _soundListSize && track >= 0); char file[13]; - sprintf(file, "%s.AUD", _soundList[track]); + sprintf(file, "%s", _soundList[track]); _musicSoundChannel = _soundDigital->playSound(file, 0xFF, Audio::Mixer::kMusicSoundType); } @@ -483,7 +483,7 @@ void KyraEngine_MR::snd_playSoundEffect(int item, int volume) { if (_sfxFileMap[item*2+0] != 0xFF) { char filename[16]; assert(_sfxFileMap[item*2+0] < _sfxFileListSize); - snprintf(filename, 16, "%s.AUD", _sfxFileList[_sfxFileMap[item*2+0]]); + snprintf(filename, 16, "%s", _sfxFileList[_sfxFileMap[item*2+0]]); uint8 priority = _sfxFileMap[item*2+1]; _soundDigital->playSound(filename, priority, Audio::Mixer::kSFXSoundType, volume); @@ -498,7 +498,7 @@ void KyraEngine_MR::playVoice(int high, int low) { void KyraEngine_MR::snd_playVoiceFile(int file) { debugC(9, kDebugLevelMain, "KyraEngine_MR::snd_playVoiceFile(%d)", file); char filename[16]; - snprintf(filename, 16, "%u.AUD", (uint)file); + snprintf(filename, 16, "%.08u", (uint)file); _voiceSoundChannel = _soundDigital->playSound(filename, 0xFE, Audio::Mixer::kSpeechSoundType, 255); } diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 46c73c9d3b..01702f08b3 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -543,6 +543,20 @@ bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableRe return true; } +namespace { + +Common::String readString(Common::SeekableReadStream &stream) { + Common::String result; + char c = 0; + + while ((c = stream.readByte()) != 0) + result += c; + + return result; +} + +} // end of anonymous namespace + bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { uint32 filesize = stream.size(); @@ -610,6 +624,33 @@ bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableRead startoffset = endoffset; } + FileList::const_iterator iter = Common::find(files.begin(), files.end(), Common::String("LINKLIST")); + if (iter != files.end()) { + stream.seek(iter->entry.offset, SEEK_SET); + + uint32 magic = stream.readUint32BE(); + + if (magic != MKID_BE('SCVM')) + error("LINKLIST file does not contain 'SCVM' header"); + + uint32 links = stream.readUint32BE(); + for (uint i = 0; i < links; ++i) { + Common::String linksTo = readString(stream); + uint32 sources = stream.readUint32BE(); + + iter = Common::find(files.begin(), files.end(), linksTo); + if (iter == files.end()) + error("PAK file link destination '%s' not found", linksTo.c_str()); + + for (uint j = 0; j < sources; ++j) { + Common::String dest = readString(stream); + files.push_back(File(dest, iter->entry)); + // Better safe than sorry, we update the 'iter' value, in case push_back invalidated it + iter = Common::find(files.begin(), files.end(), linksTo); + } + } + } + return true; } @@ -767,7 +808,7 @@ bool ResLoaderTlk::loadFile(const Common::String &filename, Common::SeekableRead entry.offset = resOffset+4; char realFilename[20]; - snprintf(realFilename, 20, "%u.AUD", resFilename); + snprintf(realFilename, 20, "%.08u.AUD", resFilename); uint32 curOffset = stream.pos(); stream.seek(resOffset, SEEK_SET); diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 167ccd7943..d43f730e6b 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -75,6 +75,10 @@ public: File() : filename(), entry() {} File(const Common::String &f, const ResFileEntry &e) : filename(f), entry(e) {} + bool operator ==(const Common::String &r) const { + return filename.equalsIgnoreCase(r); + } + Common::String filename; ResFileEntry entry; }; diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 8f9077705e..f56c43aabd 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -50,9 +50,9 @@ Sound::~Sound() { bool Sound::voiceFileIsPresent(const char *file) { char filenamebuffer[25]; - for (int i = 0; _supportedCodes[i].fileext; ++i) { + for (int i = 0; _supportedCodecs[i].fileext; ++i) { strcpy(filenamebuffer, file); - strcat(filenamebuffer, _supportedCodes[i].fileext); + strcat(filenamebuffer, _supportedCodecs[i].fileext); if (_vm->resource()->getFileSize(filenamebuffer) > 0) return true; } @@ -77,14 +77,14 @@ int32 Sound::voicePlay(const char *file, bool isSfx) { Audio::AudioStream *audioStream = 0; - for (int i = 0; _supportedCodes[i].fileext; ++i) { + for (int i = 0; _supportedCodecs[i].fileext; ++i) { strcpy(filenamebuffer, file); - strcat(filenamebuffer, _supportedCodes[i].fileext); + strcat(filenamebuffer, _supportedCodecs[i].fileext); Common::SeekableReadStream *stream = _vm->resource()->getFileStream(filenamebuffer); if (!stream) continue; - audioStream = _supportedCodes[i].streamFunc(stream, true, 0, 0, 1); + audioStream = _supportedCodecs[i].streamFunc(stream, true, 0, 0, 1); break; } @@ -551,7 +551,7 @@ bool KyraEngine_v1::snd_voiceIsPlaying() { // static res -const Sound::SpeechCodecs Sound::_supportedCodes[] = { +const Sound::SpeechCodecs Sound::_supportedCodecs[] = { #ifdef USE_FLAC { ".VOF", Audio::makeFlacStream }, #endif // USE_FLAC diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 2427a6cdde..1baeb3064a 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -232,7 +232,7 @@ private: uint numLoops); }; - static const SpeechCodecs _supportedCodes[]; + static const SpeechCodecs _supportedCodecs[]; }; class AdlibDriver; @@ -498,6 +498,7 @@ private: // Digital Audio class AUDStream; +class KyraAudioStream; class KyraEngine_MR; /** @@ -564,8 +565,20 @@ private: char filename[16]; uint8 priority; - AUDStream *stream; + KyraAudioStream *stream; } _sounds[4]; + + struct AudioCodecs { + const char *fileext; + Audio::AudioStream *(*streamFunc)( + Common::SeekableReadStream *stream, + bool disposeAfterUse, + uint32 startTime, + uint32 duration, + uint numLoops); + }; + + static const AudioCodecs _supportedCodecs[]; }; } // end of namespace Kyra diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp index bac7d67129..20f3a7f9f9 100644 --- a/engines/kyra/sound_digital.cpp +++ b/engines/kyra/sound_digital.cpp @@ -29,8 +29,79 @@ #include "sound/audiostream.h" +#include "sound/mp3.h" +#include "sound/vorbis.h" +#include "sound/flac.h" + namespace Kyra { +class KyraAudioStream : public Audio::AudioStream { +public: + KyraAudioStream(Audio::AudioStream *impl) : _impl(impl), _rate(impl->getRate()), _fadeSamples(0), _fadeCount(0), _fading(0), _endOfData(false) {} + ~KyraAudioStream() { delete _impl; _impl = 0; } + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return _impl->isStereo(); } + bool endOfData() const { return _impl->endOfData() | _endOfData; } + int getRate() const { return _rate; } + int32 getTotalPlayTime() const { return _impl->getTotalPlayTime(); } + + void setRate(int newRate) { _rate = newRate; } + void beginFadeOut(uint32 millis); +private: + Audio::AudioStream *_impl; + + int _rate; + + int32 _fadeSamples; + int32 _fadeCount; + int _fading; + + bool _endOfData; +}; + +void KyraAudioStream::beginFadeOut(uint32 millis) { + _fadeSamples = (millis * getRate()) / 1000; + if (_fading == 0) + _fadeCount = _fadeSamples; + _fading = -1; +} + +int KyraAudioStream::readBuffer(int16 *buffer, const int numSamples) { + int samplesRead = _impl->readBuffer(buffer, numSamples); + + if (_fading) { + int samplesProcessed = 0; + for (; samplesProcessed < samplesRead; ++samplesProcessed) { + // To help avoid overflows for long fade times, we divide both + // _fadeSamples and _fadeCount when calculating the new sample. + + int32 div = _fadeSamples / 256; + if (_fading) { + *buffer = (*buffer * (_fadeCount / 256)) / div; + ++buffer; + + _fadeCount += _fading; + + if (_fadeCount < 0) { + _fadeCount = 0; + _endOfData = true; + } else if (_fadeCount > _fadeSamples) { + _fadeCount = _fadeSamples; + _fading = 0; + } + } + } + + if (_endOfData) { + memset(buffer, 0, (samplesRead - samplesProcessed) * sizeof(int16)); + samplesRead = samplesProcessed; + } + } + + return samplesRead; +} + // Thanks to Torbjorn Andersson (eriktorbjorn) for his aud player on which // this code is based on @@ -46,11 +117,7 @@ public: bool isStereo() const { return false; } bool endOfData() const { return _endOfData; } - void setRate(int newRate) { _rate = newRate; } int getRate() const { return _rate; } - - void beginFadeIn(uint32 millis); - void beginFadeOut(uint32 millis); private: Common::SeekableReadStream *_stream; bool _loop; @@ -69,10 +136,6 @@ private: byte *_inBuffer; uint _inBufferSize; - int32 _fadeSamples; - int32 _fadeCount; - int _fading; - int readChunk(int16 *buffer, const int maxSamples); static const int8 WSTable2Bit[]; @@ -93,9 +156,6 @@ AUDStream::AUDStream(Common::SeekableReadStream *stream, bool loop) : _stream(st _totalSize = _stream->readUint32LE(); _loop = loop; - _fadeSamples = 0; - _fading = 0; - // TODO?: add checks int flags = _stream->readByte(); // flags int type = _stream->readByte(); // type @@ -114,20 +174,6 @@ AUDStream::~AUDStream() { delete _stream; } -void AUDStream::beginFadeIn(uint32 millis) { - _fadeSamples = (millis * getRate()) / 1000; - if (_fading == 0) - _fadeCount = 0; - _fading = 1; -} - -void AUDStream::beginFadeOut(uint32 millis) { - _fadeSamples = (millis * getRate()) / 1000; - if (_fading == 0) - _fadeCount = _fadeSamples; - _fading = -1; -} - int AUDStream::readBuffer(int16 *buffer, const int numSamples) { int samplesRead = 0, samplesLeft = numSamples; @@ -288,34 +334,13 @@ int AUDStream::readChunk(int16 *buffer, const int maxSamples) { samplesProcessed += samples; _bytesLeft -= samples; - // To help avoid overflows for long fade times, we divide both - // _fadeSamples and _fadeCount when calculating the new sample. - - int32 div = _fadeSamples / 256; - while (samples--) { int16 sample = (_outBuffer[_outBufferOffset++] << 8) ^ 0x8000; - if (_fading) { - sample = (sample * (_fadeCount / 256)) / div; - _fadeCount += _fading; - - if (_fadeCount < 0) { - _fadeCount = 0; - _endOfData = true; - } else if (_fadeCount > _fadeSamples) { - _fadeCount = _fadeSamples; - _fading = 0; - } - } - *buffer++ = sample; } } - if (_fading < 0 && _fadeCount == 0) - _fading = 0; - return samplesProcessed; } @@ -367,7 +392,19 @@ int SoundDigital::playSound(const char *filename, uint8 priority, Audio::Mixer:: } } - Common::SeekableReadStream *stream = _vm->resource()->getFileStream(filename); + Common::SeekableReadStream *stream = 0; + int usedCodec = -1; + for (int i = 0; _supportedCodecs[i].fileext; ++i) { + Common::String file = filename; + file += _supportedCodecs[i].fileext; + + if (!_vm->resource()->exists(file.c_str())) + continue; + + stream = _vm->resource()->getFileStream(file); + usedCodec = i; + } + if (!stream) { warning("Couldn't find soundfile '%s'", filename); return -1; @@ -375,7 +412,13 @@ int SoundDigital::playSound(const char *filename, uint8 priority, Audio::Mixer:: strncpy(use->filename, filename, sizeof(use->filename)); use->priority = priority; - use->stream = new AUDStream(stream, loop); + Audio::AudioStream *audioStream = _supportedCodecs[usedCodec].streamFunc(stream, true, 0, 0, loop ? 0 : 1); + if (!audioStream) { + warning("Couldn't create audio stream for file '%s'", filename); + return -1; + } + use->stream = new KyraAudioStream(audioStream); + assert(use->stream); if (use->stream->endOfData()) { delete use->stream; use->stream = 0; @@ -428,5 +471,30 @@ void SoundDigital::beginFadeOut(int channel, int ticks) { _sounds[channel].stream->beginFadeOut(ticks * _vm->tickLength()); } +// static res + +namespace { + +Audio::AudioStream *makeAUDStream(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { + return new AUDStream(stream, numLoops == 0 ? true : false); +} + +} // end of anonymous namespace + +const SoundDigital::AudioCodecs SoundDigital::_supportedCodecs[] = { +#ifdef USE_FLAC + { ".FLA", Audio::makeFlacStream }, +#endif // USE_FLAC +#ifdef USE_VORBIS + { ".OGG", Audio::makeVorbisStream }, +#endif // USE_VORBIS +#ifdef USE_MAD + { ".MP3", Audio::makeMP3Stream }, +#endif // USE_MAD + { ".AUD", makeAUDStream }, + { 0, 0 } +}; + + } // end of namespace Kyra |