1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 /** 24 * Internal interfaces to the ADPCM decoders. 25 * 26 * These can be used to make custom ADPCM decoder subclasses, 27 * or to at least share some common data tables between various 28 * ADPCM decoder implementations. 29 */ 30 31 #ifndef AUDIO_ADPCM_INTERN_H 32 #define AUDIO_ADPCM_INTERN_H 33 34 #include "audio/audiostream.h" 35 #include "common/endian.h" 36 #include "common/ptr.h" 37 #include "common/stream.h" 38 #include "common/textconsole.h" 39 40 namespace Audio { 41 42 class ADPCMStream : public SeekableAudioStream { 43 protected: 44 Common::DisposablePtr<Common::SeekableReadStream> _stream; 45 int32 _startpos; 46 const int32 _endpos; 47 const int _channels; 48 const uint32 _blockAlign; 49 uint32 _blockPos[2]; 50 const int _rate; 51 52 struct ADPCMStatus { 53 // OKI/IMA 54 struct { 55 int32 last; 56 int32 stepIndex; 57 } ima_ch[2]; 58 } _status; 59 60 virtual void reset(); 61 62 public: 63 ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign); 64 endOfData()65 virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); } isStereo()66 virtual bool isStereo() const { return _channels == 2; } getRate()67 virtual int getRate() const { return _rate; } 68 69 virtual bool rewind(); seek(const Timestamp & where)70 virtual bool seek(const Timestamp &where) { return false; } getLength()71 virtual Timestamp getLength() const { return -1; } 72 73 /** 74 * This table is used by some ADPCM variants (IMA and OKI) to adjust the 75 * step for use on the next sample. 76 * The first 8 entries are identical to the second 8 entries. Hence, we 77 * could half the table in size. But since the lookup index is always a 78 * 4-bit nibble, it is more efficient to just keep it as it is. 79 */ 80 static const int16 _stepAdjustTable[16]; 81 }; 82 83 class Oki_ADPCMStream : public ADPCMStream { 84 public: Oki_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)85 Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 86 : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; } 87 endOfData()88 virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } 89 90 virtual int readBuffer(int16 *buffer, const int numSamples); 91 92 protected: 93 int16 decodeOKI(byte); 94 95 private: 96 uint8 _decodedSampleCount; 97 int16 _decodedSamples[2]; 98 }; 99 100 class Ima_ADPCMStream : public ADPCMStream { 101 protected: 102 int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel 103 104 public: Ima_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)105 Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 106 : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} 107 108 /** 109 * This table is used by decodeIMA. 110 */ 111 static const int16 _imaTable[89]; 112 }; 113 114 class DVI_ADPCMStream : public Ima_ADPCMStream { 115 public: DVI_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)116 DVI_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 117 : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; } 118 endOfData()119 virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } 120 121 virtual int readBuffer(int16 *buffer, const int numSamples); 122 123 private: 124 uint8 _decodedSampleCount; 125 int16 _decodedSamples[2]; 126 }; 127 128 class Apple_ADPCMStream : public Ima_ADPCMStream { 129 protected: 130 // Apple QuickTime IMA ADPCM 131 int32 _streamPos[2]; 132 int16 _buffer[2][2]; 133 uint8 _chunkPos[2]; 134 reset()135 void reset() { 136 Ima_ADPCMStream::reset(); 137 _chunkPos[0] = 0; 138 _chunkPos[1] = 0; 139 _streamPos[0] = 0; 140 _streamPos[1] = _blockAlign; 141 } 142 143 public: Apple_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)144 Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 145 : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { 146 _chunkPos[0] = 0; 147 _chunkPos[1] = 0; 148 _streamPos[0] = 0; 149 _streamPos[1] = _blockAlign; 150 } 151 152 virtual int readBuffer(int16 *buffer, const int numSamples); 153 154 }; 155 156 class MSIma_ADPCMStream : public Ima_ADPCMStream { 157 public: MSIma_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)158 MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 159 : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { 160 161 if (blockAlign == 0) 162 error("MSIma_ADPCMStream(): blockAlign isn't specified"); 163 164 if (blockAlign % (_channels * 4)) 165 error("MSIma_ADPCMStream(): invalid blockAlign"); 166 167 _samplesLeft[0] = 0; 168 _samplesLeft[1] = 0; 169 } 170 171 virtual int readBuffer(int16 *buffer, const int numSamples); 172 reset()173 void reset() { 174 Ima_ADPCMStream::reset(); 175 _samplesLeft[0] = 0; 176 _samplesLeft[1] = 0; 177 } 178 179 private: 180 int16 _buffer[2][8]; 181 int _samplesLeft[2]; 182 }; 183 184 class MS_ADPCMStream : public ADPCMStream { 185 protected: 186 struct ADPCMChannelStatus { 187 byte predictor; 188 int16 delta; 189 int16 coeff1; 190 int16 coeff2; 191 int16 sample1; 192 int16 sample2; 193 }; 194 195 struct { 196 // MS ADPCM 197 ADPCMChannelStatus ch[2]; 198 } _status; 199 reset()200 void reset() { 201 ADPCMStream::reset(); 202 memset(&_status, 0, sizeof(_status)); 203 } 204 205 public: MS_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)206 MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 207 : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { 208 if (blockAlign == 0) 209 error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); 210 memset(&_status, 0, sizeof(_status)); 211 _decodedSampleCount = 0; 212 _decodedSampleIndex = 0; 213 } 214 endOfData()215 virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } 216 217 virtual int readBuffer(int16 *buffer, const int numSamples); 218 219 protected: 220 int16 decodeMS(ADPCMChannelStatus *c, byte); 221 222 private: 223 uint8 _decodedSampleCount; 224 uint8 _decodedSampleIndex; 225 int16 _decodedSamples[4]; 226 }; 227 228 // Duck DK3 IMA ADPCM Decoder 229 // Based on FFmpeg's decoder and http://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM 230 231 class DK3_ADPCMStream : public Ima_ADPCMStream { 232 protected: 233 reset()234 void reset() { 235 Ima_ADPCMStream::reset(); 236 _topNibble = false; 237 } 238 239 public: DK3_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,uint32 size,int rate,int channels,uint32 blockAlign)240 DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) 241 : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { 242 243 // DK3 only works as a stereo stream 244 assert(channels == 2); 245 _topNibble = false; 246 } 247 248 virtual int readBuffer(int16 *buffer, const int numSamples); 249 250 private: 251 byte _nibble, _lastByte; 252 bool _topNibble; 253 }; 254 255 } // End of namespace Audio 256 257 #endif 258