diff options
author | Matthew Hoops | 2011-05-03 17:17:27 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-05-03 17:25:41 -0400 |
commit | 9cb600099f4c29298707787cafad2741a1cd6686 (patch) | |
tree | fb1930fa56b611317831d66442cba19b18d2e57a /audio/decoders | |
parent | 3b2283daf850605ca897002afbafe44489c35473 (diff) | |
parent | 95a6098f672191dc0792bd4f9bfa18706bbe8e3a (diff) | |
download | scummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.tar.gz scummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.tar.bz2 scummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.zip |
Merge remote branch 'upstream/master' into pegasus
Diffstat (limited to 'audio/decoders')
-rw-r--r-- | audio/decoders/adpcm.cpp | 489 | ||||
-rw-r--r-- | audio/decoders/adpcm.h | 13 | ||||
-rw-r--r-- | audio/decoders/adpcm_intern.h | 242 | ||||
-rw-r--r-- | audio/decoders/aiff.cpp | 4 | ||||
-rw-r--r-- | audio/decoders/aiff.h | 4 | ||||
-rw-r--r-- | audio/decoders/flac.cpp | 1 | ||||
-rw-r--r-- | audio/decoders/flac.h | 3 | ||||
-rw-r--r-- | audio/decoders/iff_sound.cpp | 1 | ||||
-rw-r--r-- | audio/decoders/iff_sound.h | 2 | ||||
-rw-r--r-- | audio/decoders/mac_snd.cpp | 3 | ||||
-rw-r--r-- | audio/decoders/mac_snd.h | 4 | ||||
-rw-r--r-- | audio/decoders/mp3.cpp | 1 | ||||
-rw-r--r-- | audio/decoders/mp3.h | 3 | ||||
-rw-r--r-- | audio/decoders/raw.cpp | 3 | ||||
-rw-r--r-- | audio/decoders/raw.h | 6 | ||||
-rw-r--r-- | audio/decoders/vag.h | 3 | ||||
-rw-r--r-- | audio/decoders/voc.cpp | 2 | ||||
-rw-r--r-- | audio/decoders/voc.h | 6 | ||||
-rw-r--r-- | audio/decoders/vorbis.cpp | 6 | ||||
-rw-r--r-- | audio/decoders/vorbis.h | 3 | ||||
-rw-r--r-- | audio/decoders/wave.cpp | 3 | ||||
-rw-r--r-- | audio/decoders/wave.h | 4 |
22 files changed, 327 insertions, 479 deletions
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp index 7def89b688..a9284973d5 100644 --- a/audio/decoders/adpcm.cpp +++ b/audio/decoders/adpcm.cpp @@ -23,47 +23,16 @@ * */ -#include "common/endian.h" +#include "common/stream.h" +#include "common/textconsole.h" +#include "common/util.h" #include "audio/decoders/adpcm.h" -#include "audio/audiostream.h" +#include "audio/decoders/adpcm_intern.h" namespace Audio { -class ADPCMStream : public RewindableAudioStream { -protected: - Common::SeekableReadStream *_stream; - const DisposeAfterUse::Flag _disposeAfterUse; - const int32 _startpos; - const int32 _endpos; - const int _channels; - const uint32 _blockAlign; - uint32 _blockPos[2]; - const int _rate; - - struct { - // OKI/IMA - struct { - int32 last; - int32 stepIndex; - } ima_ch[2]; - } _status; - - virtual void reset(); - int16 stepAdjust(byte); - -public: - ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign); - ~ADPCMStream(); - - virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } - virtual bool isStereo() const { return _channels == 2; } - virtual int getRate() const { return _rate; } - - virtual bool rewind(); -}; - // Routines to convert 12 bit linear samples to the // Dialogic or Oki ADPCM coding format aka VOX. // See also <http://www.comptek.ru/telephony/tnotes/tt1-13.html> @@ -107,17 +76,6 @@ bool ADPCMStream::rewind() { #pragma mark - -class Oki_ADPCMStream : public ADPCMStream { -public: - Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); - -protected: - int16 decodeOKI(byte); -}; - int Oki_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { int samples; byte data; @@ -153,7 +111,7 @@ int16 Oki_ADPCMStream::decodeOKI(byte code) { samp = CLIP<int16>(samp, -2048, 2047); _status.ima_ch[0].last = samp; - _status.ima_ch[0].stepIndex += stepAdjust(code); + _status.ima_ch[0].stepIndex += _stepAdjustTable[code]; _status.ima_ch[0].stepIndex = CLIP<int32>(_status.ima_ch[0].stepIndex, 0, ARRAYSIZE(okiStepSize) - 1); // * 16 effectively converts 12-bit input to 16-bit output @@ -164,20 +122,7 @@ int16 Oki_ADPCMStream::decodeOKI(byte code) { #pragma mark - -class Ima_ADPCMStream : public ADPCMStream { -protected: - int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel - -public: - Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - memset(&_status, 0, sizeof(_status)); - } - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Ima_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { +int DVI_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { int samples; byte data; @@ -194,34 +139,6 @@ int Ima_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { #pragma mark - -class Apple_ADPCMStream : public Ima_ADPCMStream { -protected: - // Apple QuickTime IMA ADPCM - int32 _streamPos[2]; - int16 _buffer[2][2]; - uint8 _chunkPos[2]; - - void reset() { - Ima_ADPCMStream::reset(); - _chunkPos[0] = 0; - _chunkPos[1] = 0; - _streamPos[0] = 0; - _streamPos[1] = _blockAlign; - } - -public: - Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - _chunkPos[0] = 0; - _chunkPos[1] = 0; - _streamPos[0] = 0; - _streamPos[1] = _blockAlign; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -}; - int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { // Need to write at least one samples per channel assert((numSamples % _channels) == 0); @@ -285,82 +202,49 @@ int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { return samples[0] + samples[1]; } -#pragma mark - +#pragma mark - -class MSIma_ADPCMStream : public Ima_ADPCMStream { -public: - MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign, bool invertSamples = false) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign), _invertSamples(invertSamples) { - if (blockAlign == 0) - error("ADPCMStream(): blockAlign isn't specified for MS IMA ADPCM"); - } - - virtual int readBuffer(int16 *buffer, const int numSamples) { - if (_channels == 1) - return readBufferMSIMA1(buffer, numSamples); - else - return readBufferMSIMA2(buffer, numSamples); - } - - int readBufferMSIMA1(int16 *buffer, const int numSamples); - int readBufferMSIMA2(int16 *buffer, const int numSamples); -private: - bool _invertSamples; // Some implementations invert the way samples are decoded -}; +int MSIma_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { + // Need to write at least one sample per channel + assert((numSamples % _channels) == 0); -int MSIma_ADPCMStream::readBufferMSIMA1(int16 *buffer, const int numSamples) { int samples = 0; - byte data; - - assert(numSamples % 2 == 0); while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { if (_blockPos[0] == _blockAlign) { - // read block header - _status.ima_ch[0].last = _stream->readSint16LE(); - _status.ima_ch[0].stepIndex = _stream->readSint16LE(); - _blockPos[0] = 4; - } + for (int i = 0; i < _channels; i++) { + // read block header + _status.ima_ch[i].last = _stream->readSint16LE(); + _status.ima_ch[i].stepIndex = _stream->readSint16LE(); + } - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) { - data = _stream->readByte(); - _blockPos[0]++; - buffer[samples] = decodeIMA(_invertSamples ? (data >> 4) & 0x0f : data & 0x0f); - buffer[samples + 1] = decodeIMA(_invertSamples ? data & 0x0f : (data >> 4) & 0x0f); + _blockPos[0] = _channels * 4; } - } - return samples; -} + // Decode a set of samples + for (int i = 0; i < _channels; i++) { + // The stream encodes four bytes per channel at a time + for (int j = 0; j < 4; j++) { + byte data = _stream->readByte(); + _blockPos[0]++; + _buffer[i][j * 2] = decodeIMA(data & 0x0f, i); + _buffer[i][j * 2 + 1] = decodeIMA((data >> 4) & 0x0f, i); + _samplesLeft[i] += 2; + } + } -// Microsoft as usual tries to implement it differently. This method -// is used for stereo data. -int MSIma_ADPCMStream::readBufferMSIMA2(int16 *buffer, const int numSamples) { - int samples; - uint32 data; - int nibble; - byte k; - - // TODO: Currently this implementation only supports - // reading a multiple of 16 samples at once. We might - // consider changing that so it could read an arbitrary - // sample pair count. - assert(numSamples % 16 == 0); - - for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos;) { - for (int channel = 0; channel < 2; channel++) { - data = _stream->readUint32LE(); - - for (nibble = 0; nibble < 8; nibble++) { - k = ((data & 0xf0000000) >> 28); - buffer[samples + channel + nibble * 2] = decodeIMA(k); - data <<= 4; + while (samples < numSamples && _samplesLeft[0] != 0) { + for (int i = 0; i < _channels; i++) { + buffer[samples] = _buffer[i][8 - _samplesLeft[i]]; + _samplesLeft[i]--; } + + samples += _channels; } - samples += 16; } + return samples; } @@ -382,41 +266,6 @@ static const int MSADPCMAdaptationTable[] = { }; -class MS_ADPCMStream : public ADPCMStream { -protected: - struct ADPCMChannelStatus { - byte predictor; - int16 delta; - int16 coeff1; - int16 coeff2; - int16 sample1; - int16 sample2; - }; - - struct { - // MS ADPCM - ADPCMChannelStatus ch[2]; - } _status; - - void reset() { - ADPCMStream::reset(); - memset(&_status, 0, sizeof(_status)); - } - -public: - MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - if (blockAlign == 0) - error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); - memset(&_status, 0, sizeof(_status)); - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -protected: - int16 decodeMS(ADPCMChannelStatus *c, byte); -}; - int16 MS_ADPCMStream::decodeMS(ADPCMChannelStatus *c, byte code) { int32 predictor; @@ -478,246 +327,9 @@ int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { } - #pragma mark - -class Tinsel_ADPCMStream : public ADPCMStream { -protected: - struct { - // Tinsel - double predictor; - double K0, K1; - double d0, d1; - } _status; - - void reset() { - ADPCMStream::reset(); - memset(&_status, 0, sizeof(_status)); - } - - int16 decodeTinsel(int16, double); - void readBufferTinselHeader(); - -public: - Tinsel_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - - if (blockAlign == 0) - error("Tinsel_ADPCMStream(): blockAlign isn't specified"); - - if (channels != 1) - error("Tinsel_ADPCMStream(): Tinsel ADPCM only supports mono"); - - memset(&_status, 0, sizeof(_status)); - } - -}; - -static const double TinselFilterTable[4][2] = { - {0, 0 }, - {0.9375, 0}, - {1.796875, -0.8125}, - {1.53125, -0.859375} -}; - -void Tinsel_ADPCMStream::readBufferTinselHeader() { - uint8 start = _stream->readByte(); - uint8 filterVal = (start & 0xC0) >> 6; - - if ((start & 0x20) != 0) { - //Lower 6 bit are negative - - // Negate - start = ~(start | 0xC0) + 1; - - _status.predictor = 1 << start; - } else { - // Lower 6 bit are positive - - // Truncate - start &= 0x1F; - - _status.predictor = ((double) 1.0) / (1 << start); - } - - _status.K0 = TinselFilterTable[filterVal][0]; - _status.K1 = TinselFilterTable[filterVal][1]; -} - -int16 Tinsel_ADPCMStream::decodeTinsel(int16 code, double eVal) { - double sample; - - sample = (double) code; - sample *= eVal * _status.predictor; - sample += (_status.d0 * _status.K0) + (_status.d1 * _status.K1); - - _status.d1 = _status.d0; - _status.d0 = sample; - - return (int16) CLIP<double>(sample, -32768.0, 32767.0); -} - -class Tinsel4_ADPCMStream : public Tinsel_ADPCMStream { -public: - Tinsel4_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel4_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - uint16 data; - const double eVal = 1.142822265; - - samples = 0; - - assert(numSamples % 2 == 0); - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2, _blockPos[0]++) { - // Read 1 byte = 8 bits = two 4 bit blocks - data = _stream->readByte(); - buffer[samples] = decodeTinsel((data << 8) & 0xF000, eVal); - buffer[samples+1] = decodeTinsel((data << 12) & 0xF000, eVal); - } - } - - return samples; -} - -class Tinsel6_ADPCMStream : public Tinsel_ADPCMStream { -protected: - uint8 _chunkPos; - uint16 _chunkData; - - void reset() { - ADPCMStream::reset(); - _chunkPos = 0; - _chunkData = 0; - } - -public: - Tinsel6_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - _chunkPos = 0; - _chunkData = 0; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel6_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - const double eVal = 1.032226562; - - samples = 0; - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - _chunkPos = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _chunkPos = (_chunkPos + 1) % 4) { - - switch (_chunkPos) { - case 0: - _chunkData = _stream->readByte(); - buffer[samples] = decodeTinsel((_chunkData << 8) & 0xFC00, eVal); - break; - case 1: - _chunkData = (_chunkData << 8) | (_stream->readByte()); - buffer[samples] = decodeTinsel((_chunkData << 6) & 0xFC00, eVal); - _blockPos[0]++; - break; - case 2: - _chunkData = (_chunkData << 8) | (_stream->readByte()); - buffer[samples] = decodeTinsel((_chunkData << 4) & 0xFC00, eVal); - _blockPos[0]++; - break; - case 3: - _chunkData = (_chunkData << 8); - buffer[samples] = decodeTinsel((_chunkData << 2) & 0xFC00, eVal); - _blockPos[0]++; - break; - } - - } - - } - - return samples; -} - -class Tinsel8_ADPCMStream : public Tinsel_ADPCMStream { -public: - Tinsel8_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} - - virtual int readBuffer(int16 *buffer, const int numSamples); -}; - -int Tinsel8_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { - int samples; - byte data; - const double eVal = 1.007843258; - - samples = 0; - - while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) { - if (_blockPos[0] == _blockAlign) { - readBufferTinselHeader(); - _blockPos[0] = 0; - } - - for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _blockPos[0]++) { - // Read 1 byte = 8 bits = one 8 bit block - data = _stream->readByte(); - buffer[samples] = decodeTinsel(data << 8, eVal); - } - } - - return samples; -} - - -#pragma mark - - -// Duck DK3 IMA ADPCM Decoder -// Based on FFmpeg's decoder and http://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM - -class DK3_ADPCMStream : public Ima_ADPCMStream { -protected: - - void reset() { - Ima_ADPCMStream::reset(); - _topNibble = false; - } - -public: - DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - - // DK3 only works as a stereo stream - assert(channels == 2); - _topNibble = false; - } - - virtual int readBuffer(int16 *buffer, const int numSamples); - -private: - byte _nibble, _lastByte; - bool _topNibble; -}; - #define DK3_READ_NIBBLE() \ do { \ if (_topNibble) { \ @@ -782,14 +394,15 @@ int DK3_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) { #pragma mark - -// adjust the step for use on the next sample. -int16 ADPCMStream::stepAdjust(byte code) { - static const int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8}; - - return adjusts[code & 0x07]; -} +// This table is used to adjust the step for use on the next sample. +// We could half the table, but since the lookup index used is always +// a 4-bit nibble, it's more efficient to just keep it as it is. +const int16 ADPCMStream::_stepAdjustTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; -static const uint16 imaStepTable[89] = { +const int16 Ima_ADPCMStream::_imaTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, @@ -805,13 +418,13 @@ static const uint16 imaStepTable[89] = { }; int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) { - int32 E = (2 * (code & 0x7) + 1) * imaStepTable[_status.ima_ch[channel].stepIndex] / 8; + int32 E = (2 * (code & 0x7) + 1) * _imaTable[_status.ima_ch[channel].stepIndex] / 8; int32 diff = (code & 0x08) ? -E : E; int32 samp = CLIP<int32>(_status.ima_ch[channel].last + diff, -32768, 32767); _status.ima_ch[channel].last = samp; - _status.ima_ch[channel].stepIndex += stepAdjust(code); - _status.ima_ch[channel].stepIndex = CLIP<int32>(_status.ima_ch[channel].stepIndex, 0, ARRAYSIZE(imaStepTable) - 1); + _status.ima_ch[channel].stepIndex += _stepAdjustTable[code]; + _status.ima_ch[channel].stepIndex = CLIP<int32>(_status.ima_ch[channel].stepIndex, 0, ARRAYSIZE(_imaTable) - 1); return samp; } @@ -826,18 +439,10 @@ RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, Dispo return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); case kADPCMMSIma: return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMMSImaLastExpress: - return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign, true); case kADPCMMS: return new MS_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel4: - return new Tinsel4_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel6: - return new Tinsel6_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMTinsel8: - return new Tinsel8_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); - case kADPCMIma: - return new Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); + case kADPCMDVI: + return new DVI_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); case kADPCMApple: return new Apple_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); case kADPCMDK3: diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h index 38ec870a27..10344101e2 100644 --- a/audio/decoders/adpcm.h +++ b/audio/decoders/adpcm.h @@ -38,12 +38,15 @@ #define SOUND_ADPCM_H #include "common/scummsys.h" -#include "common/stream.h" +#include "common/types.h" + +namespace Common { +class SeekableReadStream; +} namespace Audio { -class AudioStream; class RewindableAudioStream; // There are several types of ADPCM encoding, only some are supported here @@ -54,12 +57,8 @@ class RewindableAudioStream; enum typesADPCM { kADPCMOki, // Dialogic/Oki ADPCM (aka VOX) kADPCMMSIma, // Microsoft IMA ADPCM - kADPCMMSImaLastExpress, // Microsoft IMA ADPCM (with inverted samples) kADPCMMS, // Microsoft ADPCM - kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine - kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine - kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine - kADPCMIma, // Standard IMA ADPCM + kADPCMDVI, // Intel DVI IMA ADPCM kADPCMApple, // Apple QuickTime IMA ADPCM kADPCMDK3 // Duck DK3 IMA ADPCM }; diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h new file mode 100644 index 0000000000..f875bd88c7 --- /dev/null +++ b/audio/decoders/adpcm_intern.h @@ -0,0 +1,242 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/** + * Internal interfaces to the ADPCM decoders. + * + * These can be used to make custom ADPCM decoder subclasses, + * or to at least share some common data tables between various + * ADPCM decoder implementations. + */ + +#ifndef SOUND_ADPCM_INTERN_H +#define SOUND_ADPCM_INTERN_H + +#include "audio/audiostream.h" +#include "common/endian.h" +#include "common/stream.h" +#include "common/textconsole.h" + + +namespace Audio { + +class ADPCMStream : public RewindableAudioStream { +protected: + Common::SeekableReadStream *_stream; + const DisposeAfterUse::Flag _disposeAfterUse; + const int32 _startpos; + const int32 _endpos; + const int _channels; + const uint32 _blockAlign; + uint32 _blockPos[2]; + const int _rate; + + struct ADPCMStatus { + // OKI/IMA + struct { + int32 last; + int32 stepIndex; + } ima_ch[2]; + } _status; + + virtual void reset(); + +public: + ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign); + ~ADPCMStream(); + + virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } + virtual bool isStereo() const { return _channels == 2; } + virtual int getRate() const { return _rate; } + + virtual bool rewind(); + + + /** + * This table is used by some ADPCM variants (IMA and OKI) to adjust the + * step for use on the next sample. + * The first 8 entries are identical to the second 8 entries. Hence, we + * could half the table in size. But since the lookup index is always a + * 4-bit nibble, it is more efficient to just keep it as it is. + */ + static const int16 _stepAdjustTable[16]; +}; + +class Oki_ADPCMStream : public ADPCMStream { +public: + Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} + + virtual int readBuffer(int16 *buffer, const int numSamples); + +protected: + int16 decodeOKI(byte); +}; + +class Ima_ADPCMStream : public ADPCMStream { +protected: + int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel + +public: + Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { + memset(&_status, 0, sizeof(_status)); + } + + /** + * This table is used by decodeIMA. + */ + static const int16 _imaTable[89]; +}; + +class DVI_ADPCMStream : public Ima_ADPCMStream { +public: + DVI_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} + + virtual int readBuffer(int16 *buffer, const int numSamples); +}; + +class Apple_ADPCMStream : public Ima_ADPCMStream { +protected: + // Apple QuickTime IMA ADPCM + int32 _streamPos[2]; + int16 _buffer[2][2]; + uint8 _chunkPos[2]; + + void reset() { + Ima_ADPCMStream::reset(); + _chunkPos[0] = 0; + _chunkPos[1] = 0; + _streamPos[0] = 0; + _streamPos[1] = _blockAlign; + } + +public: + Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { + _chunkPos[0] = 0; + _chunkPos[1] = 0; + _streamPos[0] = 0; + _streamPos[1] = _blockAlign; + } + + virtual int readBuffer(int16 *buffer, const int numSamples); + +}; + +class MSIma_ADPCMStream : public Ima_ADPCMStream { +public: + MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { + + if (blockAlign == 0) + error("MSIma_ADPCMStream(): blockAlign isn't specified"); + + if (blockAlign % (_channels * 4)) + error("MSIma_ADPCMStream(): invalid blockAlign"); + + _samplesLeft[0] = 0; + _samplesLeft[1] = 0; + } + + virtual int readBuffer(int16 *buffer, const int numSamples); + + void reset() { + Ima_ADPCMStream::reset(); + _samplesLeft[0] = 0; + _samplesLeft[1] = 0; + } + +private: + int16 _buffer[2][8]; + int _samplesLeft[2]; +}; + +class MS_ADPCMStream : public ADPCMStream { +protected: + struct ADPCMChannelStatus { + byte predictor; + int16 delta; + int16 coeff1; + int16 coeff2; + int16 sample1; + int16 sample2; + }; + + struct { + // MS ADPCM + ADPCMChannelStatus ch[2]; + } _status; + + void reset() { + ADPCMStream::reset(); + memset(&_status, 0, sizeof(_status)); + } + +public: + MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { + if (blockAlign == 0) + error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); + memset(&_status, 0, sizeof(_status)); + } + + virtual int readBuffer(int16 *buffer, const int numSamples); + +protected: + int16 decodeMS(ADPCMChannelStatus *c, byte); +}; + +// Duck DK3 IMA ADPCM Decoder +// Based on FFmpeg's decoder and http://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM + +class DK3_ADPCMStream : public Ima_ADPCMStream { +protected: + + void reset() { + Ima_ADPCMStream::reset(); + _topNibble = false; + } + +public: + DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) + : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { + + // DK3 only works as a stereo stream + assert(channels == 2); + _topNibble = false; + } + + virtual int readBuffer(int16 *buffer, const int numSamples); + +private: + byte _nibble, _lastByte; + bool _topNibble; +}; + +} // End of namespace Audio + +#endif diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp index 0f947752f6..957fb13638 100644 --- a/audio/decoders/aiff.cpp +++ b/audio/decoders/aiff.cpp @@ -32,12 +32,10 @@ */ #include "common/endian.h" -#include "common/util.h" #include "common/stream.h" +#include "common/textconsole.h" #include "audio/decoders/aiff.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/raw.h" namespace Audio { diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h index 06c56ecd38..dddbffb520 100644 --- a/audio/decoders/aiff.h +++ b/audio/decoders/aiff.h @@ -37,7 +37,9 @@ #include "common/scummsys.h" #include "common/types.h" -namespace Common { class SeekableReadStream; } +namespace Common { +class SeekableReadStream; +} namespace Audio { diff --git a/audio/decoders/flac.cpp b/audio/decoders/flac.cpp index 76b6d35419..fe15877ac6 100644 --- a/audio/decoders/flac.cpp +++ b/audio/decoders/flac.cpp @@ -32,6 +32,7 @@ #include "common/debug.h" #include "common/stream.h" +#include "common/textconsole.h" #include "common/util.h" #include "audio/audiostream.h" diff --git a/audio/decoders/flac.h b/audio/decoders/flac.h index 17f95ec1fb..69222f22a1 100644 --- a/audio/decoders/flac.h +++ b/audio/decoders/flac.h @@ -49,12 +49,11 @@ #ifdef USE_FLAC namespace Common { - class SeekableReadStream; +class SeekableReadStream; } namespace Audio { -class AudioStream; class SeekableAudioStream; /** diff --git a/audio/decoders/iff_sound.cpp b/audio/decoders/iff_sound.cpp index 2ec189c586..8efe017e75 100644 --- a/audio/decoders/iff_sound.cpp +++ b/audio/decoders/iff_sound.cpp @@ -25,7 +25,6 @@ #include "audio/decoders/iff_sound.h" #include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/raw.h" #include "common/iff_container.h" #include "common/func.h" diff --git a/audio/decoders/iff_sound.h b/audio/decoders/iff_sound.h index 4e53059380..4d26b32e71 100644 --- a/audio/decoders/iff_sound.h +++ b/audio/decoders/iff_sound.h @@ -33,7 +33,7 @@ #define SOUND_IFF_H namespace Common { - class ReadStream; +class ReadStream; } namespace Audio { diff --git a/audio/decoders/mac_snd.cpp b/audio/decoders/mac_snd.cpp index 7c1a2f75f0..fc69988860 100644 --- a/audio/decoders/mac_snd.cpp +++ b/audio/decoders/mac_snd.cpp @@ -30,11 +30,10 @@ * We implement both type 1 and type 2 snd resources, but only those that are sampled */ -#include "common/util.h" +#include "common/textconsole.h" #include "common/stream.h" #include "audio/decoders/mac_snd.h" -#include "audio/audiostream.h" #include "audio/decoders/raw.h" namespace Audio { diff --git a/audio/decoders/mac_snd.h b/audio/decoders/mac_snd.h index 198a61333e..bf6331a265 100644 --- a/audio/decoders/mac_snd.h +++ b/audio/decoders/mac_snd.h @@ -35,7 +35,9 @@ #include "common/scummsys.h" #include "common/types.h" -namespace Common { class SeekableReadStream; } +namespace Common { +class SeekableReadStream; +} namespace Audio { diff --git a/audio/decoders/mp3.cpp b/audio/decoders/mp3.cpp index 53d68fa9db..91bd49873a 100644 --- a/audio/decoders/mp3.cpp +++ b/audio/decoders/mp3.cpp @@ -29,6 +29,7 @@ #include "common/debug.h" #include "common/stream.h" +#include "common/textconsole.h" #include "common/util.h" #include "audio/audiostream.h" diff --git a/audio/decoders/mp3.h b/audio/decoders/mp3.h index 72bc6e1b3e..d3a5b70d45 100644 --- a/audio/decoders/mp3.h +++ b/audio/decoders/mp3.h @@ -50,12 +50,11 @@ #ifdef USE_MAD namespace Common { - class SeekableReadStream; +class SeekableReadStream; } namespace Audio { -class AudioStream; class SeekableAudioStream; /** diff --git a/audio/decoders/raw.cpp b/audio/decoders/raw.cpp index 8b833c7838..cf787f9b12 100644 --- a/audio/decoders/raw.cpp +++ b/audio/decoders/raw.cpp @@ -25,9 +25,10 @@ #include "common/endian.h" #include "common/memstream.h" +#include "common/textconsole.h" +#include "common/util.h" #include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/raw.h" namespace Audio { diff --git a/audio/decoders/raw.h b/audio/decoders/raw.h index 3e9426012c..23ed02182d 100644 --- a/audio/decoders/raw.h +++ b/audio/decoders/raw.h @@ -32,12 +32,12 @@ #include "common/list.h" -namespace Common { class SeekableReadStream; } - +namespace Common { +class SeekableReadStream; +} namespace Audio { -class AudioStream; class SeekableAudioStream; /** diff --git a/audio/decoders/vag.h b/audio/decoders/vag.h index cdf91a8ea1..4adc1d3dde 100644 --- a/audio/decoders/vag.h +++ b/audio/decoders/vag.h @@ -35,12 +35,11 @@ #define SOUND_VAG_H namespace Common { - class SeekableReadStream; +class SeekableReadStream; } namespace Audio { -class AudioStream; class RewindableAudioStream; /** diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp index b811a640ec..9c2dc4f337 100644 --- a/audio/decoders/voc.cpp +++ b/audio/decoders/voc.cpp @@ -27,9 +27,9 @@ #include "common/endian.h" #include "common/util.h" #include "common/stream.h" +#include "common/textconsole.h" #include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/raw.h" #include "audio/decoders/voc.h" diff --git a/audio/decoders/voc.h b/audio/decoders/voc.h index 82cc261f2c..38250dcf7a 100644 --- a/audio/decoders/voc.h +++ b/audio/decoders/voc.h @@ -41,8 +41,10 @@ #include "common/scummsys.h" #include "common/types.h" -namespace Common { class ReadStream; } -namespace Common { class SeekableReadStream; } +namespace Common { +class ReadStream; +class SeekableReadStream; +} namespace Audio { diff --git a/audio/decoders/vorbis.cpp b/audio/decoders/vorbis.cpp index dc37e852d3..63f7ba8207 100644 --- a/audio/decoders/vorbis.cpp +++ b/audio/decoders/vorbis.cpp @@ -32,15 +32,15 @@ #ifdef USE_VORBIS -#include "common/debug.h" #include "common/stream.h" +#include "common/textconsole.h" #include "common/util.h" #include "audio/audiostream.h" #ifdef USE_TREMOR -#if defined(__GP32__) // custom libtremor locations -#include <ivorbisfile.h> +#ifdef USE_TREMOLO +#include <tremolo/ivorbisfile.h> #else #include <tremor/ivorbisfile.h> #endif diff --git a/audio/decoders/vorbis.h b/audio/decoders/vorbis.h index 7cc395cccb..51d0b82d5f 100644 --- a/audio/decoders/vorbis.h +++ b/audio/decoders/vorbis.h @@ -49,12 +49,11 @@ #ifdef USE_VORBIS namespace Common { - class SeekableReadStream; +class SeekableReadStream; } namespace Audio { -class AudioStream; class SeekableAudioStream; /** diff --git a/audio/decoders/wave.cpp b/audio/decoders/wave.cpp index 1f0ddd8ceb..a64874887a 100644 --- a/audio/decoders/wave.cpp +++ b/audio/decoders/wave.cpp @@ -24,11 +24,10 @@ */ #include "common/debug.h" -#include "common/util.h" +#include "common/textconsole.h" #include "common/stream.h" #include "audio/audiostream.h" -#include "audio/mixer.h" #include "audio/decoders/wave.h" #include "audio/decoders/adpcm.h" #include "audio/decoders/raw.h" diff --git a/audio/decoders/wave.h b/audio/decoders/wave.h index 2bdbe8f0b6..33c3e798a0 100644 --- a/audio/decoders/wave.h +++ b/audio/decoders/wave.h @@ -43,7 +43,9 @@ #include "common/scummsys.h" #include "common/types.h" -namespace Common { class SeekableReadStream; } +namespace Common { +class SeekableReadStream; +} namespace Audio { |