PageRenderTime 44ms CodeModel.GetById 13ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/project/jni/sdl_mixer/load_voc.c

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