1 /*
2 Copyright (C) 2005 The Pentagram team
3 Copyright (C) 2010-2013 The Exult Team
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "pent_include.h"
21 #include "VocAudioSample.h"
22 #include <new>
23
24 #define TRAILING_VOC_SLOP 32
25 #define LEADING_VOC_SLOP 32
26
27 #ifndef min
28 using std::min;
29 #endif
30 #ifndef max
31 using std::max;
32 #endif
33
34 namespace Pentagram {
35
VocAudioSample(std::unique_ptr<uint8[]> buffer_,uint32 size_)36 VocAudioSample::VocAudioSample(std::unique_ptr<uint8[]> buffer_, uint32 size_)
37 : AudioSample(std::move(buffer_), size_)
38 {
39 bool last_chunk=false;
40
41 size_t data_offset=0x1a;
42 size_t l = 0;
43 int compression = 0;
44 int adpcm_reference = -1;
45 //int adpcm_scale = 0;
46
47 // Parse the file, get the 'important' details
48 sample_rate = 0;
49 frame_size = 0;
50 length = 0;
51 while (!last_chunk && data_offset < size_)
52 {
53 int chunk_length;
54 switch(buffer[data_offset++])
55 {
56 case 0:
57 COUT("Terminator");
58 last_chunk = true;
59 continue;
60
61 case 1:
62 COUT("Sound data");
63 l = (buffer[2+data_offset])<<16;
64 l |= (buffer[1+data_offset])<<8;
65 l |= (buffer[0+data_offset]);
66 data_offset+=3;
67 COUT("Chunk length appears to be " << l);
68 if (!sample_rate)
69 {
70 sample_rate=1000000/(256-(buffer[data_offset]));
71 #ifdef FUDGE_SAMPLE_RATES
72 if (sample_rate == 11111) sample_rate = 11025;
73 else if (sample_rate == 22222) sample_rate = 22050;
74 #endif
75 COUT("Sample rate ("<< sample_rate<<") = _real_rate");
76 }
77 compression = buffer[1+data_offset];
78 COUT("compression type " << compression);
79 if (compression) {
80 adpcm_reference = -1;
81 }
82
83 l -= 2;
84 chunk_length = l;
85 data_offset += 2;
86
87 break;
88 case 2:
89 COUT("Sound continues");
90 l=(buffer[2+data_offset])<<16;
91 l|=(buffer[1+data_offset])<<8;
92 l|=(buffer[0+data_offset]);
93 data_offset+=3;
94 COUT("Chunk length appears to be " << l);
95 chunk_length = l;
96 break;
97 case 3:
98 COUT("Silence");
99 l=(buffer[1+data_offset])<<8;
100 l|=(buffer[0+data_offset]);
101 l++;
102 if (!sample_rate)
103 {
104 sample_rate=1000000/(256-(buffer[2+data_offset]));
105 #ifdef FUDGE_SAMPLE_RATES
106 if (sample_rate == 11111) sample_rate = 11025;
107 else if (sample_rate == 22222) sample_rate = 22050;
108 #endif
109 COUT("Sample rate ("<< sample_rate<<") = _real_rate");
110 }
111 data_offset+=3;
112 chunk_length=0;
113 break;
114
115 default:
116 COUT("Other chunk type");
117 l=(buffer[2+data_offset])<<16;
118 l|=(buffer[1+data_offset])<<8;
119 l|=(buffer[0+data_offset]);
120 data_offset+=3;
121 COUT("Chunk length appears to be " << l);
122 chunk_length = l;
123 l = 0;
124 break;
125 }
126
127 if(chunk_length==0)
128 break;
129
130 if (l)
131 {
132 size_t dec_len = l;
133
134 // Decompress data
135 if (compression == 1) {
136 if (adpcm_reference == -1) dec_len = (dec_len-1)*2;
137 else dec_len *= 2;
138 adpcm_reference = 0;
139 }
140 else if (compression != 0) {
141 CERR("Can't handle VOC compression type");
142 }
143
144 if (dec_len > static_cast<size_t>(frame_size)) frame_size = dec_len;
145 length += dec_len;
146 }
147
148 data_offset += chunk_length;
149 }
150
151 // Limit frame size to only 512
152 if (frame_size > 512) frame_size = 512;
153
154 bits = 8;
155 stereo = false;
156 decompressor_size = sizeof(VocDecompData);
157 decompressor_align = alignof(VocDecompData);
158 length = size_;
159 }
160
initDecompressor(void * DecompData) const161 void VocAudioSample::initDecompressor(void *DecompData) const
162 {
163 auto *decomp = new (DecompData) VocDecompData;
164 decomp->pos = 0x1a;
165 decomp->compression = 0;
166 decomp->adpcm_reference = -1;
167 decomp->adpcm_scale = 0;
168 decomp->chunk_remain = 0;
169 decomp->cur_type = 0;
170 }
171
freeDecompressor(void * DecompData) const172 void VocAudioSample::freeDecompressor(void *DecompData) const
173 {
174 auto *decomp = static_cast<VocDecompData *>(DecompData);
175 decomp->~VocDecompData();
176 }
177
178 //
179 // Decode 4bit ADPCM vocs (thunder in SI intro)
180 //
181 // Code grabbed from VDMS
182 //
183
decode_ADPCM_4_sample(uint8 sample,int & reference,int & scale)184 inline int VocAudioSample::decode_ADPCM_4_sample(uint8 sample,
185 int& reference,
186 int& scale)
187 {
188 static int scaleMap[8] = { -2, -1, 0, 0, 1, 1, 1, 1 };
189
190 if (sample & 0x08) {
191 reference = max(0x00, reference - ((sample & 0x07) << scale));
192 } else {
193 reference = min(0xff, reference + ((sample & 0x07) << scale));
194 }
195
196 scale = max(2, min(6, scaleMap[sample & 0x07]));
197
198 return reference;
199 }
200
201 //
202 // Performs 4-bit ADPCM decoding in-place.
203 //
decode_ADPCM_4(uint8 * inBuf,int bufSize,uint8 * outBuf,int & reference,int & scale)204 void VocAudioSample::decode_ADPCM_4(uint8* inBuf,
205 int bufSize, // Size of inbuf
206 uint8* outBuf, // Size is 2x bufsize
207 int& reference, // ADPCM reference value
208 int& scale)
209 {
210 if (reference < 0) {
211 reference = inBuf[0] & 0xff; // use the first byte in the buffer as the reference byte
212 bufSize--; // remember to skip the reference byte
213 inBuf++;
214 }
215
216 for (int i = 0; i < bufSize; i++) {
217 outBuf[i * 2 + 0] = decode_ADPCM_4_sample(inBuf[i] >> 4, reference, scale);
218 outBuf[i * 2 + 1] = decode_ADPCM_4_sample(inBuf[i] >> 0, reference, scale);
219 }
220 }
221
advanceChunk(void * DecompData) const222 bool VocAudioSample::advanceChunk(void *DecompData) const
223 {
224 auto *decomp = static_cast<VocDecompData *>(DecompData);
225
226 if (decomp->pos == buffer_size) return false;
227
228 size_t l = 0;
229 size_t chunk_length = 0;
230
231 // Look at the chunk type
232 switch (buffer[decomp->pos++])
233 {
234 case 0:
235 return false;
236
237 case 1: // Sound data
238 l = (buffer[2+decomp->pos])<<16;
239 l |= (buffer[1+decomp->pos])<<8;
240 l |= (buffer[0+decomp->pos]);
241 decomp->pos += 3;
242 decomp->compression = buffer[1+decomp->pos];
243
244 if (decomp->compression) decomp->adpcm_reference = -1;
245
246 l -= 2;
247 chunk_length = l;
248 decomp->pos += 2;
249 break;
250
251 case 2: // Sound continue
252 l=(buffer[2+decomp->pos])<<16;
253 l|=(buffer[1+decomp->pos])<<8;
254 l|=(buffer[0+decomp->pos]);
255 decomp->pos += 3;
256 chunk_length = l;
257 break;
258
259 case 3: // Silence
260 l =(buffer[1+decomp->pos])<<8;
261 l |=(buffer[0+decomp->pos]);
262 l++;
263 decomp->pos += 3;
264 chunk_length=0;
265 break;
266
267 // Skip all other chunk types
268 default:
269 l=(buffer[2+decomp->pos])<<16;
270 l|=(buffer[1+decomp->pos])<<8;
271 l|=(buffer[0+decomp->pos]);
272 decomp->pos += 3 + l;
273 return advanceChunk(decomp);
274 };
275
276 if (!chunk_length)
277 {
278 decomp->cur_type = 1;
279 decomp->chunk_remain = l;
280 }
281 else
282 {
283 decomp->cur_type = 0;
284 decomp->chunk_remain = chunk_length;
285 }
286
287 return true;
288 }
289
decompressFrame(void * DecompData,void * samples) const290 uint32 VocAudioSample::decompressFrame(void *DecompData, void *samples) const
291 {
292 auto *decomp = static_cast<VocDecompData *>(DecompData);
293
294 // At end of stream??
295 if (!decomp->chunk_remain && !advanceChunk(decomp)) return 0;
296
297 int num_samples = decomp->chunk_remain;
298
299 if (decomp->cur_type == 0 && decomp->compression == 1)
300 {
301 if (decomp->adpcm_reference == -1) num_samples = (num_samples-1)*2;
302 else num_samples *= 2;
303 }
304
305 // Limit number of samples produced
306 if (num_samples > frame_size) num_samples = frame_size;
307
308 int bytes_used = 0;
309
310 // This is just silence
311 if (decomp->cur_type == 1)
312 {
313 bytes_used = 0;
314 std::memset(samples,0,num_samples);
315 }
316 else if (decomp->compression == 0)
317 {
318 bytes_used = num_samples;
319 std::memcpy(samples, buffer.get()+decomp->pos, num_samples);
320 }
321 else if (decomp->compression == 1)
322 {
323 bytes_used = num_samples/2;
324 if (decomp->adpcm_reference == -1) bytes_used++;
325 decode_ADPCM_4(buffer.get()+decomp->pos, bytes_used, static_cast<uint8*>(samples), decomp->adpcm_reference, decomp->adpcm_scale);
326 }
327 else
328 {
329 bytes_used = num_samples;
330 // Unhandled chunk types set to silence
331 std::memset(samples,0,num_samples);
332 }
333
334 decomp->pos += bytes_used;
335 decomp->chunk_remain -= bytes_used;
336 return num_samples;
337 }
338
339
isThis(IDataSource * ds)340 bool VocAudioSample::isThis(IDataSource *ds)
341 {
342 char buffer[19];
343 ds->read(buffer,19);
344
345 return strncmp(buffer,"Creative Voice File",19) == 0;
346 }
347
348
349 }
350