diff options
-rw-r--r-- | engines/zvision/zork_raw.cpp | 209 | ||||
-rw-r--r-- | engines/zvision/zork_raw.h | 59 |
2 files changed, 131 insertions, 137 deletions
diff --git a/engines/zvision/zork_raw.cpp b/engines/zvision/zork_raw.cpp index d920550bc7..69d8edd8df 100644 --- a/engines/zvision/zork_raw.cpp +++ b/engines/zvision/zork_raw.cpp @@ -22,164 +22,113 @@ #include "common/scummsys.h" -#include "common/endian.h" +#include "common/stream.h" #include "common/memstream.h" -#include "common/textconsole.h" #include "common/util.h" - #include "audio/audiostream.h" #include "engines/zvision/zork_raw.h" namespace ZVision { -#pragma mark - -#pragma mark --- RawZorkStream --- -#pragma mark - - -/** - * This is a stream, which allows for playing raw PCM data from a stream. - */ -class RawZorkStream : public Audio::SeekableAudioStream { -public: - RawZorkStream(int rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) - : _rate(rate), _playtime(0, rate), _stream(stream, disposeStream), _endOfData(false), _buffer(0) { - // Setup our buffer for readBuffer - _buffer = new byte[kSampleBufferLength]; - assert(_buffer); - - // Calculate the total playtime of the stream - _playtime = Audio::Timestamp(0, _stream->size() / 2 / 1, rate); - } - - ~RawZorkStream() { - delete[] _buffer; - } - - int readBuffer(int16 *buffer, const int numSamples); - - bool isStereo() const { return true; } - bool endOfData() const { return _endOfData; } - - int getRate() const { return _rate; } - Audio::Timestamp getLength() const { return _playtime; } - - bool seek(const Audio::Timestamp &where); -private: - const int _rate; ///< Sample rate of stream - Audio::Timestamp _playtime; ///< Calculated total play time - Common::DisposablePtr<Common::SeekableReadStream> _stream; ///< Stream to read data from - bool _endOfData; ///< Whether the stream end has been reached - - byte *_buffer; ///< Buffer used in readBuffer - enum { - /** - * How many samples we can buffer at once. - * - * TODO: Check whether this size suffices - * for systems with slow disk I/O. - */ - kSampleBufferLength = 2048 - }; - - /** - * Fill the temporary sample buffer used in readBuffer. - * - * @param maxSamples Maximum samples to read. - * @return actual count of samples read. - */ - int fillBuffer(int maxSamples); -}; - -int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) { - int samplesLeft = numSamples; - - while (samplesLeft > 0) { - // Try to read up to "samplesLeft" samples. - int len = fillBuffer(samplesLeft); - - // In case we were not able to read any samples - // we will stop reading here. - if (!len) - break; - - // Adjust the samples left to read. - samplesLeft -= len; - - // Copy the data to the caller's buffer. - const byte *src = _buffer; - while (len-- > 0) { - if (*src < 128) - *buffer++ = ((128 - *src) << 8) ^ 0x8000; - else - *buffer++ = (*src << 8) ^ 0x8000; - src++; - } - } - - return numSamples - samplesLeft; +const int16 RawZorkStream::stepAdjustmentTable[8] = {-1, -1, -1, 1, 4, 7, 10, 12}; + +const int32 RawZorkStream::amplitudeLookupTable[89] = {0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, + 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, + 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, + 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, + 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133, + 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, + 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, + 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0, + 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, + 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, + 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF}; + +RawZorkStream::RawZorkStream(uint32 rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) + : _rate(rate), + _stream(stream, disposeStream), + _endOfData(false) { + _lastSample[0] = {0, 0}; + _lastSample[1] = {0, 0}; + + // Calculate the total playtime of the stream + _playtime = Audio::Timestamp(0, _stream->size() / 2, rate); } -int RawZorkStream::fillBuffer(int maxSamples) { - int bufferedSamples = 0; - byte *dst = _buffer; - - // We can only read up to "kSampleBufferLength" samples - // so we take this into consideration, when trying to - // read up to maxSamples. - maxSamples = MIN<int>(kSampleBufferLength, maxSamples); - - // We will only read up to maxSamples - while (maxSamples > 0 && !endOfData()) { - // Try to read all the sample data and update the - // destination pointer. - const int bytesRead = _stream->read(dst, maxSamples); - dst += bytesRead; +int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) { + uint16 bytesRead = 0; - // Calculate how many samples we actually read. - const int samplesRead = bytesRead; + // 0: Left, 1: Right + byte channel = 0; - // Update all status variables - bufferedSamples += samplesRead; - maxSamples -= samplesRead; + while (bytesRead < numSamples) { + byte encodedSample = _stream->readByte(); + bytesRead++; - // We stop stream playback, when we reached the end of the data stream. - // We also stop playback when an error occures. - if (_stream->pos() == _stream->size() || _stream->err() || _stream->eos()) + if (_stream->eos()) { _endOfData = true; + return bytesRead; + } + + uint16 index = _lastSample[channel].index; + uint32 lookUpSample = amplitudeLookupTable[index]; + + int32 sample = 0; + + if (encodedSample & 0x40) + sample += lookUpSample; + if (encodedSample & 0x20) + sample += lookUpSample >> 1; + if (encodedSample & 0x10) + sample += lookUpSample >> 2; + if (encodedSample & 8) + sample += lookUpSample >> 3; + if (encodedSample & 4) + sample += lookUpSample >> 4; + if (encodedSample & 2) + sample += lookUpSample >> 5; + if (encodedSample & 1) + sample += lookUpSample >> 6; + if (encodedSample & 0x80) + sample = -sample; + + sample += _lastSample[channel].sample; + sample = CLIP(sample, -32768, 32767); + + buffer[bytesRead - 1] = (int16)sample; + + index += stepAdjustmentTable[(encodedSample >> 4) & 7]; + index = CLIP<uint16>(index, 0, 88); + + _lastSample[channel].sample = sample; + _lastSample[channel].index = index; + + // Increment and wrap the channel + channel = (channel + 1) & 1; } - return bufferedSamples; + return bytesRead; } -bool RawZorkStream::seek(const Audio::Timestamp &where) { - _endOfData = true; - - if (where > _playtime) - return false; - - const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); - _stream->seek(seekSample, SEEK_SET); - - // In case of an error we will not continue stream playback. - if (!_stream->err() && !_stream->eos() && _stream->pos() != _stream->size()) - _endOfData = false; +bool RawZorkStream::rewind() { + _stream->seek(0, 0); + _stream->clearErr(); + _endOfData = false; + _lastSample[0] = {0, 0}; + _lastSample[1] = {0, 0}; return true; } -#pragma mark - -#pragma mark --- Raw stream factories --- -#pragma mark - - -Audio::SeekableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, +Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, int rate, DisposeAfterUse::Flag disposeAfterUse) { assert(stream->size() % 2 == 0); return new RawZorkStream(rate, disposeAfterUse, stream); } -Audio::SeekableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, +Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, int rate, DisposeAfterUse::Flag disposeAfterUse) { return makeRawZorkStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, DisposeAfterUse::YES); diff --git a/engines/zvision/zork_raw.h b/engines/zvision/zork_raw.h index 1de3b575ba..43cf4d83d0 100644 --- a/engines/zvision/zork_raw.h +++ b/engines/zvision/zork_raw.h @@ -23,19 +23,64 @@ #ifndef ZVISION_ZORK_RAW_H #define ZVISION_ZORK_RAW_H -#include "common/scummsys.h" #include "common/types.h" - -#include "common/list.h" - +#include "audio/audiostream.h" namespace Common { class SeekableReadStream; } namespace ZVision { +/** + * This is a stream, which allows for playing raw ADPCM data from a stream. + */ +class RawZorkStream : public Audio::RewindableAudioStream { +public: + RawZorkStream(uint32 rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream); + + ~RawZorkStream() { + } + +private: + const int _rate; // Sample rate of stream + Audio::Timestamp _playtime; // Calculated total play time + Common::DisposablePtr<Common::SeekableReadStream> _stream; // Stream to read data from + bool _endOfData; // Whether the stream end has been reached + + /** + * Holds the frequency and index from the last sample + * 0 holds the left channel, 1 holds the right channel + */ + struct { + int32 sample; + int16 index; + } _lastSample[2]; + + static const int16 stepAdjustmentTable[8]; + + static const int32 amplitudeLookupTable[89]; + +public: + int readBuffer(int16 *buffer, const int numSamples); + + bool isStereo() const { return true; } + bool endOfData() const { return _endOfData; } + + int getRate() const { return _rate; } + Audio::Timestamp getLength() const { return _playtime; } + + bool rewind(); -class SeekableAudioStream; +private: + /** + * Fill the temporary sample buffer used in readBuffer. + * + * @param maxSamples Maximum samples to read. + * @return actual count of samples read. + */ + int fillBuffer(int maxSamples); + uint32 processBlock(); +}; /** * Creates an audio stream, which plays from the given buffer. @@ -46,7 +91,7 @@ class SeekableAudioStream; * @param disposeAfterUse Whether to free the buffer after use (with free!). * @return The new SeekableAudioStream (or 0 on failure). */ -Audio::SeekableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, +Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, int rate, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); @@ -58,7 +103,7 @@ Audio::SeekableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, * @param disposeAfterUse Whether to delete the stream after use. * @return The new SeekableAudioStream (or 0 on failure). */ -Audio::SeekableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, +Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, int rate, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); |