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 #include "common/scummsys.h"
24 #include "common/file.h"
25 #include "common/str.h"
26 #include "common/stream.h"
27 #include "common/memstream.h"
28 #include "common/bufferedstream.h"
29 #include "common/util.h"
30 #include "common/tokenizer.h"
31 #include "audio/audiostream.h"
32 #include "audio/decoders/raw.h"
33
34 #include "zvision/sound/zork_raw.h"
35 #include "zvision/zvision.h"
36
37 namespace ZVision {
38
39 const int16 RawChunkStream::_stepAdjustmentTable[8] = { -1, -1, -1, 1, 4, 7, 10, 12};
40
41 const int32 RawChunkStream::_amplitudeLookupTable[89] = {0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
42 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F,
43 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042,
44 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F,
45 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133,
46 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292,
47 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583,
48 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0,
49 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954,
50 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B,
51 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
52 };
53
RawChunkStream(bool stereo)54 RawChunkStream::RawChunkStream(bool stereo) {
55 if (stereo)
56 _stereo = 1;
57 else
58 _stereo = 0;
59
60 init();
61 }
62
init()63 void RawChunkStream::init() {
64 _lastSample[0].index = 0;
65 _lastSample[0].sample = 0;
66 _lastSample[1].index = 0;
67 _lastSample[1].sample = 0;
68 }
69
readNextChunk(Common::SeekableReadStream * stream)70 RawChunkStream::RawChunk RawChunkStream::readNextChunk(Common::SeekableReadStream *stream) {
71 RawChunk tmp;
72 tmp.size = 0;
73 tmp.data = NULL;
74
75 if (!stream || stream->size() == 0 || stream->eos())
76 return tmp;
77
78 tmp.size = (stream->size() - stream->pos()) * 2;
79 tmp.data = (int16 *)calloc(tmp.size, 1);
80
81 readBuffer(tmp.data, stream, stream->size() - stream->pos());
82
83 return tmp;
84 }
85
readBuffer(int16 * buffer,Common::SeekableReadStream * stream,const int numSamples)86 int RawChunkStream::readBuffer(int16 *buffer, Common::SeekableReadStream *stream, const int numSamples) {
87 int32 bytesRead = 0;
88
89 // 0: Left, 1: Right
90 uint channel = 0;
91
92 while (bytesRead < numSamples) {
93 byte encodedSample = stream->readByte();
94 if (stream->eos()) {
95 return bytesRead;
96 }
97 bytesRead++;
98
99 int16 index = _lastSample[channel].index;
100 uint32 lookUpSample = _amplitudeLookupTable[index];
101
102 int32 sample = 0;
103
104 if (encodedSample & 0x40)
105 sample += lookUpSample;
106 if (encodedSample & 0x20)
107 sample += lookUpSample >> 1;
108 if (encodedSample & 0x10)
109 sample += lookUpSample >> 2;
110 if (encodedSample & 8)
111 sample += lookUpSample >> 3;
112 if (encodedSample & 4)
113 sample += lookUpSample >> 4;
114 if (encodedSample & 2)
115 sample += lookUpSample >> 5;
116 if (encodedSample & 1)
117 sample += lookUpSample >> 6;
118 if (encodedSample & 0x80)
119 sample = -sample;
120
121 sample += _lastSample[channel].sample;
122 sample = CLIP<int32>(sample, -32768, 32767);
123
124 buffer[bytesRead - 1] = (int16)sample;
125
126 index += _stepAdjustmentTable[(encodedSample >> 4) & 7];
127 index = CLIP<int16>(index, 0, 88);
128
129 _lastSample[channel].sample = sample;
130 _lastSample[channel].index = index;
131
132 // Increment and wrap the channel
133 channel = (channel + 1) & _stereo;
134 }
135 return bytesRead;
136 }
137
138 const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {
139 {'0', 0x1F40, false, false, false},
140 {'1', 0x1F40, true, false, false},
141 {'2', 0x1F40, false, false, true},
142 {'3', 0x1F40, true, false, true},
143 {'4', 0x2B11, false, false, false},
144 {'5', 0x2B11, true, false, false},
145 {'6', 0x2B11, false, false, true},
146 {'7', 0x2B11, true, false, true},
147 {'8', 0x5622, false, false, false},
148 {'9', 0x5622, true, false, false},
149 {'a', 0x5622, false, false, true},
150 {'b', 0x5622, true, false, true},
151 {'c', 0xAC44, false, false, false},
152 {'d', 0xAC44, true, false, false},
153 {'e', 0xAC44, false, false, true},
154 {'f', 0xAC44, true, false, true},
155 {'g', 0x1F40, false, true, false},
156 {'h', 0x1F40, true, true, false},
157 {'j', 0x1F40, false, true, true},
158 {'k', 0x1F40, true, true, true},
159 {'l', 0x2B11, false, true, false},
160 {'m', 0x2B11, true, true, false},
161 {'n', 0x2B11, false, true, true},
162 {'p', 0x2B11, true, true, true},
163 {'q', 0x5622, false, true, false},
164 {'r', 0x5622, true, true, false},
165 {'s', 0x5622, false, true, true},
166 {'t', 0x5622, true, true, true},
167 {'u', 0xAC44, false, true, false},
168 {'v', 0xAC44, true, true, false},
169 {'w', 0xAC44, false, true, true},
170 {'x', 0xAC44, true, true, true}
171 };
172
173 const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {
174 {'4', 0x2B11, false, false, false},
175 {'5', 0x2B11, true, false, false},
176 {'6', 0x2B11, false, false, true},
177 {'7', 0x2B11, true, false, true},
178 {'8', 0x5622, false, false, false},
179 {'9', 0x5622, true, false, false},
180 {'a', 0x5622, false, false, true},
181 {'b', 0x5622, true, false, true},
182 {'c', 0xAC44, false, false, false},
183 {'d', 0xAC44, true, false, false},
184 {'e', 0xAC44, false, false, true},
185 {'f', 0xAC44, true, false, true},
186 {'g', 0x2B11, false, true, false},
187 {'h', 0x2B11, true, true, false},
188 {'j', 0x2B11, false, true, true},
189 {'k', 0x2B11, true, true, true},
190 {'m', 0x5622, false, true, false},
191 {'n', 0x5622, true, true, false},
192 {'p', 0x5622, false, true, true},
193 {'q', 0x5622, true, true, true},
194 {'r', 0xAC44, false, true, false},
195 {'s', 0xAC44, true, true, false},
196 {'t', 0xAC44, false, true, true},
197 {'u', 0xAC44, true, true, true}
198 };
199
RawZorkStream(uint32 rate,bool stereo,DisposeAfterUse::Flag disposeStream,Common::SeekableReadStream * stream)200 RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream)
201 : _rate(rate),
202 _stereo(0),
203 _stream(stream, disposeStream),
204 _endOfData(false),
205 _streamReader(stereo) {
206 if (stereo)
207 _stereo = 1;
208
209 // Calculate the total playtime of the stream
210 if (stereo)
211 _playtime = Audio::Timestamp(0, _stream->size() / 2, rate);
212 else
213 _playtime = Audio::Timestamp(0, _stream->size(), rate);
214 }
215
readBuffer(int16 * buffer,const int numSamples)216 int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) {
217 int32 bytesRead = _streamReader.readBuffer(buffer, _stream.get(), numSamples);
218
219 if (_stream->eos())
220 _endOfData = true;
221
222 return bytesRead;
223 }
224
rewind()225 bool RawZorkStream::rewind() {
226 _stream->seek(0, 0);
227 _stream->clearErr();
228 _endOfData = false;
229 _streamReader.init();
230
231 return true;
232 }
233
makeRawZorkStream(Common::SeekableReadStream * stream,int rate,bool stereo,DisposeAfterUse::Flag disposeAfterUse)234 Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream,
235 int rate,
236 bool stereo,
237 DisposeAfterUse::Flag disposeAfterUse) {
238 if (stereo)
239 assert(stream->size() % 2 == 0);
240
241 return new RawZorkStream(rate, stereo, disposeAfterUse, stream);
242 }
243
makeRawZorkStream(const Common::String & filePath,ZVision * engine)244 Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) {
245 Common::File *file = new Common::File();
246 Common::String actualName = filePath;
247 bool found = engine->getSearchManager()->openFile(*file, actualName);
248 bool isRaw = actualName.hasSuffix(".raw");
249
250 if ((!found && isRaw) || (found && isRaw && file->size() < 10)) {
251 if (found)
252 file->close();
253
254 // Check for an audio patch (.src)
255 actualName.setChar('s', actualName.size() - 3);
256 actualName.setChar('r', actualName.size() - 2);
257 actualName.setChar('c', actualName.size() - 1);
258
259 if (!engine->getSearchManager()->openFile(*file, actualName))
260 return NULL;
261 } else if (!found && !isRaw) {
262 return NULL;
263 }
264
265 // Get the file name
266 Common::StringTokenizer tokenizer(actualName, "/\\");
267 Common::String fileName;
268 while (!tokenizer.empty()) {
269 fileName = tokenizer.nextToken();
270 }
271
272 fileName.toLowercase();
273
274 const SoundParams *soundParams = NULL;
275
276 if (engine->getGameId() == GID_NEMESIS) {
277 for (int i = 0; i < 32; ++i) {
278 if (RawZorkStream::_zNemSoundParamLookupTable[i].identifier == (fileName[6]))
279 soundParams = &RawZorkStream::_zNemSoundParamLookupTable[i];
280 }
281 } else if (engine->getGameId() == GID_GRANDINQUISITOR) {
282 for (int i = 0; i < 24; ++i) {
283 if (RawZorkStream::_zgiSoundParamLookupTable[i].identifier == (fileName[7]))
284 soundParams = &RawZorkStream::_zgiSoundParamLookupTable[i];
285 }
286 }
287
288 if (soundParams == NULL)
289 return NULL;
290
291 if (soundParams->packed) {
292 return makeRawZorkStream(wrapBufferedSeekableReadStream(file, 2048, DisposeAfterUse::YES), soundParams->rate, soundParams->stereo, DisposeAfterUse::YES);
293 } else {
294 byte flags = 0;
295 if (soundParams->bits16)
296 flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
297 if (soundParams->stereo)
298 flags |= Audio::FLAG_STEREO;
299
300 return Audio::makeRawStream(file, soundParams->rate, flags, DisposeAfterUse::YES);
301 }
302 }
303
304 } // End of namespace ZVision
305