1 /*
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20
21 This is the source needed to decode a Creative Labs VOC file into a
22 waveform. It's pretty straightforward once you get going. The only
23 externally-callable function is Mix_LoadVOC_RW(), which is meant to
24 act as identically to SDL_LoadWAV_RW() as possible.
25
26 This file by Ryan C. Gordon (icculus@icculus.org).
27
28 Heavily borrowed from sox v12.17.1's voc.c.
29 (http://www.freshmeat.net/projects/sox/)
30 */
31
32 #include "SDL_mixer.h"
33 #include "load_voc.h"
34
35 /* Private data for VOC file */
36 typedef struct vocstuff {
37 Uint32 rest; /* bytes remaining in current block */
38 Uint32 rate; /* rate code (byte) of this chunk */
39 int silent; /* sound or silence? */
40 Uint32 srate; /* rate code (byte) of silence */
41 Uint32 blockseek; /* start of current output block */
42 Uint32 samples; /* number of samples output */
43 Uint32 size; /* word length of data */
44 Uint8 channels; /* number of sound channels */
45 int has_extended; /* Has an extended block been read? */
46 } vs_t;
47
48 /* Size field */
49 /* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
50 #define ST_SIZE_BYTE 1
51 #define ST_SIZE_8BIT 1
52 #define ST_SIZE_WORD 2
53 #define ST_SIZE_16BIT 2
54 #define ST_SIZE_DWORD 4
55 #define ST_SIZE_32BIT 4
56 #define ST_SIZE_FLOAT 5
57 #define ST_SIZE_DOUBLE 6
58 #define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */
59
60 /* Style field */
61 #define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */
62 #define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */
63 #define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */
64 #define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */
65 #define ST_ENCODING_ADPCM 5 /* Compressed PCM */
66 #define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */
67 #define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */
68
69 #define VOC_TERM 0
70 #define VOC_DATA 1
71 #define VOC_CONT 2
72 #define VOC_SILENCE 3
73 #define VOC_MARKER 4
74 #define VOC_TEXT 5
75 #define VOC_LOOP 6
76 #define VOC_LOOPEND 7
77 #define VOC_EXTENDED 8
78 #define VOC_DATA_16 9
79
80
voc_check_header(SDL_RWops * src)81 static int voc_check_header(SDL_RWops *src)
82 {
83 /* VOC magic header */
84 Uint8 signature[20]; /* "Creative Voice File\032" */
85 Uint16 datablockofs;
86
87 SDL_RWseek(src, 0, RW_SEEK_SET);
88
89 if (SDL_RWread(src, signature, sizeof (signature), 1) != 1)
90 return(0);
91
92 if (SDL_memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0) {
93 SDL_SetError("Unrecognized file type (not VOC)");
94 return(0);
95 }
96
97 /* get the offset where the first datablock is located */
98 if (SDL_RWread(src, &datablockofs, sizeof (Uint16), 1) != 1)
99 return(0);
100
101 datablockofs = SDL_SwapLE16(datablockofs);
102
103 if (SDL_RWseek(src, datablockofs, RW_SEEK_SET) != datablockofs)
104 return(0);
105
106 return(1); /* success! */
107 } /* voc_check_header */
108
109
110 /* Read next block header, save info, leave position at start of data */
voc_get_block(SDL_RWops * src,vs_t * v,SDL_AudioSpec * spec)111 static int voc_get_block(SDL_RWops *src, vs_t *v, SDL_AudioSpec *spec)
112 {
113 Uint8 bits24[3];
114 Uint8 uc, block;
115 Uint32 sblen;
116 Uint16 new_rate_short;
117 Uint32 new_rate_long;
118 Uint8 trash[6];
119 Uint16 period;
120 unsigned int i;
121
122 v->silent = 0;
123 while (v->rest == 0)
124 {
125 if (SDL_RWread(src, &block, sizeof (block), 1) != 1)
126 return 1; /* assume that's the end of the file. */
127
128 if (block == VOC_TERM)
129 return 1;
130
131 if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)
132 return 1; /* assume that's the end of the file. */
133
134 /* Size is an 24-bit value. Ugh. */
135 sblen = ((bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16));
136
137 switch(block)
138 {
139 case VOC_DATA:
140 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
141 return 0;
142
143 /* When DATA block preceeded by an EXTENDED */
144 /* block, the DATA blocks rate value is invalid */
145 if (!v->has_extended)
146 {
147 if (uc == 0)
148 {
149 SDL_SetError("VOC Sample rate is zero?");
150 return 0;
151 }
152
153 if ((v->rate != -1) && (uc != v->rate))
154 {
155 SDL_SetError("VOC sample rate codes differ");
156 return 0;
157 }
158
159 v->rate = uc;
160 spec->freq = (Uint16)(1000000.0/(256 - v->rate));
161 v->channels = 1;
162 }
163
164 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
165 return 0;
166
167 if (uc != 0)
168 {
169 SDL_SetError("VOC decoder only interprets 8-bit data");
170 return 0;
171 }
172
173 v->has_extended = 0;
174 v->rest = sblen - 2;
175 v->size = ST_SIZE_BYTE;
176 return 1;
177
178 case VOC_DATA_16:
179 if (SDL_RWread(src, &new_rate_long, sizeof (new_rate_long), 1) != 1)
180 return 0;
181 new_rate_long = SDL_SwapLE32(new_rate_long);
182 if (new_rate_long == 0)
183 {
184 SDL_SetError("VOC Sample rate is zero?");
185 return 0;
186 }
187 if ((v->rate != -1) && (new_rate_long != v->rate))
188 {
189 SDL_SetError("VOC sample rate codes differ");
190 return 0;
191 }
192 v->rate = new_rate_long;
193 spec->freq = new_rate_long;
194
195 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
196 return 0;
197
198 switch (uc)
199 {
200 case 8: v->size = ST_SIZE_BYTE; break;
201 case 16: v->size = ST_SIZE_WORD; break;
202 default:
203 SDL_SetError("VOC with unknown data size");
204 return 0;
205 }
206
207 if (SDL_RWread(src, &v->channels, sizeof (Uint8), 1) != 1)
208 return 0;
209
210 if (SDL_RWread(src, trash, sizeof (Uint8), 6) != 6)
211 return 0;
212
213 v->rest = sblen - 12;
214 return 1;
215
216 case VOC_CONT:
217 v->rest = sblen;
218 return 1;
219
220 case VOC_SILENCE:
221 if (SDL_RWread(src, &period, sizeof (period), 1) != 1)
222 return 0;
223 period = SDL_SwapLE16(period);
224
225 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
226 return 0;
227 if (uc == 0)
228 {
229 SDL_SetError("VOC silence sample rate is zero");
230 return 0;
231 }
232
233 /*
234 * Some silence-packed files have gratuitously
235 * different sample rate codes in silence.
236 * Adjust period.
237 */
238 if ((v->rate != -1) && (uc != v->rate))
239 period = (Uint16)((period * (256 - uc))/(256 - v->rate));
240 else
241 v->rate = uc;
242 v->rest = period;
243 v->silent = 1;
244 return 1;
245
246 case VOC_LOOP:
247 case VOC_LOOPEND:
248 for(i = 0; i < sblen; i++) /* skip repeat loops. */
249 {
250 if (SDL_RWread(src, trash, sizeof (Uint8), 1) != 1)
251 return 0;
252 }
253 break;
254
255 case VOC_EXTENDED:
256 /* An Extended block is followed by a data block */
257 /* Set this byte so we know to use the rate */
258 /* value from the extended block and not the */
259 /* data block. */
260 v->has_extended = 1;
261 if (SDL_RWread(src, &new_rate_short, sizeof (new_rate_short), 1) != 1)
262 return 0;
263 new_rate_short = SDL_SwapLE16(new_rate_short);
264 if (new_rate_short == 0)
265 {
266 SDL_SetError("VOC sample rate is zero");
267 return 0;
268 }
269 if ((v->rate != -1) && (new_rate_short != v->rate))
270 {
271 SDL_SetError("VOC sample rate codes differ");
272 return 0;
273 }
274 v->rate = new_rate_short;
275
276 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
277 return 0;
278
279 if (uc != 0)
280 {
281 SDL_SetError("VOC decoder only interprets 8-bit data");
282 return 0;
283 }
284
285 if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
286 return 0;
287
288 if (uc)
289 spec->channels = 2; /* Stereo */
290 /* Needed number of channels before finishing
291 compute for rate */
292 spec->freq = (256000000L/(65536L - v->rate))/spec->channels;
293 /* An extended block must be followed by a data */
294 /* block to be valid so loop back to top so it */
295 /* can be grabed. */
296 continue;
297
298 case VOC_MARKER:
299 if (SDL_RWread(src, trash, sizeof (Uint8), 2) != 2)
300 return 0;
301
302 /* Falling! Falling! */
303
304 default: /* text block or other krapola. */
305 for(i = 0; i < sblen; i++)
306 {
307 if (SDL_RWread(src, &trash, sizeof (Uint8), 1) != 1)
308 return 0;
309 }
310
311 if (block == VOC_TEXT)
312 continue; /* get next block */
313 }
314 }
315
316 return 1;
317 }
318
319
voc_read(SDL_RWops * src,vs_t * v,Uint8 * buf,SDL_AudioSpec * spec)320 static int voc_read(SDL_RWops *src, vs_t *v, Uint8 *buf, SDL_AudioSpec *spec)
321 {
322 Uint32 done = 0;
323 Uint8 silence = 0x80;
324
325 if (v->rest == 0)
326 {
327 if (!voc_get_block(src, v, spec))
328 return 0;
329 }
330
331 if (v->rest == 0)
332 return 0;
333
334 if (v->silent)
335 {
336 if (v->size == ST_SIZE_WORD)
337 silence = 0x00;
338
339 /* Fill in silence */
340 SDL_memset(buf, silence, v->rest);
341 done = v->rest;
342 v->rest = 0;
343 }
344
345 else
346 {
347 done = (Uint32)SDL_RWread(src, buf, 1, v->rest);
348 v->rest -= done;
349 if (v->size == ST_SIZE_WORD)
350 {
351 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
352 Uint16 *samples = (Uint16 *)buf;
353 for (; v->rest > 0; v->rest -= 2)
354 {
355 *samples = SDL_SwapLE16(*samples);
356 samples++;
357 }
358 #endif
359 done >>= 1;
360 }
361 }
362
363 return done;
364 } /* voc_read */
365
366
367 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
Mix_LoadVOC_RW(SDL_RWops * src,int freesrc,SDL_AudioSpec * spec,Uint8 ** audio_buf,Uint32 * audio_len)368 SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,
369 SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
370 {
371 vs_t v;
372 int was_error = 1;
373 int samplesize;
374 Uint8 *fillptr;
375 void *ptr;
376
377 if ((!src) || (!audio_buf) || (!audio_len)) /* sanity checks. */
378 goto done;
379
380 if (!voc_check_header(src))
381 goto done;
382
383 v.rate = -1;
384 v.rest = 0;
385 v.has_extended = 0;
386 *audio_buf = NULL;
387 *audio_len = 0;
388 SDL_memset(spec, '\0', sizeof (SDL_AudioSpec));
389
390 if (!voc_get_block(src, &v, spec))
391 goto done;
392
393 if (v.rate == -1)
394 {
395 SDL_SetError("VOC data had no sound!");
396 goto done;
397 }
398
399 spec->format = ((v.size == ST_SIZE_WORD) ? AUDIO_S16 : AUDIO_U8);
400 if (spec->channels == 0)
401 spec->channels = v.channels;
402
403 *audio_len = v.rest;
404 *audio_buf = SDL_malloc(v.rest);
405 if (*audio_buf == NULL)
406 goto done;
407
408 fillptr = *audio_buf;
409
410 while (voc_read(src, &v, fillptr, spec) > 0)
411 {
412 if (!voc_get_block(src, &v, spec))
413 goto done;
414
415 *audio_len += v.rest;
416 ptr = SDL_realloc(*audio_buf, *audio_len);
417 if (ptr == NULL)
418 {
419 SDL_free(*audio_buf);
420 *audio_buf = NULL;
421 *audio_len = 0;
422 goto done;
423 }
424
425 *audio_buf = ptr;
426 fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest);
427 }
428
429 spec->samples = (Uint16)(*audio_len / v.size);
430
431 was_error = 0; /* success, baby! */
432
433 /* Don't return a buffer that isn't a multiple of samplesize */
434 samplesize = ((spec->format & 0xFF)/8)*spec->channels;
435 *audio_len &= ~(samplesize-1);
436
437 done:
438 if (freesrc && src) {
439 SDL_RWclose(src);
440 }
441
442 if (was_error) {
443 spec = NULL;
444 }
445
446 return(spec);
447 } /* Mix_LoadVOC_RW */
448
449 /* end of load_voc.c ... */
450
451 /* vi: set ts=4 sw=4 expandtab: */
452