aboutsummaryrefslogtreecommitdiff
path: root/audio/decoders/adpcm_intern.h
diff options
context:
space:
mode:
authorMax Horn2011-04-13 12:22:57 +0200
committerMax Horn2011-04-13 12:48:57 +0200
commitb9296a189e12c94e110ea15c490d9f46dcf4a802 (patch)
tree17f61c3f4261d678b8d4a939095e6e8eaa850565 /audio/decoders/adpcm_intern.h
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.
Diffstat (limited to 'audio/decoders/adpcm_intern.h')
-rw-r--r--audio/decoders/adpcm_intern.h215
1 files changed, 215 insertions, 0 deletions
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