wavestream.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 22 Jun 2014 10:08:56 -0700
changeset 684 41ab1dfca52e
parent 642 dae7bb0a66b1
child 686 dd498db4e82e
permissions -rw-r--r--
Fixed bug 1673 - BEXT wave files only have extra metadata that you can easily skip through

bill

In SDL_wave.c, BEXT wave files with "bext" instead of "fmt " are choked on

if (chunk.magic != FMT) {
SDL_SetError("Complex WAVE files not supported");
was_error = 1;
goto done;
}

BEXT files http://en.wikipedia.org/wiki/Broadcast_Wave_Format actually playback the same as regular waves. All they have is (A LOT OF) extra header info.

To open them, just SKIP the "bext" chunk, and the "fmt " chunk will be a couple of hundred bytes later.

The "fmt " chunk is also bloated, but if you skip past the extra information to the "data" chunk, there is nothing different about a BEXT wave file than a "normal" one.

You can then load the data and proceed as normal.
slouken@0
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@601
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@0
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@0
    21
slouken@140
    22
/* $Id$ */
slouken@138
    23
slouken@0
    24
/* This file supports streaming WAV files, without volume adjustment */
slouken@0
    25
slouken@0
    26
#include <stdlib.h>
slouken@0
    27
#include <string.h>
slouken@0
    28
slouken@24
    29
#include "SDL_audio.h"
slouken@24
    30
#include "SDL_mutex.h"
slouken@24
    31
#include "SDL_rwops.h"
slouken@24
    32
#include "SDL_endian.h"
slouken@0
    33
slouken@135
    34
#include "SDL_mixer.h"
slouken@0
    35
#include "wavestream.h"
slouken@0
    36
slouken@111
    37
/*
slouken@111
    38
    Taken with permission from SDL_wave.h, part of the SDL library,
slouken@111
    39
    available at: http://www.libsdl.org/
slouken@111
    40
    and placed under the same license as this mixer library.
slouken@111
    41
*/
slouken@111
    42
slouken@111
    43
/* WAVE files are little-endian */
slouken@111
    44
slouken@111
    45
/*******************************************/
slouken@111
    46
/* Define values for Microsoft WAVE format */
slouken@111
    47
/*******************************************/
slouken@617
    48
#define RIFF        0x46464952      /* "RIFF" */
slouken@617
    49
#define WAVE        0x45564157      /* "WAVE" */
slouken@617
    50
#define FACT        0x74636166      /* "fact" */
slouken@617
    51
#define LIST        0x5453494c      /* "LIST" */
slouken@684
    52
#define BEXT        0x74786562      /* "bext" */
slouken@684
    53
#define FMT         0x20746D66      /* "fmt " */
slouken@617
    54
#define DATA        0x61746164      /* "data" */
slouken@617
    55
#define PCM_CODE    1
slouken@617
    56
#define ADPCM_CODE  2
slouken@617
    57
#define WAVE_MONO   1
slouken@617
    58
#define WAVE_STEREO 2
slouken@111
    59
slouken@111
    60
/* Normally, these three chunks come consecutively in a WAVE file */
slouken@111
    61
typedef struct WaveFMT {
slouken@111
    62
/* Not saved in the chunk we read:
slouken@617
    63
    Uint32  FMTchunk;
slouken@617
    64
    Uint32  fmtlen;
slouken@111
    65
*/
slouken@617
    66
    Uint16  encoding;
slouken@617
    67
    Uint16  channels;       /* 1 = mono, 2 = stereo */
slouken@617
    68
    Uint32  frequency;      /* One of 11025, 22050, or 44100 Hz */
slouken@617
    69
    Uint32  byterate;       /* Average bytes per second */
slouken@617
    70
    Uint16  blockalign;     /* Bytes per sample block */
slouken@617
    71
    Uint16  bitspersample;      /* One of 8, 12, 16, or 4 for ADPCM */
slouken@111
    72
} WaveFMT;
slouken@111
    73
slouken@111
    74
/* The general chunk found in the WAVE file */
slouken@111
    75
typedef struct Chunk {
slouken@617
    76
    Uint32 magic;
slouken@617
    77
    Uint32 length;
slouken@617
    78
    Uint8 *data;            /* Data includes magic and length */
slouken@111
    79
} Chunk;
slouken@111
    80
slouken@111
    81
/*********************************************/
slouken@111
    82
/* Define values for AIFF (IFF audio) format */
slouken@111
    83
/*********************************************/
slouken@617
    84
#define FORM        0x4d524f46      /* "FORM" */
slouken@617
    85
#define AIFF        0x46464941      /* "AIFF" */
slouken@617
    86
#define SSND        0x444e5353      /* "SSND" */
slouken@617
    87
#define COMM        0x4d4d4f43      /* "COMM" */
slouken@111
    88
slouken@111
    89
slouken@64
    90
/* Currently we only support a single stream at a time */
slouken@173
    91
static WAVStream *music = NULL;
slouken@64
    92
slouken@0
    93
/* This is the format of the audio mixer data */
slouken@0
    94
static SDL_AudioSpec mixer;
slouken@214
    95
static int wavestream_volume = MIX_MAX_VOLUME;
slouken@0
    96
slouken@0
    97
/* Function to load the WAV/AIFF stream */
slouken@381
    98
static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@617
    99
                    long *start, long *stop);
slouken@381
   100
static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@617
   101
                    long *start, long *stop);
slouken@0
   102
slouken@0
   103
/* Initialize the WAVStream player, with the given mixer settings
slouken@0
   104
   This function returns 0, or -1 if there was an error.
slouken@0
   105
 */
slouken@0
   106
int WAVStream_Init(SDL_AudioSpec *mixerfmt)
slouken@0
   107
{
slouken@617
   108
    mixer = *mixerfmt;
slouken@617
   109
    return(0);
slouken@0
   110
}
slouken@0
   111
slouken@214
   112
void WAVStream_SetVolume(int volume)
slouken@0
   113
{
slouken@617
   114
    wavestream_volume = volume;
slouken@0
   115
}
slouken@0
   116
slouken@542
   117
/* Load a WAV stream from the given RWops object */
slouken@625
   118
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *src, int freesrc)
slouken@0
   119
{
slouken@617
   120
    WAVStream *wave;
slouken@617
   121
    SDL_AudioSpec wavespec;
slouken@0
   122
slouken@617
   123
    if ( ! mixer.format ) {
slouken@617
   124
        Mix_SetError("WAV music output not started");
slouken@617
   125
        return(NULL);
slouken@617
   126
    }
slouken@617
   127
    wave = (WAVStream *)SDL_malloc(sizeof *wave);
slouken@617
   128
    if ( wave ) {
slouken@625
   129
        Uint32 magic;
slouken@625
   130
slouken@625
   131
        SDL_zerop(wave);
slouken@625
   132
        wave->freesrc = freesrc;
slouken@625
   133
slouken@625
   134
        magic = SDL_ReadLE32(src);
slouken@625
   135
        if ( magic == RIFF || magic == WAVE ) {
slouken@625
   136
            wave->src = LoadWAVStream(src, &wavespec, &wave->start, &wave->stop);
slouken@625
   137
        } else if ( magic == FORM ) {
slouken@625
   138
            wave->src = LoadAIFFStream(src, &wavespec, &wave->start, &wave->stop);
slouken@617
   139
        } else {
slouken@617
   140
            Mix_SetError("Unknown WAVE format");
slouken@617
   141
        }
slouken@625
   142
        if ( wave->src == NULL ) {
slouken@617
   143
            SDL_free(wave);
slouken@617
   144
            return(NULL);
slouken@617
   145
        }
slouken@617
   146
        SDL_BuildAudioCVT(&wave->cvt,
slouken@617
   147
            wavespec.format, wavespec.channels, wavespec.freq,
slouken@617
   148
            mixer.format, mixer.channels, mixer.freq);
slouken@617
   149
    } else {
slouken@617
   150
        SDL_OutOfMemory();
slouken@617
   151
        return(NULL);
slouken@617
   152
    }
slouken@617
   153
    return(wave);
slouken@0
   154
}
slouken@0
   155
slouken@0
   156
/* Start playback of a given WAV stream */
slouken@214
   157
void WAVStream_Start(WAVStream *wave)
slouken@0
   158
{
slouken@625
   159
    SDL_RWseek (wave->src, wave->start, RW_SEEK_SET);
slouken@617
   160
    music = wave;
slouken@0
   161
}
slouken@0
   162
slouken@173
   163
/* Play some of a stream previously started with WAVStream_Start() */
slouken@407
   164
int WAVStream_PlaySome(Uint8 *stream, int len)
slouken@0
   165
{
slouken@621
   166
    Sint64 pos;
slouken@621
   167
    Sint64 left = 0;
slouken@0
   168
slouken@625
   169
    if ( music && ((pos=SDL_RWtell(music->src)) < music->stop) ) {
slouken@617
   170
        if ( music->cvt.needed ) {
slouken@617
   171
            int original_len;
slouken@0
   172
slouken@617
   173
            original_len=(int)((double)len/music->cvt.len_ratio);
slouken@617
   174
            if ( music->cvt.len != original_len ) {
slouken@617
   175
                int worksize;
slouken@617
   176
                if ( music->cvt.buf != NULL ) {
slouken@617
   177
                    SDL_free(music->cvt.buf);
slouken@617
   178
                }
slouken@617
   179
                worksize = original_len*music->cvt.len_mult;
slouken@617
   180
                music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
slouken@617
   181
                if ( music->cvt.buf == NULL ) {
slouken@617
   182
                    return 0;
slouken@617
   183
                }
slouken@617
   184
                music->cvt.len = original_len;
slouken@617
   185
            }
slouken@617
   186
            if ( (music->stop - pos) < original_len ) {
slouken@617
   187
                left = (original_len - (music->stop - pos));
aschiffler@642
   188
                original_len -= (int)left;
slouken@617
   189
                left = (int)((double)left*music->cvt.len_ratio);
slouken@617
   190
            }
slouken@625
   191
            original_len = SDL_RWread(music->src, music->cvt.buf,1,original_len);
slouken@617
   192
            /* At least at the time of writing, SDL_ConvertAudio()
slouken@617
   193
               does byte-order swapping starting at the end of the
slouken@617
   194
               buffer. Thus, if we are reading 16-bit samples, we
slouken@617
   195
               had better make damn sure that we get an even
slouken@617
   196
               number of bytes, or we'll get garbage.
slouken@617
   197
             */
slouken@617
   198
            if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
slouken@617
   199
                original_len--;
slouken@617
   200
            }
slouken@617
   201
            music->cvt.len = original_len;
slouken@617
   202
            SDL_ConvertAudio(&music->cvt);
slouken@617
   203
            SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
slouken@617
   204
        } else {
slouken@617
   205
            Uint8 *data;
slouken@617
   206
            if ( (music->stop - pos) < len ) {
slouken@617
   207
                left = (len - (music->stop - pos));
aschiffler@642
   208
                len -= (int)left;
slouken@617
   209
            }
slouken@617
   210
            data = SDL_stack_alloc(Uint8, len);
slouken@617
   211
            if (data)
slouken@617
   212
            {
slouken@625
   213
                SDL_RWread(music->src, data, len, 1);
slouken@617
   214
                SDL_MixAudio(stream, data, len, wavestream_volume);
slouken@617
   215
                SDL_stack_free(data);
slouken@617
   216
            }
slouken@617
   217
        }
slouken@617
   218
    }
aschiffler@642
   219
    return (int)left;
slouken@0
   220
}
slouken@0
   221
slouken@0
   222
/* Stop playback of a stream previously started with WAVStream_Start() */
slouken@214
   223
void WAVStream_Stop(void)
slouken@0
   224
{
slouken@617
   225
    music = NULL;
slouken@0
   226
}
slouken@0
   227
slouken@0
   228
/* Close the given WAV stream */
slouken@214
   229
void WAVStream_FreeSong(WAVStream *wave)
slouken@0
   230
{
slouken@617
   231
    if ( wave ) {
slouken@617
   232
        /* Clean up associated data */
slouken@617
   233
        if ( wave->cvt.buf ) {
slouken@617
   234
            SDL_free(wave->cvt.buf);
slouken@617
   235
        }
slouken@625
   236
        if ( wave->freesrc ) {
slouken@625
   237
            SDL_RWclose(wave->src);
slouken@617
   238
        }
slouken@617
   239
        SDL_free(wave);
slouken@617
   240
    }
slouken@0
   241
}
slouken@0
   242
slouken@0
   243
/* Return non-zero if a stream is currently playing */
slouken@214
   244
int WAVStream_Active(void)
slouken@0
   245
{
slouken@617
   246
    int active;
slouken@0
   247
slouken@617
   248
    active = 0;
slouken@625
   249
    if ( music && (SDL_RWtell(music->src) < music->stop) ) {
slouken@617
   250
        active = 1;
slouken@617
   251
    }
slouken@617
   252
    return(active);
slouken@0
   253
}
slouken@0
   254
slouken@0
   255
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
slouken@0
   256
{
slouken@617
   257
    chunk->magic    = SDL_ReadLE32(src);
slouken@617
   258
    chunk->length   = SDL_ReadLE32(src);
slouken@617
   259
    if ( read_data ) {
slouken@617
   260
        chunk->data = (Uint8 *)SDL_malloc(chunk->length);
slouken@617
   261
        if ( chunk->data == NULL ) {
slouken@617
   262
            Mix_SetError("Out of memory");
slouken@617
   263
            return(-1);
slouken@617
   264
        }
slouken@617
   265
        if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
slouken@617
   266
            Mix_SetError("Couldn't read chunk");
slouken@617
   267
            SDL_free(chunk->data);
slouken@617
   268
            return(-1);
slouken@617
   269
        }
slouken@617
   270
    } else {
slouken@617
   271
        SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
slouken@617
   272
    }
slouken@617
   273
    return(chunk->length);
slouken@0
   274
}
slouken@0
   275
slouken@381
   276
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@617
   277
                    long *start, long *stop)
slouken@0
   278
{
slouken@617
   279
    int was_error;
slouken@617
   280
    Chunk chunk;
slouken@617
   281
    int lenread;
slouken@0
   282
slouken@617
   283
    /* WAV magic header */
slouken@617
   284
    Uint32 wavelen;
slouken@617
   285
    Uint32 WAVEmagic;
slouken@0
   286
slouken@617
   287
    /* FMT chunk */
slouken@617
   288
    WaveFMT *format = NULL;
slouken@0
   289
slouken@617
   290
    was_error = 0;
slouken@29
   291
slouken@617
   292
    /* Check the magic header */
slouken@617
   293
    wavelen     = SDL_ReadLE32(src);
slouken@617
   294
    WAVEmagic   = SDL_ReadLE32(src);
slouken@0
   295
slouken@617
   296
    /* Read the audio data format chunk */
slouken@617
   297
    chunk.data = NULL;
slouken@617
   298
    do {
slouken@617
   299
        /* FIXME! Add this logic to SDL_LoadWAV_RW() */
slouken@617
   300
        if ( chunk.data ) {
slouken@617
   301
            SDL_free(chunk.data);
slouken@617
   302
        }
slouken@617
   303
        lenread = ReadChunk(src, &chunk, 1);
slouken@617
   304
        if ( lenread < 0 ) {
slouken@617
   305
            was_error = 1;
slouken@617
   306
            goto done;
slouken@617
   307
        }
slouken@684
   308
    } while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT));
slouken@0
   309
slouken@617
   310
    /* Decode the audio data format */
slouken@617
   311
    format = (WaveFMT *)chunk.data;
slouken@617
   312
    if ( chunk.magic != FMT ) {
slouken@617
   313
        SDL_free(chunk.data);
slouken@617
   314
        Mix_SetError("Complex WAVE files not supported");
slouken@617
   315
        was_error = 1;
slouken@617
   316
        goto done;
slouken@617
   317
    }
slouken@617
   318
    switch (SDL_SwapLE16(format->encoding)) {
slouken@617
   319
        case PCM_CODE:
slouken@617
   320
            /* We can understand this */
slouken@617
   321
            break;
slouken@617
   322
        default:
slouken@617
   323
            Mix_SetError("Unknown WAVE data format");
slouken@617
   324
            was_error = 1;
slouken@617
   325
            goto done;
slouken@617
   326
    }
slouken@621
   327
    SDL_memset(spec, 0, (sizeof *spec));
slouken@617
   328
    spec->freq = SDL_SwapLE32(format->frequency);
slouken@617
   329
    switch (SDL_SwapLE16(format->bitspersample)) {
slouken@617
   330
        case 8:
slouken@617
   331
            spec->format = AUDIO_U8;
slouken@617
   332
            break;
slouken@617
   333
        case 16:
slouken@617
   334
            spec->format = AUDIO_S16;
slouken@617
   335
            break;
slouken@617
   336
        default:
slouken@617
   337
            Mix_SetError("Unknown PCM data format");
slouken@617
   338
            was_error = 1;
slouken@617
   339
            goto done;
slouken@617
   340
    }
slouken@617
   341
    spec->channels = (Uint8) SDL_SwapLE16(format->channels);
slouken@617
   342
    spec->samples = 4096;       /* Good default buffer size */
slouken@0
   343
slouken@617
   344
    /* Set the file offset to the DATA chunk data */
slouken@617
   345
    chunk.data = NULL;
slouken@617
   346
    do {
aschiffler@642
   347
        *start = (long)SDL_RWtell(src) + 2*sizeof(Uint32);
slouken@617
   348
        lenread = ReadChunk(src, &chunk, 0);
slouken@617
   349
        if ( lenread < 0 ) {
slouken@617
   350
            was_error = 1;
slouken@617
   351
            goto done;
slouken@617
   352
        }
slouken@617
   353
    } while ( chunk.magic != DATA );
aschiffler@642
   354
    *stop = (long)SDL_RWtell(src);
slouken@0
   355
slouken@0
   356
done:
slouken@617
   357
    if ( format != NULL ) {
slouken@617
   358
        SDL_free(format);
slouken@617
   359
    }
slouken@617
   360
    if ( was_error ) {
slouken@617
   361
        return NULL;
slouken@617
   362
    }
slouken@617
   363
    return(src);
slouken@0
   364
}
slouken@0
   365
slouken@95
   366
/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
slouken@95
   367
 * I don't pretend to fully understand it.
slouken@95
   368
 */
slouken@95
   369
slouken@95
   370
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
slouken@0
   371
{
slouken@617
   372
    /* Negative number? */
slouken@617
   373
    if (sanebuf[0] & 0x80)
slouken@617
   374
        return 0;
slouken@0
   375
slouken@617
   376
    /* Less than 1? */
slouken@617
   377
    if (sanebuf[0] <= 0x3F)
slouken@617
   378
        return 1;
slouken@95
   379
slouken@617
   380
    /* Way too big? */
slouken@617
   381
    if (sanebuf[0] > 0x40)
slouken@617
   382
        return 0x4000000;
slouken@95
   383
slouken@617
   384
    /* Still too big? */
slouken@617
   385
    if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
slouken@617
   386
        return 800000000;
slouken@95
   387
slouken@617
   388
    return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
slouken@617
   389
        | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
slouken@0
   390
}
slouken@0
   391
slouken@381
   392
static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@617
   393
                    long *start, long *stop)
slouken@0
   394
{
slouken@617
   395
    int was_error;
slouken@617
   396
    int found_SSND;
slouken@617
   397
    int found_COMM;
slouken@0
   398
slouken@617
   399
    Uint32 chunk_type;
slouken@617
   400
    Uint32 chunk_length;
slouken@621
   401
    Sint64 next_chunk;
slouken@95
   402
slouken@617
   403
    /* AIFF magic header */
slouken@617
   404
    Uint32 AIFFmagic;
slouken@617
   405
    /* SSND chunk        */
slouken@617
   406
    Uint32 offset;
slouken@617
   407
    Uint32 blocksize;
slouken@617
   408
    /* COMM format chunk */
slouken@617
   409
    Uint16 channels = 0;
slouken@617
   410
    Uint32 numsamples = 0;
slouken@617
   411
    Uint16 samplesize = 0;
slouken@617
   412
    Uint8 sane_freq[10];
slouken@617
   413
    Uint32 frequency = 0;
slouken@0
   414
slouken@617
   415
    was_error = 0;
slouken@29
   416
slouken@617
   417
    /* Check the magic header */
slouken@617
   418
    chunk_length    = SDL_ReadBE32(src);
slouken@617
   419
    AIFFmagic   = SDL_ReadLE32(src);
slouken@625
   420
    if ( AIFFmagic != AIFF ) {
slouken@617
   421
        Mix_SetError("Unrecognized file type (not AIFF)");
slouken@617
   422
        was_error = 1;
slouken@617
   423
        goto done;
slouken@617
   424
    }
slouken@0
   425
slouken@617
   426
    /* From what I understand of the specification, chunks may appear in
slouken@95
   427
         * any order, and we should just ignore unknown ones.
slouken@617
   428
     *
slouken@617
   429
     * TODO: Better sanity-checking. E.g. what happens if the AIFF file
slouken@617
   430
     *       contains compressed sound data?
slouken@625
   431
     */
slouken@95
   432
slouken@617
   433
    found_SSND = 0;
slouken@617
   434
    found_COMM = 0;
slouken@95
   435
slouken@617
   436
    do {
slouken@617
   437
        chunk_type      = SDL_ReadLE32(src);
slouken@617
   438
        chunk_length    = SDL_ReadBE32(src);
slouken@617
   439
        next_chunk      = SDL_RWtell(src) + chunk_length;
slouken@95
   440
slouken@617
   441
        /* Paranoia to avoid infinite loops */
slouken@617
   442
        if (chunk_length == 0)
slouken@617
   443
        break;
slouken@95
   444
slouken@625
   445
        switch (chunk_type) {
slouken@617
   446
        case SSND:
slouken@617
   447
            found_SSND      = 1;
slouken@617
   448
            offset      = SDL_ReadBE32(src);
slouken@617
   449
            blocksize       = SDL_ReadBE32(src);
aschiffler@642
   450
            *start      = (long)SDL_RWtell(src) + offset;
slouken@617
   451
            break;
slouken@95
   452
slouken@617
   453
        case COMM:
slouken@617
   454
            found_COMM      = 1;
slouken@95
   455
slouken@617
   456
            /* Read the audio data format chunk */
slouken@617
   457
            channels        = SDL_ReadBE16(src);
slouken@617
   458
            numsamples      = SDL_ReadBE32(src);
slouken@617
   459
            samplesize      = SDL_ReadBE16(src);
slouken@617
   460
            SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
slouken@617
   461
            frequency       = SANE_to_Uint32(sane_freq);
slouken@617
   462
            break;
slouken@95
   463
slouken@617
   464
        default:
slouken@617
   465
            break;
slouken@617
   466
        }
slouken@617
   467
    } while ((!found_SSND || !found_COMM)
slouken@617
   468
         && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
slouken@95
   469
slouken@617
   470
    if (!found_SSND) {
slouken@617
   471
        Mix_SetError("Bad AIFF file (no SSND chunk)");
slouken@617
   472
        was_error = 1;
slouken@617
   473
        goto done;
slouken@617
   474
    }
slouken@0
   475
slouken@617
   476
    if (!found_COMM) {
slouken@617
   477
        Mix_SetError("Bad AIFF file (no COMM chunk)");
slouken@617
   478
        was_error = 1;
slouken@617
   479
        goto done;
slouken@617
   480
    }
slouken@0
   481
slouken@617
   482
    *stop = *start + channels * numsamples * (samplesize / 8);
slouken@617
   483
slouken@617
   484
    /* Decode the audio data format */
slouken@621
   485
    SDL_memset(spec, 0, (sizeof *spec));
slouken@617
   486
    spec->freq = frequency;
slouken@617
   487
    switch (samplesize) {
slouken@617
   488
        case 8:
slouken@617
   489
            spec->format = AUDIO_S8;
slouken@617
   490
            break;
slouken@617
   491
        case 16:
slouken@617
   492
            spec->format = AUDIO_S16MSB;
slouken@617
   493
            break;
slouken@617
   494
        default:
slouken@617
   495
            Mix_SetError("Unknown samplesize in data format");
slouken@617
   496
            was_error = 1;
slouken@617
   497
            goto done;
slouken@617
   498
    }
slouken@617
   499
    spec->channels = (Uint8) channels;
slouken@617
   500
    spec->samples = 4096;       /* Good default buffer size */
slouken@0
   501
slouken@0
   502
done:
slouken@617
   503
    if ( was_error ) {
slouken@617
   504
        return NULL;
slouken@617
   505
    }
slouken@617
   506
    return(src);
slouken@0
   507
}
slouken@308
   508