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