ScummVM API documentation
adpcm_intern.h
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 modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (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, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
30 #ifndef AUDIO_ADPCM_INTERN_H
31 #define AUDIO_ADPCM_INTERN_H
32 
33 #include "audio/audiostream.h"
34 #include "common/endian.h"
35 #include "common/ptr.h"
36 #include "common/array.h"
37 #include "common/stream.h"
38 #include "common/textconsole.h"
39 
40 namespace Audio {
41 
43 protected:
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  int16 sample[2];
58  } ima_ch[2];
59  } _status;
60 
61  virtual void reset();
62 
63 public:
64  ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign);
65 
66  virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
67  virtual bool isStereo() const { return _channels == 2; }
68  virtual int getRate() const { return _rate; }
69 
70  virtual bool rewind();
71  virtual bool seek(const Timestamp &where) { return false; }
72  virtual Timestamp getLength() const { return Timestamp(); }
73 
81  static const int16 _stepAdjustTable[16];
82 };
83 
84 class Oki_ADPCMStream : public ADPCMStream {
85 public:
86  Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
87  : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; }
88 
89  virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
90 
91  virtual int readBuffer(int16 *buffer, const int numSamples);
92 
93 protected:
94  int16 decodeOKI(byte);
95 
96 private:
97  uint8 _decodedSampleCount;
98  int16 _decodedSamples[2];
99 };
100 
101 class XA_ADPCMStream : public ADPCMStream {
102 public:
103  XA_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
104  : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; }
105 
106  virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
107 
108  virtual int readBuffer(int16 *buffer, const int numSamples);
109 
110 protected:
111  void decodeXA(const byte *src);
112 
113 private:
114  uint8 _decodedSampleCount;
115  uint8 _decodedSampleIndex;
116  int16 _decodedSamples[28 * 2 * 4];
117 };
118 
119 class Ima_ADPCMStream : public ADPCMStream {
120 protected:
121  int16 decodeIMA(byte code, int channel = 0, int shift = 3); // Default to using the left channel/using one channel
122 
123 public:
124  Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
125  : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}
126 
130  static const int16 _imaTable[89];
131 };
132 
134 public:
135  DVI_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
136  : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; }
137 
138  virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
139 
140  virtual int readBuffer(int16 *buffer, const int numSamples);
141 
142 private:
143  uint8 _decodedSampleCount;
144  int16 _decodedSamples[2];
145 };
146 
148 protected:
149  // Apple QuickTime IMA ADPCM
150  int32 _streamPos[2];
151  int16 _buffer[2][2];
152  uint8 _chunkPos[2];
153 
154  void reset() {
155  Ima_ADPCMStream::reset();
156  _chunkPos[0] = 0;
157  _chunkPos[1] = 0;
158  _streamPos[0] = 0;
159  _streamPos[1] = _blockAlign;
160  }
161 
162 public:
163  Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
164  : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
165  _chunkPos[0] = 0;
166  _chunkPos[1] = 0;
167  _streamPos[0] = 0;
168  _streamPos[1] = _blockAlign;
169  }
170 
171  virtual int readBuffer(int16 *buffer, const int numSamples);
172 };
173 
175 public:
176  MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
177  : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
178 
179  if (blockAlign == 0)
180  error("MSIma_ADPCMStream(): blockAlign isn't specified");
181 
182  if (blockAlign % (_channels * 4))
183  error("MSIma_ADPCMStream(): invalid blockAlign");
184 
185  _samplesLeft[0] = 0;
186  _samplesLeft[1] = 0;
187  }
188 
189  virtual int readBuffer(int16 *buffer, const int numSamples);
190 
191  void reset() {
192  Ima_ADPCMStream::reset();
193  _samplesLeft[0] = 0;
194  _samplesLeft[1] = 0;
195  }
196 
197 private:
198  int16 _buffer[2][8];
199  int _samplesLeft[2];
200 };
201 
202 class MS_ADPCMStream : public ADPCMStream {
203 protected:
205  byte predictor;
206  int16 delta;
207  int16 coeff1;
208  int16 coeff2;
209  int16 sample1;
210  int16 sample2;
211  };
212 
213  struct {
214  // MS ADPCM
215  ADPCMChannelStatus ch[2];
216  } _status;
217 
218  void reset() {
219  ADPCMStream::reset();
220  memset(&_status, 0, sizeof(_status));
221  }
222 
223 public:
224  MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
225  : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
226  if (blockAlign == 0)
227  error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM");
228  memset(&_status, 0, sizeof(_status));
229  _decodedSampleCount = 0;
230  _decodedSampleIndex = 0;
231  }
232 
233  virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
234 
235  virtual int readBuffer(int16 *buffer, const int numSamples);
236 
237 protected:
238  int16 decodeMS(ADPCMChannelStatus *c, byte);
239 
240 private:
241  uint8 _decodedSampleCount;
242  uint8 _decodedSampleIndex;
243  int16 _decodedSamples[4];
244 };
245 
246 // Duck DK3 IMA ADPCM Decoder
247 // Based on FFmpeg's decoder and https://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM
248 
250 public:
251  DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
252  : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
253 
254  // DK3 only works as a stereo stream
255  assert(channels == 2);
256  }
257 
258  virtual int readBuffer(int16 *buffer, const int numSamples);
259 
260 private:
261  byte _nibble, _lastByte;
262  bool _topNibble;
263 };
264 
266 public:
267  FOURXM_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels)
268  : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, 0) {
269  decode();
270  }
271 
272  int readBuffer(int16 *buffer, const int numSamples) override;
273  bool endOfData() const override {
274  return !_planes.empty() && _samplePos >= _planes[0].size();
275  }
276 
277  void reset() override {
278  Ima_ADPCMStream::reset();
279  _samplePos = 0;
280  _planes.clear();
281  }
282 
283 private:
284  void decode();
285 
286  uint _samplePos = 0;
288 };
289 
290 } // End of namespace Audio
291 
292 #endif
virtual bool endOfData() const
Definition: adpcm_intern.h:138
virtual bool rewind()
virtual int64 pos() const =0
virtual int readBuffer(int16 *buffer, const int numSamples)=0
virtual bool endOfData() const
Definition: adpcm_intern.h:89
Definition: array.h:52
virtual bool eos() const =0
virtual Timestamp getLength() const
Definition: adpcm_intern.h:72
virtual bool endOfData() const
Definition: adpcm_intern.h:233
Definition: adpcm_intern.h:52
Definition: timestamp.h:83
Definition: stream.h:745
virtual int getRate() const
Definition: adpcm_intern.h:68
Definition: audiostream.h:212
Definition: adpcm_intern.h:174
Definition: adpcm_intern.h:204
Definition: adpcm_intern.h:84
Definition: adpcm_intern.h:147
Definition: adpcm_intern.h:202
Definition: adpcm_intern.h:265
static const int16 _stepAdjustTable[16]
Definition: adpcm_intern.h:81
virtual bool seek(const Timestamp &where)
Definition: adpcm_intern.h:71
Definition: adpcm_intern.h:101
virtual bool isStereo() const
Definition: adpcm_intern.h:67
virtual bool endOfData() const
Definition: adpcm_intern.h:66
Definition: adpcm_intern.h:249
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
Definition: adpcm_intern.h:42
Definition: adpcm_intern.h:119
virtual bool endOfData() const
Definition: adpcm_intern.h:106
Definition: adpcm_intern.h:133
bool endOfData() const override
Definition: adpcm_intern.h:273
Definition: system.h:38