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