/
voc.c
583 lines (470 loc) · 17.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* VOC decoder for SDL_sound.
*
* This driver handles Creative Labs VOC audio data...this is a legacy format,
* but there's some game ports that could make use of such a decoder. Plus,
* VOC is fairly straightforward to decode, so this is a more complex, but
* still palatable example of an SDL_sound decoder. Y'know, in case the
* RAW decoder didn't do it for you. :)
*
* This code was ripped from a decoder I had written for SDL_mixer, which was
* largely ripped from sox v12.17.1's voc.c.
*
* SDL_mixer: http://www.libsdl.org/projects/SDL_mixer/
* sox: http://www.freshmeat.net/projects/sox/
*
35
* Please see the file COPYING in the source's root directory.
36
37
38
39
*
* This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
*/
40
41
42
#if HAVE_CONFIG_H
# include <config.h>
#endif
43
44
#ifdef SOUND_SUPPORTS_VOC
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
50
51
52
53
54
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
55
56
static int VOC_init(void);
static void VOC_quit(void);
57
58
59
static int VOC_open(Sound_Sample *sample, const char *ext);
static void VOC_close(Sound_Sample *sample);
static Uint32 VOC_read(Sound_Sample *sample);
60
static int VOC_rewind(Sound_Sample *sample);
61
static int VOC_seek(Sound_Sample *sample, Uint32 ms);
62
63
static const char *extensions_voc[] = { "VOC", NULL };
64
65
66
const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC =
{
{
67
extensions_voc,
68
69
70
71
72
"Creative Labs Voice format",
"Ryan C. Gordon <icculus@clutteredmind.org>",
"http://www.icculus.org/SDL_sound/"
},
73
74
75
76
77
VOC_init, /* init() method */
VOC_quit, /* quit() method */
VOC_open, /* open() method */
VOC_close, /* close() method */
VOC_read, /* read() method */
78
79
VOC_rewind, /* rewind() method */
VOC_seek /* seek() method */
80
81
82
83
84
};
/* Private data for VOC file */
typedef struct vocstuff {
85
86
87
88
89
90
91
92
Uint32 rest; /* bytes remaining in current block */
Uint32 rate; /* rate code (byte) of this chunk */
int silent; /* sound or silence? */
Uint32 srate; /* rate code (byte) of silence */
Uint32 blockseek; /* start of current output block */
Uint32 samples; /* number of samples output */
Uint32 size; /* word length of data */
Uint8 channels; /* number of sound channels */
93
94
int extended; /* Has an extended block been read? */
Uint32 bufpos; /* byte position in internal->buffer. */
95
Uint32 start_pos; /* offset to seek to in stream when rewinding. */
96
int error; /* error condition (as opposed to EOF). */
97
98
} vs_t;
99
100
/* Size field */
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
#define ST_SIZE_BYTE 1
#define ST_SIZE_8BIT 1
#define ST_SIZE_WORD 2
#define ST_SIZE_16BIT 2
#define ST_SIZE_DWORD 4
#define ST_SIZE_32BIT 4
#define ST_SIZE_FLOAT 5
#define ST_SIZE_DOUBLE 6
#define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */
/* Style field */
#define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */
#define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */
#define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */
#define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */
#define ST_ENCODING_ADPCM 5 /* Compressed PCM */
#define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */
#define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */
#define VOC_TERM 0
#define VOC_DATA 1
#define VOC_CONT 2
#define VOC_SILENCE 3
#define VOC_MARKER 4
#define VOC_TEXT 5
#define VOC_LOOP 6
#define VOC_LOOPEND 7
#define VOC_EXTENDED 8
#define VOC_DATA_16 9
133
134
135
136
137
138
139
140
141
142
143
144
static int VOC_init(void)
{
return(1); /* always succeeds. */
} /* VOC_init */
static void VOC_quit(void)
{
/* it's a no-op. */
} /* VOC_quit */
145
static __inline__ int voc_readbytes(SDL_RWops *src, vs_t *v, void *p, int size)
146
147
148
149
{
if (SDL_RWread(src, p, size, 1) != 1)
{
v->error = 1;
150
BAIL_MACRO("VOC: i/o error", 0);
151
152
153
154
155
156
} /* if */
return(1);
} /* voc_readbytes */
157
static __inline__ int voc_check_header(SDL_RWops *src)
158
159
160
161
{
/* VOC magic header */
Uint8 signature[20]; /* "Creative Voice File\032" */
Uint16 datablockofs;
162
vs_t v; /* dummy struct for voc_readbytes */
163
164
if (!voc_readbytes(src, &v, signature, sizeof (signature)))
165
166
return(0);
167
168
if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0)
{
169
BAIL_MACRO("VOC: Wrong signature; not a VOC file.", 0);
170
} /* if */
171
172
/* get the offset where the first datablock is located */
173
if (!voc_readbytes(src, &v, &datablockofs, sizeof (Uint16)))
174
175
176
177
178
return(0);
datablockofs = SDL_SwapLE16(datablockofs);
if (SDL_RWseek(src, datablockofs, SEEK_SET) != datablockofs)
179
{
180
BAIL_MACRO("VOC: Failed to seek to data block.", 0);
181
} /* if */
182
183
184
185
186
187
return(1); /* success! */
} /* voc_check_header */
/* Read next block header, save info, leave position at start of data */
188
static int voc_get_block(Sound_Sample *sample, vs_t *v)
189
190
191
192
193
194
195
196
197
198
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *src = internal->rw;
Uint8 bits24[3];
Uint8 uc, block;
Uint32 sblen;
Uint16 new_rate_short;
Uint32 new_rate_long;
Uint8 trash[6];
Uint16 period;
199
Uint32 bytes_per_second;
200
201
202
203
204
205
206
207
208
209
210
211
212
int i;
v->silent = 0;
while (v->rest == 0)
{
if (SDL_RWread(src, &block, sizeof (block), 1) != 1)
return 1; /* assume that's the end of the file. */
if (block == VOC_TERM)
return 1;
if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)
return 1; /* assume that's the end of the file. */
213
214
215
216
217
218
219
/* Size is an 24-bit value. Ugh. */
sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) );
switch(block)
{
case VOC_DATA:
220
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
221
222
223
224
225
226
return 0;
/* When DATA block preceeded by an EXTENDED */
/* block, the DATA blocks rate value is invalid */
if (!v->extended)
{
227
BAIL_IF_MACRO(uc == 0, "VOC: Sample rate is zero?", 0);
228
229
if ((v->rate != -1) && (uc != v->rate))
230
BAIL_MACRO("VOC sample rate codes differ", 0);
231
232
233
234
v->rate = uc;
sample->actual.rate = 1000000.0/(256 - v->rate);
v->channels = 1;
235
} /* if */
236
237
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
238
return(0);
239
240
BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
241
242
243
244
v->extended = 0;
v->rest = sblen - 2;
v->size = ST_SIZE_BYTE;
245
246
247
248
249
250
bytes_per_second = sample->actual.rate
* sample->actual.channels;
sample->total_time += ( v->rest ) / bytes_per_second * 1000;
sample->total_time += (v->rest % bytes_per_second) * 1000
/ bytes_per_second;
251
252
253
return 1;
case VOC_DATA_16:
254
if (!voc_readbytes(src, v, &new_rate_long, sizeof (Uint32)))
255
return 0;
256
257
new_rate_long = SDL_SwapLE32(new_rate_long);
258
259
BAIL_IF_MACRO(!new_rate_long, "VOC: Sample rate is zero?", 0);
260
if ((v->rate != -1) && (new_rate_long != v->rate))
261
262
BAIL_MACRO("VOC: sample rate codes differ", 0);
263
264
265
v->rate = new_rate_long;
sample->actual.rate = new_rate_long;
266
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
267
268
269
270
271
272
273
return 0;
switch (uc)
{
case 8: v->size = ST_SIZE_BYTE; break;
case 16: v->size = ST_SIZE_WORD; break;
default:
274
BAIL_MACRO("VOC: unknown data size", 0);
275
} /* switch */
276
277
if (!voc_readbytes(src, v, &v->channels, sizeof (Uint8)))
278
279
return 0;
280
if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 6))
281
282
return 0;
v->rest = sblen - 12;
283
284
285
286
287
288
bytes_per_second = ((v->size == ST_SIZE_WORD) ? (2) : (1)) *
sample->actual.rate * v->channels;
sample->total_time += v->rest / bytes_per_second * 1000;
sample->total_time += ( v->rest % bytes_per_second ) * 1000
/ bytes_per_second;
289
290
291
292
293
294
295
return 1;
case VOC_CONT:
v->rest = sblen;
return 1;
case VOC_SILENCE:
296
if (!voc_readbytes(src, v, &period, sizeof (period)))
297
return 0;
298
299
300
period = SDL_SwapLE16(period);
301
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
302
return 0;
303
304
BAIL_IF_MACRO(uc == 0, "VOC: silence sample rate is zero", 0);
305
306
307
308
309
310
311
312
313
314
315
316
/*
* Some silence-packed files have gratuitously
* different sample rate codes in silence.
* Adjust period.
*/
if ((v->rate != -1) && (uc != v->rate))
period = (period * (256 - uc))/(256 - v->rate);
else
v->rate = uc;
v->rest = period;
v->silent = 1;
317
318
319
sample->total_time += (period) / (v->rate) * 1000;
sample->total_time += (period % v->rate) * 1000 / v->rate;
320
321
322
323
324
325
return 1;
case VOC_LOOP:
case VOC_LOOPEND:
for(i = 0; i < sblen; i++) /* skip repeat loops. */
{
326
if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
327
return 0;
328
} /* for */
329
330
331
332
333
334
335
336
break;
case VOC_EXTENDED:
/* An Extended block is followed by a data block */
/* Set this byte so we know to use the rate */
/* value from the extended block and not the */
/* data block. */
v->extended = 1;
337
if (!voc_readbytes(src, v, &new_rate_short, sizeof (Uint16)))
338
return 0;
339
340
new_rate_short = SDL_SwapLE16(new_rate_short);
341
342
BAIL_IF_MACRO(!new_rate_short, "VOC: sample rate is zero", 0);
343
if ((v->rate != -1) && (new_rate_short != v->rate))
344
345
BAIL_MACRO("VOC: sample rate codes differ", 0);
346
347
v->rate = new_rate_short;
348
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
349
350
return 0;
351
BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
352
353
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
354
355
356
357
return 0;
if (uc)
sample->actual.channels = 2; /* Stereo */
358
359
360
361
362
363
364
365
366
367
368
/* Needed number of channels before finishing
compute for rate */
sample->actual.rate =
(256000000L/(65536L - v->rate)) / sample->actual.channels;
/* An extended block must be followed by a data */
/* block to be valid so loop back to top so it */
/* can be grabed. */
continue;
case VOC_MARKER:
369
if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 2))
370
371
372
373
374
return 0;
/* Falling! Falling! */
default: /* text block or other krapola. */
375
376
377
378
379
for(i = 0; i < sblen; i++) /* skip repeat loops. */
{
if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
return 0;
} /* for */
380
381
382
if (block == VOC_TEXT)
continue; /* get next block */
383
384
} /* switch */
} /* while */
385
386
return 1;
387
} /* voc_get_block */
388
389
390
static int voc_read_waveform(Sound_Sample *sample, int fill_buf, Uint32 max)
391
392
393
394
395
396
397
398
399
400
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *src = internal->rw;
vs_t *v = (vs_t *) internal->decoder_private;
int done = 0;
Uint8 silence = 0x80;
Uint8 *buf = internal->buffer;
if (v->rest == 0)
{
401
if (!voc_get_block(sample, v))
402
return 0;
403
} /* if */
404
405
406
407
if (v->rest == 0)
return 0;
408
409
max = (v->rest < max) ? v->rest : max;
410
411
412
413
414
415
if (v->silent)
{
if (v->size == ST_SIZE_WORD)
silence = 0x00;
/* Fill in silence */
416
417
418
419
420
421
if (fill_buf)
memset(buf + v->bufpos, silence, max);
done = max;
v->rest -= done;
} /* if */
422
423
424
else
{
425
if (fill_buf)
426
{
427
done = SDL_RWread(src, buf + v->bufpos, 1, max);
428
429
if (done < max)
{
430
__Sound_SetError("VOC: i/o error");
431
432
433
434
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* if */
} /* if */
435
436
437
438
439
440
441
442
443
else
{
int cur, rc;
cur = SDL_RWtell(src);
if (cur >= 0)
{
rc = SDL_RWseek(src, max, SEEK_CUR);
if (rc >= 0)
done = rc - cur;
444
445
else
{
446
__Sound_SetError("VOC: seek error");
447
448
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* else */
449
450
451
} /* if */
} /* else */
452
453
v->rest -= done;
v->bufpos += done;
454
} /* else */
455
456
return(done);
457
} /* voc_read_waveform */
458
459
460
461
462
463
464
465
466
467
468
469
470
471
static int VOC_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = NULL;
if (!voc_check_header(internal->rw))
return(0);
v = (vs_t *) malloc(sizeof (vs_t));
BAIL_IF_MACRO(v == NULL, ERR_OUT_OF_MEMORY, 0);
memset(v, '\0', sizeof (vs_t));
472
v->start_pos = SDL_RWtell(internal->rw);
473
v->rate = -1;
474
if (!voc_get_block(sample, v))
475
476
477
478
479
480
481
482
{
free(v);
return(0);
} /* if */
if (v->rate == -1)
{
free(v);
483
BAIL_MACRO("VOC: data had no sound!", 0);
484
485
} /* if */
486
SNDDBG(("VOC: Accepting data stream.\n"));
487
488
sample->actual.format = (v->size == ST_SIZE_WORD) ? AUDIO_S16LSB:AUDIO_U8;
sample->actual.channels = v->channels;
489
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
490
internal->decoder_private = v;
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
return(1);
} /* VOC_open */
static void VOC_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
free(internal->decoder_private);
} /* VOC_close */
static Uint32 VOC_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
v->bufpos = 0;
while (v->bufpos < internal->buffer_size)
{
510
Uint32 rc = voc_read_waveform(sample, 1, internal->buffer_size);
511
if (rc == 0)
512
{
513
514
515
sample->flags |= (v->error) ?
SOUND_SAMPLEFLAG_ERROR :
SOUND_SAMPLEFLAG_EOF;
516
517
518
break;
} /* if */
519
if (!voc_get_block(sample, v))
520
{
521
522
523
sample->flags |= (v->error) ?
SOUND_SAMPLEFLAG_ERROR :
SOUND_SAMPLEFLAG_EOF;
524
525
526
527
528
529
530
break;
} /* if */
} /* while */
return(v->bufpos);
} /* VOC_read */
531
532
533
static int VOC_rewind(Sound_Sample *sample)
{
534
535
536
537
538
539
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
int rc = SDL_RWseek(internal->rw, v->start_pos, SEEK_SET);
BAIL_IF_MACRO(rc != v->start_pos, ERR_IO_ERROR, 0);
v->rest = 0;
return(1);
540
541
} /* VOC_rewind */
542
543
544
static int VOC_seek(Sound_Sample *sample, Uint32 ms)
{
545
546
547
548
549
550
551
552
553
/*
* VOCs don't lend themselves well to seeking, since you have to
* parse each section, which is an arbitrary size. The best we can do
* is rewind, set a flag saying not to write the waveforms to a buffer,
* and decode to the point that we want. Ugh. Fortunately, there's
* really no such thing as a large VOC, due to the era and hardware that
* spawned them, so even though this is inefficient, this is still a
* relatively fast operation in most cases.
*/
554
555
556
557
558
559
560
561
562
563
564
565
566
567
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int origpos = SDL_RWtell(internal->rw);
int origrest = v->rest;
BAIL_IF_MACRO(!VOC_rewind(sample), NULL, 0);
v->bufpos = 0;
while (offset > 0)
{
Uint32 rc = voc_read_waveform(sample, 0, offset);
568
if ( (rc == 0) || (!voc_get_block(sample, v)) )
569
570
571
572
573
574
575
576
577
578
579
{
SDL_RWseek(internal->rw, origpos, SEEK_SET);
v->rest = origrest;
return(0);
} /* if */
offset -= rc;
} /* while */
return(1);
} /* VOC_seek */
580
581
#endif /* SOUND_SUPPORTS_VOC */
582
583
/* end of voc.c ... */