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