aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2011-04-13 12:22:57 +0200
committerMax Horn2011-04-13 12:48:57 +0200
commitb9296a189e12c94e110ea15c490d9f46dcf4a802 (patch)
tree17f61c3f4261d678b8d4a939095e6e8eaa850565
parentaadb4f74591f4044c82cf9de5cbac1694b9cd55c (diff)
downloadscummvm-rg350-b9296a189e12c94e110ea15c490d9f46dcf4a802.tar.gz
scummvm-rg350-b9296a189e12c94e110ea15c490d9f46dcf4a802.tar.bz2
scummvm-rg350-b9296a189e12c94e110ea15c490d9f46dcf4a802.zip
AUDIO: Expose ADPCM decoder internals via a new header
There are tons of ADPCM variants out there, and it is impractical to stuff them all into a single adpcm.cpp file. By exposing the internals, engines can implement their ADPCM decoder variants more easily.
-rw-r--r--audio/decoders/adpcm.cpp170
-rw-r--r--audio/decoders/adpcm_intern.h215
2 files changed, 216 insertions, 169 deletions
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp
index 7def89b688..1ade3dc0a1 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;
@@ -164,19 +121,6 @@ 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 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;
@@ -691,33 +550,6 @@ int Tinsel8_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
#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) { \
diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h
new file mode 100644
index 0000000000..8e092e67ad
--- /dev/null
+++ b/audio/decoders/adpcm_intern.h
@@ -0,0 +1,215 @@
+/* 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();
+ 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();
+};
+
+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));
+ }
+
+ 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