aboutsummaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
authorMatthew Hoops2011-04-13 16:04:29 -0400
committerMatthew Hoops2011-04-13 16:04:29 -0400
commit6d153f311c65fe414e31e99f8a9a6503c49a01a5 (patch)
tree9173f9964c0fec4215514e622f705810730d0ce9 /audio
parent47c2a9adbe8d9e6640a819386f0f34e929937672 (diff)
parent66b43f2312578f35e0718d0699de207a7bf77f1a (diff)
downloadscummvm-rg350-6d153f311c65fe414e31e99f8a9a6503c49a01a5.tar.gz
scummvm-rg350-6d153f311c65fe414e31e99f8a9a6503c49a01a5.tar.bz2
scummvm-rg350-6d153f311c65fe414e31e99f8a9a6503c49a01a5.zip
Merge remote branch 'upstream/master' into t7g-ios
Conflicts: video/qt_decoder.cpp
Diffstat (limited to 'audio')
-rw-r--r--audio/decoders/adpcm.cpp415
-rw-r--r--audio/decoders/adpcm.h9
-rw-r--r--audio/decoders/adpcm_intern.h235
-rw-r--r--audio/decoders/qdm2.cpp10
-rw-r--r--audio/decoders/quicktime.cpp20
-rw-r--r--audio/mods/module.cpp2
-rw-r--r--audio/mods/rjp1.cpp4
7 files changed, 273 insertions, 422 deletions
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp
index 7def89b688..ac18b244c5 100644
--- a/audio/decoders/adpcm.cpp
+++ b/audio/decoders/adpcm.cpp
@@ -26,44 +26,12 @@
#include "common/endian.h"
#include "audio/decoders/adpcm.h"
+#include "audio/decoders/adpcm_intern.h"
#include "audio/audiostream.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 +75,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 +110,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 +121,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 +138,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);
@@ -288,28 +204,6 @@ int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
#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::readBufferMSIMA1(int16 *buffer, const int numSamples) {
int samples = 0;
byte data;
@@ -382,41 +276,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 +337,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 +404,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 +428,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;
}
@@ -830,14 +453,8 @@ RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, Dispo
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..7202d6bc9c 100644
--- a/audio/decoders/adpcm.h
+++ b/audio/decoders/adpcm.h
@@ -38,7 +38,9 @@
#define SOUND_ADPCM_H
#include "common/scummsys.h"
-#include "common/stream.h"
+#include "common/types.h"
+
+namespace Common { class SeekableReadStream; }
namespace Audio {
@@ -56,10 +58,7 @@ enum typesADPCM {
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..2d56c9d468
--- /dev/null
+++ b/audio/decoders/adpcm_intern.h
@@ -0,0 +1,235 @@
+/* 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 encoders.
+ *
+ * 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"
+
+
+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();
+
+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, 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
+};
+
+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/qdm2.cpp b/audio/decoders/qdm2.cpp
index 2bbb608754..d4f3b2f101 100644
--- a/audio/decoders/qdm2.cpp
+++ b/audio/decoders/qdm2.cpp
@@ -1769,14 +1769,14 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
tmp = extraData->readUint32BE();
debug(1, "QDM2Stream::QDM2Stream() extraTag: %d", tmp);
- if (tmp != MKID_BE('frma'))
+ if (tmp != MKTAG('f','r','m','a'))
warning("QDM2Stream::QDM2Stream() extraTag mismatch");
tmp = extraData->readUint32BE();
debug(1, "QDM2Stream::QDM2Stream() extraType: %d", tmp);
- if (tmp == MKID_BE('QDMC'))
+ if (tmp == MKTAG('Q','D','M','C'))
warning("QDM2Stream::QDM2Stream() QDMC stream type not supported");
- else if (tmp != MKID_BE('QDM2'))
+ else if (tmp != MKTAG('Q','D','M','2'))
error("QDM2Stream::QDM2Stream() Unsupported stream type");
tmp_s = extraData->readSint32BE();
@@ -1786,7 +1786,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
tmp = extraData->readUint32BE();
debug(1, "QDM2Stream::QDM2Stream() extraTag2: %d", tmp);
- if (tmp != MKID_BE('QDCA'))
+ if (tmp != MKTAG('Q','D','C','A'))
warning("QDM2Stream::QDM2Stream() extraTag2 mismatch");
if (extraData->readUint32BE() != 1)
@@ -1818,7 +1818,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
tmp = extraData->readUint32BE();
debug(1, "QDM2Stream::QDM2Stream() extraTag3: %d", tmp);
- if (tmp != MKID_BE('QDCP'))
+ if (tmp != MKTAG('Q','D','C','P'))
warning("QDM2Stream::QDM2Stream() extraTag3 mismatch");
if ((float)extraData->readUint32BE() != 1.0)
diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp
index 0888041cfc..d4cd3a62f2 100644
--- a/audio/decoders/quicktime.cpp
+++ b/audio/decoders/quicktime.cpp
@@ -82,7 +82,7 @@ void QuickTimeAudioDecoder::init() {
_curAudioChunk = 0;
// Make sure the bits per sample transfers to the sample size
- if (entry->codecTag == MKID_BE('raw ') || entry->codecTag == MKID_BE('twos'))
+ if (entry->codecTag == MKTAG('r', 'a', 'w', ' ') || entry->codecTag == MKTAG('t', 'w', 'o', 's'))
_streams[_audioStreamIndex]->sample_size = (entry->bitsPerSample / 8) * entry->channels;
}
}
@@ -127,7 +127,7 @@ Common::QuickTimeParser::SampleDesc *QuickTimeAudioDecoder::readSampleDesc(MOVSt
// Version 0 videos (such as the Riven ones) don't have this set,
// but we need it later on. Add it in here.
- if (format == MKID_BE('ima4')) {
+ if (format == MKTAG('i', 'm', 'a', '4')) {
entry->samplesPerFrame = 64;
entry->bytesPerFrame = 34 * entry->channels;
}
@@ -143,15 +143,15 @@ Common::QuickTimeParser::SampleDesc *QuickTimeAudioDecoder::readSampleDesc(MOVSt
bool QuickTimeAudioDecoder::checkAudioCodecSupport(uint32 tag, byte objectTypeMP4) {
// Check if the codec is a supported codec
- if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4'))
+ if (tag == MKTAG('t', 'w', 'o', 's') || tag == MKTAG('r', 'a', 'w', ' ') || tag == MKTAG('i', 'm', 'a', '4'))
return true;
#ifdef AUDIO_QDM2_H
- if (tag == MKID_BE('QDM2'))
+ if (tag == MKTAG('Q', 'D', 'M', '2'))
return true;
#endif
- if (tag == MKID_BE('mp4a')) {
+ if (tag == MKTAG('m', 'p', '4', 'a')) {
Common::String audioType;
switch (objectTypeMP4) {
case 0x40: // AAC
@@ -178,10 +178,10 @@ AudioStream *QuickTimeAudioDecoder::createAudioStream(Common::SeekableReadStream
AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
- if (entry->codecTag == MKID_BE('twos') || entry->codecTag == MKID_BE('raw ')) {
+ if (entry->codecTag == MKTAG('t', 'w', 'o', 's') || entry->codecTag == MKTAG('r', 'a', 'w', ' ')) {
// Fortunately, most of the audio used in Myst videos is raw...
uint16 flags = 0;
- if (entry->codecTag == MKID_BE('raw '))
+ if (entry->codecTag == MKTAG('r', 'a', 'w', ' '))
flags |= FLAG_UNSIGNED;
if (entry->channels == 2)
flags |= FLAG_STEREO;
@@ -192,17 +192,17 @@ AudioStream *QuickTimeAudioDecoder::createAudioStream(Common::SeekableReadStream
stream->read(data, dataSize);
delete stream;
return makeRawStream(data, dataSize, entry->sampleRate, flags);
- } else if (entry->codecTag == MKID_BE('ima4')) {
+ } else if (entry->codecTag == MKTAG('i', 'm', 'a', '4')) {
// Riven uses this codec (as do some Myst ME videos)
return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, entry->sampleRate, entry->channels, 34);
- } else if (entry->codecTag == MKID_BE('mp4a')) {
+ } else if (entry->codecTag == MKTAG('m', 'p', '4', 'a')) {
// The 7th Guest iOS uses an MPEG-4 codec
#ifdef USE_FAAD
if (_streams[_audioStreamIndex]->objectTypeMP4 == 0x40)
return makeAACStream(stream, DisposeAfterUse::YES, _streams[_audioStreamIndex]->extradata);
#endif
#ifdef AUDIO_QDM2_H
- } else if (entry->codecTag == MKID_BE('QDM2')) {
+ } else if (entry->codecTag == MKTAG('Q', 'D', 'M', '2')) {
// Myst ME uses this codec for many videos
return makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
#endif
diff --git a/audio/mods/module.cpp b/audio/mods/module.cpp
index 0da6923b5d..3dad3794f9 100644
--- a/audio/mods/module.cpp
+++ b/audio/mods/module.cpp
@@ -113,7 +113,7 @@ const int16 Module::periods[16][60] = {
108 , 101 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 }};
const uint32 Module::signatures[] = {
- MKID_BE('M.K.'), MKID_BE('M!K!'), MKID_BE('FLT4')
+ MKTAG('M','.','K','.'), MKTAG('M','!','K','!'), MKTAG('F','L','T','4')
};
bool Module::load(Common::SeekableReadStream &st, int offs) {
diff --git a/audio/mods/rjp1.cpp b/audio/mods/rjp1.cpp
index 7423abb668..957bbb933a 100644
--- a/audio/mods/rjp1.cpp
+++ b/audio/mods/rjp1.cpp
@@ -138,7 +138,7 @@ Rjp1::~Rjp1() {
}
bool Rjp1::load(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData) {
- if (songData->readUint32BE() == MKID_BE('RJP1') && songData->readUint32BE() == MKID_BE('SMOD')) {
+ if (songData->readUint32BE() == MKTAG('R','J','P','1') && songData->readUint32BE() == MKTAG('S','M','O','D')) {
for (int i = 0; i < 7; ++i) {
uint32 size = songData->readUint32BE();
_vars.songData[i] = (uint8 *)malloc(size);
@@ -167,7 +167,7 @@ bool Rjp1::load(Common::SeekableReadStream *songData, Common::SeekableReadStream
}
}
- if (instrumentsData->readUint32BE() == MKID_BE('RJP1')) {
+ if (instrumentsData->readUint32BE() == MKTAG('R','J','P','1')) {
uint32 size = instrumentsData->size() - 4;
_vars.instData = (int8 *)malloc(size);
if (!_vars.instData)