wavestream.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 01 Jun 2013 19:52:15 -0700
changeset 625 1d489d8ec2e0
parent 621 944412baab72
child 642 dae7bb0a66b1
permissions -rw-r--r--
SDL_LoadMUS_RW() now takes an argument telling whether or not the data source should be freed when done.
Fixes crashes cleaning up the data source for music when loading fails.
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@625
   117
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *src, int freesrc)
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
        return(NULL);
slouken@617
   125
    }
slouken@617
   126
    wave = (WAVStream *)SDL_malloc(sizeof *wave);
slouken@617
   127
    if ( wave ) {
slouken@625
   128
        Uint32 magic;
slouken@625
   129
slouken@625
   130
        SDL_zerop(wave);
slouken@625
   131
        wave->freesrc = freesrc;
slouken@625
   132
slouken@625
   133
        magic = SDL_ReadLE32(src);
slouken@625
   134
        if ( magic == RIFF || magic == WAVE ) {
slouken@625
   135
            wave->src = LoadWAVStream(src, &wavespec, &wave->start, &wave->stop);
slouken@625
   136
        } else if ( magic == FORM ) {
slouken@625
   137
            wave->src = LoadAIFFStream(src, &wavespec, &wave->start, &wave->stop);
slouken@617
   138
        } else {
slouken@617
   139
            Mix_SetError("Unknown WAVE format");
slouken@617
   140
        }
slouken@625
   141
        if ( wave->src == NULL ) {
slouken@617
   142
            SDL_free(wave);
slouken@617
   143
            return(NULL);
slouken@617
   144
        }
slouken@617
   145
        SDL_BuildAudioCVT(&wave->cvt,
slouken@617
   146
            wavespec.format, wavespec.channels, wavespec.freq,
slouken@617
   147
            mixer.format, mixer.channels, mixer.freq);
slouken@617
   148
    } else {
slouken@617
   149
        SDL_OutOfMemory();
slouken@617
   150
        return(NULL);
slouken@617
   151
    }
slouken@617
   152
    return(wave);
slouken@0
   153
}
slouken@0
   154
slouken@0
   155
/* Start playback of a given WAV stream */
slouken@214
   156
void WAVStream_Start(WAVStream *wave)
slouken@0
   157
{
slouken@625
   158
    SDL_RWseek (wave->src, wave->start, RW_SEEK_SET);
slouken@617
   159
    music = wave;
slouken@0
   160
}
slouken@0
   161
slouken@173
   162
/* Play some of a stream previously started with WAVStream_Start() */
slouken@407
   163
int WAVStream_PlaySome(Uint8 *stream, int len)
slouken@0
   164
{
slouken@621
   165
    Sint64 pos;
slouken@621
   166
    Sint64 left = 0;
slouken@0
   167
slouken@625
   168
    if ( music && ((pos=SDL_RWtell(music->src)) < music->stop) ) {
slouken@617
   169
        if ( music->cvt.needed ) {
slouken@617
   170
            int original_len;
slouken@0
   171
slouken@617
   172
            original_len=(int)((double)len/music->cvt.len_ratio);
slouken@617
   173
            if ( music->cvt.len != original_len ) {
slouken@617
   174
                int worksize;
slouken@617
   175
                if ( music->cvt.buf != NULL ) {
slouken@617
   176
                    SDL_free(music->cvt.buf);
slouken@617
   177
                }
slouken@617
   178
                worksize = original_len*music->cvt.len_mult;
slouken@617
   179
                music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
slouken@617
   180
                if ( music->cvt.buf == NULL ) {
slouken@617
   181
                    return 0;
slouken@617
   182
                }
slouken@617
   183
                music->cvt.len = original_len;
slouken@617
   184
            }
slouken@617
   185
            if ( (music->stop - pos) < original_len ) {
slouken@617
   186
                left = (original_len - (music->stop - pos));
slouken@617
   187
                original_len -= left;
slouken@617
   188
                left = (int)((double)left*music->cvt.len_ratio);
slouken@617
   189
            }
slouken@625
   190
            original_len = SDL_RWread(music->src, music->cvt.buf,1,original_len);
slouken@617
   191
            /* At least at the time of writing, SDL_ConvertAudio()
slouken@617
   192
               does byte-order swapping starting at the end of the
slouken@617
   193
               buffer. Thus, if we are reading 16-bit samples, we
slouken@617
   194
               had better make damn sure that we get an even
slouken@617
   195
               number of bytes, or we'll get garbage.
slouken@617
   196
             */
slouken@617
   197
            if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
slouken@617
   198
                original_len--;
slouken@617
   199
            }
slouken@617
   200
            music->cvt.len = original_len;
slouken@617
   201
            SDL_ConvertAudio(&music->cvt);
slouken@617
   202
            SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
slouken@617
   203
        } else {
slouken@617
   204
            Uint8 *data;
slouken@617
   205
            if ( (music->stop - pos) < len ) {
slouken@617
   206
                left = (len - (music->stop - pos));
slouken@617
   207
                len -= left;
slouken@617
   208
            }
slouken@617
   209
            data = SDL_stack_alloc(Uint8, len);
slouken@617
   210
            if (data)
slouken@617
   211
            {
slouken@625
   212
                SDL_RWread(music->src, data, len, 1);
slouken@617
   213
                SDL_MixAudio(stream, data, len, wavestream_volume);
slouken@617
   214
                SDL_stack_free(data);
slouken@617
   215
            }
slouken@617
   216
        }
slouken@617
   217
    }
slouken@617
   218
    return left;
slouken@0
   219
}
slouken@0
   220
slouken@0
   221
/* Stop playback of a stream previously started with WAVStream_Start() */
slouken@214
   222
void WAVStream_Stop(void)
slouken@0
   223
{
slouken@617
   224
    music = NULL;
slouken@0
   225
}
slouken@0
   226
slouken@0
   227
/* Close the given WAV stream */
slouken@214
   228
void WAVStream_FreeSong(WAVStream *wave)
slouken@0
   229
{
slouken@617
   230
    if ( wave ) {
slouken@617
   231
        /* Clean up associated data */
slouken@617
   232
        if ( wave->cvt.buf ) {
slouken@617
   233
            SDL_free(wave->cvt.buf);
slouken@617
   234
        }
slouken@625
   235
        if ( wave->freesrc ) {
slouken@625
   236
            SDL_RWclose(wave->src);
slouken@617
   237
        }
slouken@617
   238
        SDL_free(wave);
slouken@617
   239
    }
slouken@0
   240
}
slouken@0
   241
slouken@0
   242
/* Return non-zero if a stream is currently playing */
slouken@214
   243
int WAVStream_Active(void)
slouken@0
   244
{
slouken@617
   245
    int active;
slouken@0
   246
slouken@617
   247
    active = 0;
slouken@625
   248
    if ( music && (SDL_RWtell(music->src) < music->stop) ) {
slouken@617
   249
        active = 1;
slouken@617
   250
    }
slouken@617
   251
    return(active);
slouken@0
   252
}
slouken@0
   253
slouken@0
   254
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
slouken@0
   255
{
slouken@617
   256
    chunk->magic    = SDL_ReadLE32(src);
slouken@617
   257
    chunk->length   = SDL_ReadLE32(src);
slouken@617
   258
    if ( read_data ) {
slouken@617
   259
        chunk->data = (Uint8 *)SDL_malloc(chunk->length);
slouken@617
   260
        if ( chunk->data == NULL ) {
slouken@617
   261
            Mix_SetError("Out of memory");
slouken@617
   262
            return(-1);
slouken@617
   263
        }
slouken@617
   264
        if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
slouken@617
   265
            Mix_SetError("Couldn't read chunk");
slouken@617
   266
            SDL_free(chunk->data);
slouken@617
   267
            return(-1);
slouken@617
   268
        }
slouken@617
   269
    } else {
slouken@617
   270
        SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
slouken@617
   271
    }
slouken@617
   272
    return(chunk->length);
slouken@0
   273
}
slouken@0
   274
slouken@381
   275
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@617
   276
                    long *start, long *stop)
slouken@0
   277
{
slouken@617
   278
    int was_error;
slouken@617
   279
    Chunk chunk;
slouken@617
   280
    int lenread;
slouken@0
   281
slouken@617
   282
    /* WAV magic header */
slouken@617
   283
    Uint32 wavelen;
slouken@617
   284
    Uint32 WAVEmagic;
slouken@0
   285
slouken@617
   286
    /* FMT chunk */
slouken@617
   287
    WaveFMT *format = NULL;
slouken@0
   288
slouken@617
   289
    was_error = 0;
slouken@29
   290
slouken@617
   291
    /* Check the magic header */
slouken@617
   292
    wavelen     = SDL_ReadLE32(src);
slouken@617
   293
    WAVEmagic   = SDL_ReadLE32(src);
slouken@0
   294
slouken@617
   295
    /* Read the audio data format chunk */
slouken@617
   296
    chunk.data = NULL;
slouken@617
   297
    do {
slouken@617
   298
        /* FIXME! Add this logic to SDL_LoadWAV_RW() */
slouken@617
   299
        if ( chunk.data ) {
slouken@617
   300
            SDL_free(chunk.data);
slouken@617
   301
        }
slouken@617
   302
        lenread = ReadChunk(src, &chunk, 1);
slouken@617
   303
        if ( lenread < 0 ) {
slouken@617
   304
            was_error = 1;
slouken@617
   305
            goto done;
slouken@617
   306
        }
slouken@617
   307
    } while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
slouken@0
   308
slouken@617
   309
    /* Decode the audio data format */
slouken@617
   310
    format = (WaveFMT *)chunk.data;
slouken@617
   311
    if ( chunk.magic != FMT ) {
slouken@617
   312
        SDL_free(chunk.data);
slouken@617
   313
        Mix_SetError("Complex WAVE files not supported");
slouken@617
   314
        was_error = 1;
slouken@617
   315
        goto done;
slouken@617
   316
    }
slouken@617
   317
    switch (SDL_SwapLE16(format->encoding)) {
slouken@617
   318
        case PCM_CODE:
slouken@617
   319
            /* We can understand this */
slouken@617
   320
            break;
slouken@617
   321
        default:
slouken@617
   322
            Mix_SetError("Unknown WAVE data format");
slouken@617
   323
            was_error = 1;
slouken@617
   324
            goto done;
slouken@617
   325
    }
slouken@621
   326
    SDL_memset(spec, 0, (sizeof *spec));
slouken@617
   327
    spec->freq = SDL_SwapLE32(format->frequency);
slouken@617
   328
    switch (SDL_SwapLE16(format->bitspersample)) {
slouken@617
   329
        case 8:
slouken@617
   330
            spec->format = AUDIO_U8;
slouken@617
   331
            break;
slouken@617
   332
        case 16:
slouken@617
   333
            spec->format = AUDIO_S16;
slouken@617
   334
            break;
slouken@617
   335
        default:
slouken@617
   336
            Mix_SetError("Unknown PCM data format");
slouken@617
   337
            was_error = 1;
slouken@617
   338
            goto done;
slouken@617
   339
    }
slouken@617
   340
    spec->channels = (Uint8) SDL_SwapLE16(format->channels);
slouken@617
   341
    spec->samples = 4096;       /* Good default buffer size */
slouken@0
   342
slouken@617
   343
    /* Set the file offset to the DATA chunk data */
slouken@617
   344
    chunk.data = NULL;
slouken@617
   345
    do {
slouken@617
   346
        *start = SDL_RWtell(src) + 2*sizeof(Uint32);
slouken@617
   347
        lenread = ReadChunk(src, &chunk, 0);
slouken@617
   348
        if ( lenread < 0 ) {
slouken@617
   349
            was_error = 1;
slouken@617
   350
            goto done;
slouken@617
   351
        }
slouken@617
   352
    } while ( chunk.magic != DATA );
slouken@617
   353
    *stop = SDL_RWtell(src);
slouken@0
   354
slouken@0
   355
done:
slouken@617
   356
    if ( format != NULL ) {
slouken@617
   357
        SDL_free(format);
slouken@617
   358
    }
slouken@617
   359
    if ( was_error ) {
slouken@617
   360
        return NULL;
slouken@617
   361
    }
slouken@617
   362
    return(src);
slouken@0
   363
}
slouken@0
   364
slouken@95
   365
/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
slouken@95
   366
 * I don't pretend to fully understand it.
slouken@95
   367
 */
slouken@95
   368
slouken@95
   369
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
slouken@0
   370
{
slouken@617
   371
    /* Negative number? */
slouken@617
   372
    if (sanebuf[0] & 0x80)
slouken@617
   373
        return 0;
slouken@0
   374
slouken@617
   375
    /* Less than 1? */
slouken@617
   376
    if (sanebuf[0] <= 0x3F)
slouken@617
   377
        return 1;
slouken@95
   378
slouken@617
   379
    /* Way too big? */
slouken@617
   380
    if (sanebuf[0] > 0x40)
slouken@617
   381
        return 0x4000000;
slouken@95
   382
slouken@617
   383
    /* Still too big? */
slouken@617
   384
    if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
slouken@617
   385
        return 800000000;
slouken@95
   386
slouken@617
   387
    return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
slouken@617
   388
        | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
slouken@0
   389
}
slouken@0
   390
slouken@381
   391
static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@617
   392
                    long *start, long *stop)
slouken@0
   393
{
slouken@617
   394
    int was_error;
slouken@617
   395
    int found_SSND;
slouken@617
   396
    int found_COMM;
slouken@0
   397
slouken@617
   398
    Uint32 chunk_type;
slouken@617
   399
    Uint32 chunk_length;
slouken@621
   400
    Sint64 next_chunk;
slouken@95
   401
slouken@617
   402
    /* AIFF magic header */
slouken@617
   403
    Uint32 AIFFmagic;
slouken@617
   404
    /* SSND chunk        */
slouken@617
   405
    Uint32 offset;
slouken@617
   406
    Uint32 blocksize;
slouken@617
   407
    /* COMM format chunk */
slouken@617
   408
    Uint16 channels = 0;
slouken@617
   409
    Uint32 numsamples = 0;
slouken@617
   410
    Uint16 samplesize = 0;
slouken@617
   411
    Uint8 sane_freq[10];
slouken@617
   412
    Uint32 frequency = 0;
slouken@0
   413
slouken@617
   414
    was_error = 0;
slouken@29
   415
slouken@617
   416
    /* Check the magic header */
slouken@617
   417
    chunk_length    = SDL_ReadBE32(src);
slouken@617
   418
    AIFFmagic   = SDL_ReadLE32(src);
slouken@625
   419
    if ( AIFFmagic != AIFF ) {
slouken@617
   420
        Mix_SetError("Unrecognized file type (not AIFF)");
slouken@617
   421
        was_error = 1;
slouken@617
   422
        goto done;
slouken@617
   423
    }
slouken@0
   424
slouken@617
   425
    /* From what I understand of the specification, chunks may appear in
slouken@95
   426
         * any order, and we should just ignore unknown ones.
slouken@617
   427
     *
slouken@617
   428
     * TODO: Better sanity-checking. E.g. what happens if the AIFF file
slouken@617
   429
     *       contains compressed sound data?
slouken@625
   430
     */
slouken@95
   431
slouken@617
   432
    found_SSND = 0;
slouken@617
   433
    found_COMM = 0;
slouken@95
   434
slouken@617
   435
    do {
slouken@617
   436
        chunk_type      = SDL_ReadLE32(src);
slouken@617
   437
        chunk_length    = SDL_ReadBE32(src);
slouken@617
   438
        next_chunk      = SDL_RWtell(src) + chunk_length;
slouken@95
   439
slouken@617
   440
        /* Paranoia to avoid infinite loops */
slouken@617
   441
        if (chunk_length == 0)
slouken@617
   442
        break;
slouken@95
   443
slouken@625
   444
        switch (chunk_type) {
slouken@617
   445
        case SSND:
slouken@617
   446
            found_SSND      = 1;
slouken@617
   447
            offset      = SDL_ReadBE32(src);
slouken@617
   448
            blocksize       = SDL_ReadBE32(src);
slouken@617
   449
            *start      = SDL_RWtell(src) + offset;
slouken@617
   450
            break;
slouken@95
   451
slouken@617
   452
        case COMM:
slouken@617
   453
            found_COMM      = 1;
slouken@95
   454
slouken@617
   455
            /* Read the audio data format chunk */
slouken@617
   456
            channels        = SDL_ReadBE16(src);
slouken@617
   457
            numsamples      = SDL_ReadBE32(src);
slouken@617
   458
            samplesize      = SDL_ReadBE16(src);
slouken@617
   459
            SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
slouken@617
   460
            frequency       = SANE_to_Uint32(sane_freq);
slouken@617
   461
            break;
slouken@95
   462
slouken@617
   463
        default:
slouken@617
   464
            break;
slouken@617
   465
        }
slouken@617
   466
    } while ((!found_SSND || !found_COMM)
slouken@617
   467
         && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
slouken@95
   468
slouken@617
   469
    if (!found_SSND) {
slouken@617
   470
        Mix_SetError("Bad AIFF file (no SSND chunk)");
slouken@617
   471
        was_error = 1;
slouken@617
   472
        goto done;
slouken@617
   473
    }
slouken@0
   474
slouken@617
   475
    if (!found_COMM) {
slouken@617
   476
        Mix_SetError("Bad AIFF file (no COMM chunk)");
slouken@617
   477
        was_error = 1;
slouken@617
   478
        goto done;
slouken@617
   479
    }
slouken@0
   480
slouken@617
   481
    *stop = *start + channels * numsamples * (samplesize / 8);
slouken@617
   482
slouken@617
   483
    /* Decode the audio data format */
slouken@621
   484
    SDL_memset(spec, 0, (sizeof *spec));
slouken@617
   485
    spec->freq = frequency;
slouken@617
   486
    switch (samplesize) {
slouken@617
   487
        case 8:
slouken@617
   488
            spec->format = AUDIO_S8;
slouken@617
   489
            break;
slouken@617
   490
        case 16:
slouken@617
   491
            spec->format = AUDIO_S16MSB;
slouken@617
   492
            break;
slouken@617
   493
        default:
slouken@617
   494
            Mix_SetError("Unknown samplesize in data format");
slouken@617
   495
            was_error = 1;
slouken@617
   496
            goto done;
slouken@617
   497
    }
slouken@617
   498
    spec->channels = (Uint8) channels;
slouken@617
   499
    spec->samples = 4096;       /* Good default buffer size */
slouken@0
   500
slouken@0
   501
done:
slouken@617
   502
    if ( was_error ) {
slouken@617
   503
        return NULL;
slouken@617
   504
    }
slouken@617
   505
    return(src);
slouken@0
   506
}
slouken@308
   507