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