diff options
author | Torbjörn Andersson | 2006-05-18 21:46:07 +0000 |
---|---|---|
committer | Torbjörn Andersson | 2006-05-18 21:46:07 +0000 |
commit | 2531fd58737b1e02b32f496ac891e5a96bf95828 (patch) | |
tree | 4b05196eebcff9bd67618bc809d98dee18db1b0a /sound | |
parent | 4ead8dff26c85f76ffcb46e35f8ed8684664713a (diff) | |
download | scummvm-rg350-2531fd58737b1e02b32f496ac891e5a96bf95828.tar.gz scummvm-rg350-2531fd58737b1e02b32f496ac891e5a96bf95828.tar.bz2 scummvm-rg350-2531fd58737b1e02b32f496ac891e5a96bf95828.zip |
Added player for the Kyra 3 VQA cutscenes, based on my earlier prototype. It
could use some cleanup, and there are a couple of TODOs sprinkled throughout
the code, but it seems to work reasonably well. Until the Kyra 3 main menu is
implemented, it won't actually be used though.
It uses the appendable audio stream class, which I have moved out of the SCUMM
engine.
svn-id: r22526
Diffstat (limited to 'sound')
-rw-r--r-- | sound/audiostream.cpp | 144 | ||||
-rw-r--r-- | sound/audiostream.h | 12 |
2 files changed, 156 insertions, 0 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 07115390e8..2f8a5e0d4c 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -214,4 +214,148 @@ AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 } +#pragma mark - +#pragma mark --- Appendable audio stream --- +#pragma mark - + + +/** + * Wrapped memory stream. + */ +template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> +class AppendableMemoryStream : public AppendableAudioStream { +protected: + Common::Mutex _mutex; + + byte *_bufferStart; + byte *_bufferEnd; + byte *_pos; + byte *_end; + bool _finalized; + const int _rate; + + inline bool eosIntern() const { return _end == _pos; }; +public: + AppendableMemoryStream(int rate, uint bufferSize); + ~AppendableMemoryStream(); + int readBuffer(int16 *buffer, const int numSamples); + + bool isStereo() const { return stereo; } + bool endOfStream() const { return _finalized && eosIntern(); } + bool endOfData() const { return eosIntern(); } + + int getRate() const { return _rate; } + + void append(const byte *data, uint32 len); + void finish() { _finalized = true; } +}; + +template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> +AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate, uint bufferSize) + : _finalized(false), _rate(rate) { + + // Verify the buffer size is sane + if (is16Bit && stereo) + assert((bufferSize & 3) == 0); + else if (is16Bit || stereo) + assert((bufferSize & 1) == 0); + + _bufferStart = (byte *)malloc(bufferSize); + _pos = _end = _bufferStart; + _bufferEnd = _bufferStart + bufferSize; +} + +template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> +AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::~AppendableMemoryStream() { + free(_bufferStart); +} + +template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> +int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + + int samples = 0; + while (samples < numSamples && !eosIntern()) { + // Wrap around? + if (_pos >= _bufferEnd) + _pos = _pos - (_bufferEnd - _bufferStart); + + const byte *endMarker = (_pos > _end) ? _bufferEnd : _end; + const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1)); + while (samples < len) { + *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _pos, isLE); + _pos += (is16Bit ? 2 : 1); + samples++; + } + } + + return samples; +} + +template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> +void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::append(const byte *data, uint32 len) { + Common::StackLock lock(_mutex); + + // Verify the buffer size is sane + if (is16Bit && stereo) + assert((len & 3) == 0); + else if (is16Bit || stereo) + assert((len & 1) == 0); + + // Verify that the stream has not yet been finalized (by a call to finish()) + assert(!_finalized); + + if (_end + len > _bufferEnd) { + // Wrap-around case + uint32 size_to_end_of_buffer = _bufferEnd - _end; + len -= size_to_end_of_buffer; + if ((_end < _pos) || (_bufferStart + len >= _pos)) { + debug(2, "AppendableMemoryStream: buffer overflow (A)"); + return; + } + memcpy(_end, data, size_to_end_of_buffer); + memcpy(_bufferStart, data + size_to_end_of_buffer, len); + _end = _bufferStart + len; + } else { + if ((_end < _pos) && (_end + len >= _pos)) { + debug(2, "AppendableMemoryStream: buffer overflow (B)"); + return; + } + memcpy(_end, data, len); + _end += len; + } +} + + +#define MAKE_WRAPPED(STEREO, UNSIGNED) \ + if (is16Bit) { \ + if (isLE) \ + return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate, len); \ + else \ + return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate, len); \ + } else \ + return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate, len) + +AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len) { + const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0; + const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0; + const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0; + const bool isLE = (_flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; + + if (isStereo) { + if (isUnsigned) { + MAKE_WRAPPED(true, true); + } else { + MAKE_WRAPPED(true, false); + } + } else { + if (isUnsigned) { + MAKE_WRAPPED(false, true); + } else { + MAKE_WRAPPED(false, false); + } + } +} + + } // End of namespace Audio diff --git a/sound/audiostream.h b/sound/audiostream.h index 078c8506c5..5aa46f2e85 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -112,6 +112,18 @@ public: AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen); +/** + * An audio stream to which additional data can be appended on-the-fly. + * Used by SMUSH, iMuseDigital, and the Kyrandia 3 VQA player. + */ +class AppendableAudioStream : public Audio::AudioStream { +public: + virtual void append(const byte *data, uint32 len) = 0; + virtual void finish() = 0; +}; + +AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len); + // This used to be an inline template function, but // buggy template function handling in MSVC6 forced |