wavestream.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 Jul 2014 00:42:06 -0700
changeset 693 b9ed366f0154
parent 686 dd498db4e82e
child 709 1ef7c1254ffb
permissions -rw-r--r--
Skip JUNK chunks in wave files
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@693
    53
#define JUNK        0x4B4E554A      /* "JUNK" */
slouken@684
    54
#define FMT         0x20746D66      /* "fmt " */
slouken@617
    55
#define DATA        0x61746164      /* "data" */
slouken@617
    56
#define PCM_CODE    1
slouken@617
    57
#define ADPCM_CODE  2
slouken@617
    58
#define WAVE_MONO   1
slouken@617
    59
#define WAVE_STEREO 2
slouken@111
    60
slouken@111
    61
/* Normally, these three chunks come consecutively in a WAVE file */
slouken@111
    62
typedef struct WaveFMT {
slouken@111
    63
/* Not saved in the chunk we read:
slouken@617
    64
    Uint32  FMTchunk;
slouken@617
    65
    Uint32  fmtlen;
slouken@111
    66
*/
slouken@617
    67
    Uint16  encoding;
slouken@617
    68
    Uint16  channels;       /* 1 = mono, 2 = stereo */
slouken@617
    69
    Uint32  frequency;      /* One of 11025, 22050, or 44100 Hz */
slouken@617
    70
    Uint32  byterate;       /* Average bytes per second */
slouken@617
    71
    Uint16  blockalign;     /* Bytes per sample block */
slouken@617
    72
    Uint16  bitspersample;      /* One of 8, 12, 16, or 4 for ADPCM */
slouken@111
    73
} WaveFMT;
slouken@111
    74
slouken@111
    75
/* The general chunk found in the WAVE file */
slouken@111
    76
typedef struct Chunk {
slouken@617
    77
    Uint32 magic;
slouken@617
    78
    Uint32 length;
slouken@617
    79
    Uint8 *data;            /* Data includes magic and length */
slouken@111
    80
} Chunk;
slouken@111
    81
slouken@111
    82
/*********************************************/
slouken@111
    83
/* Define values for AIFF (IFF audio) format */
slouken@111
    84
/*********************************************/
slouken@617
    85
#define FORM        0x4d524f46      /* "FORM" */
slouken@617
    86
#define AIFF        0x46464941      /* "AIFF" */
slouken@617
    87
#define SSND        0x444e5353      /* "SSND" */
slouken@617
    88
#define COMM        0x4d4d4f43      /* "COMM" */
slouken@111
    89
slouken@111
    90
slouken@64
    91
/* Currently we only support a single stream at a time */
slouken@173
    92
static WAVStream *music = NULL;
slouken@64
    93
slouken@0
    94
/* This is the format of the audio mixer data */
slouken@0
    95
static SDL_AudioSpec mixer;
slouken@214
    96
static int wavestream_volume = MIX_MAX_VOLUME;
slouken@0
    97
slouken@0
    98
/* Function to load the WAV/AIFF stream */
slouken@381
    99
static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@617
   100
                    long *start, long *stop);
slouken@381
   101
static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@617
   102
                    long *start, long *stop);
slouken@0
   103
slouken@0
   104
/* Initialize the WAVStream player, with the given mixer settings
slouken@0
   105
   This function returns 0, or -1 if there was an error.
slouken@0
   106
 */
slouken@0
   107
int WAVStream_Init(SDL_AudioSpec *mixerfmt)
slouken@0
   108
{
slouken@617
   109
    mixer = *mixerfmt;
slouken@617
   110
    return(0);
slouken@0
   111
}
slouken@0
   112
slouken@214
   113
void WAVStream_SetVolume(int volume)
slouken@0
   114
{
slouken@617
   115
    wavestream_volume = volume;
slouken@0
   116
}
slouken@0
   117
slouken@542
   118
/* Load a WAV stream from the given RWops object */
slouken@625
   119
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *src, int freesrc)
slouken@0
   120
{
slouken@617
   121
    WAVStream *wave;
slouken@617
   122
    SDL_AudioSpec wavespec;
slouken@0
   123
slouken@617
   124
    if ( ! mixer.format ) {
slouken@617
   125
        Mix_SetError("WAV music output not started");
slouken@617
   126
        return(NULL);
slouken@617
   127
    }
slouken@617
   128
    wave = (WAVStream *)SDL_malloc(sizeof *wave);
slouken@617
   129
    if ( wave ) {
slouken@625
   130
        Uint32 magic;
slouken@625
   131
slouken@625
   132
        SDL_zerop(wave);
slouken@625
   133
        wave->freesrc = freesrc;
slouken@625
   134
slouken@625
   135
        magic = SDL_ReadLE32(src);
slouken@625
   136
        if ( magic == RIFF || magic == WAVE ) {
slouken@625
   137
            wave->src = LoadWAVStream(src, &wavespec, &wave->start, &wave->stop);
slouken@625
   138
        } else if ( magic == FORM ) {
slouken@625
   139
            wave->src = LoadAIFFStream(src, &wavespec, &wave->start, &wave->stop);
slouken@617
   140
        } else {
slouken@617
   141
            Mix_SetError("Unknown WAVE format");
slouken@617
   142
        }
slouken@625
   143
        if ( wave->src == NULL ) {
slouken@617
   144
            SDL_free(wave);
slouken@617
   145
            return(NULL);
slouken@617
   146
        }
slouken@617
   147
        SDL_BuildAudioCVT(&wave->cvt,
slouken@617
   148
            wavespec.format, wavespec.channels, wavespec.freq,
slouken@617
   149
            mixer.format, mixer.channels, mixer.freq);
slouken@617
   150
    } else {
slouken@617
   151
        SDL_OutOfMemory();
slouken@617
   152
        return(NULL);
slouken@617
   153
    }
slouken@617
   154
    return(wave);
slouken@0
   155
}
slouken@0
   156
slouken@0
   157
/* Start playback of a given WAV stream */
slouken@214
   158
void WAVStream_Start(WAVStream *wave)
slouken@0
   159
{
slouken@625
   160
    SDL_RWseek (wave->src, wave->start, RW_SEEK_SET);
slouken@617
   161
    music = wave;
slouken@0
   162
}
slouken@0
   163
slouken@173
   164
/* Play some of a stream previously started with WAVStream_Start() */
slouken@407
   165
int WAVStream_PlaySome(Uint8 *stream, int len)
slouken@0
   166
{
slouken@621
   167
    Sint64 pos;
slouken@621
   168
    Sint64 left = 0;
slouken@0
   169
slouken@625
   170
    if ( music && ((pos=SDL_RWtell(music->src)) < music->stop) ) {
slouken@617
   171
        if ( music->cvt.needed ) {
slouken@617
   172
            int original_len;
slouken@0
   173
slouken@617
   174
            original_len=(int)((double)len/music->cvt.len_ratio);
slouken@617
   175
            if ( music->cvt.len != original_len ) {
slouken@617
   176
                int worksize;
slouken@617
   177
                if ( music->cvt.buf != NULL ) {
slouken@617
   178
                    SDL_free(music->cvt.buf);
slouken@617
   179
                }
slouken@617
   180
                worksize = original_len*music->cvt.len_mult;
slouken@617
   181
                music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
slouken@617
   182
                if ( music->cvt.buf == NULL ) {
slouken@617
   183
                    return 0;
slouken@617
   184
                }
slouken@617
   185
                music->cvt.len = original_len;
slouken@617
   186
            }
slouken@617
   187
            if ( (music->stop - pos) < original_len ) {
slouken@617
   188
                left = (original_len - (music->stop - pos));
aschiffler@642
   189
                original_len -= (int)left;
slouken@617
   190
                left = (int)((double)left*music->cvt.len_ratio);
slouken@617
   191
            }
slouken@625
   192
            original_len = SDL_RWread(music->src, music->cvt.buf,1,original_len);
slouken@617
   193
            /* At least at the time of writing, SDL_ConvertAudio()
slouken@617
   194
               does byte-order swapping starting at the end of the
slouken@617
   195
               buffer. Thus, if we are reading 16-bit samples, we
slouken@617
   196
               had better make damn sure that we get an even
slouken@617
   197
               number of bytes, or we'll get garbage.
slouken@617
   198
             */
slouken@617
   199
            if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
slouken@617
   200
                original_len--;
slouken@617
   201
            }
slouken@617
   202
            music->cvt.len = original_len;
slouken@617
   203
            SDL_ConvertAudio(&music->cvt);
slouken@617
   204
            SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
slouken@617
   205
        } else {
slouken@617
   206
            Uint8 *data;
slouken@617
   207
            if ( (music->stop - pos) < len ) {
slouken@617
   208
                left = (len - (music->stop - pos));
aschiffler@642
   209
                len -= (int)left;
slouken@617
   210
            }
slouken@617
   211
            data = SDL_stack_alloc(Uint8, len);
slouken@617
   212
            if (data)
slouken@617
   213
            {
slouken@625
   214
                SDL_RWread(music->src, data, len, 1);
slouken@617
   215
                SDL_MixAudio(stream, data, len, wavestream_volume);
slouken@617
   216
                SDL_stack_free(data);
slouken@617
   217
            }
slouken@617
   218
        }
slouken@617
   219
    }
aschiffler@642
   220
    return (int)left;
slouken@0
   221
}
slouken@0
   222
slouken@0
   223
/* Stop playback of a stream previously started with WAVStream_Start() */
slouken@214
   224
void WAVStream_Stop(void)
slouken@0
   225
{
slouken@617
   226
    music = NULL;
slouken@0
   227
}
slouken@0
   228
slouken@0
   229
/* Close the given WAV stream */
slouken@214
   230
void WAVStream_FreeSong(WAVStream *wave)
slouken@0
   231
{
slouken@617
   232
    if ( wave ) {
slouken@617
   233
        /* Clean up associated data */
slouken@617
   234
        if ( wave->cvt.buf ) {
slouken@617
   235
            SDL_free(wave->cvt.buf);
slouken@617
   236
        }
slouken@625
   237
        if ( wave->freesrc ) {
slouken@625
   238
            SDL_RWclose(wave->src);
slouken@617
   239
        }
slouken@617
   240
        SDL_free(wave);
slouken@617
   241
    }
slouken@0
   242
}
slouken@0
   243
slouken@0
   244
/* Return non-zero if a stream is currently playing */
slouken@214
   245
int WAVStream_Active(void)
slouken@0
   246
{
slouken@617
   247
    int active;
slouken@0
   248
slouken@617
   249
    active = 0;
slouken@625
   250
    if ( music && (SDL_RWtell(music->src) < music->stop) ) {
slouken@617
   251
        active = 1;
slouken@617
   252
    }
slouken@617
   253
    return(active);
slouken@0
   254
}
slouken@0
   255
slouken@0
   256
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
slouken@0
   257
{
slouken@617
   258
    chunk->magic    = SDL_ReadLE32(src);
slouken@617
   259
    chunk->length   = SDL_ReadLE32(src);
slouken@617
   260
    if ( read_data ) {
slouken@617
   261
        chunk->data = (Uint8 *)SDL_malloc(chunk->length);
slouken@617
   262
        if ( chunk->data == NULL ) {
slouken@617
   263
            Mix_SetError("Out of memory");
slouken@617
   264
            return(-1);
slouken@617
   265
        }
slouken@617
   266
        if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
slouken@617
   267
            Mix_SetError("Couldn't read chunk");
slouken@617
   268
            SDL_free(chunk->data);
slouken@617
   269
            return(-1);
slouken@617
   270
        }
slouken@617
   271
    } else {
slouken@617
   272
        SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
slouken@617
   273
    }
slouken@617
   274
    return(chunk->length);
slouken@0
   275
}
slouken@0
   276
slouken@381
   277
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@617
   278
                    long *start, long *stop)
slouken@0
   279
{
slouken@617
   280
    int was_error;
slouken@617
   281
    Chunk chunk;
slouken@617
   282
    int lenread;
slouken@0
   283
slouken@617
   284
    /* WAV magic header */
slouken@617
   285
    Uint32 wavelen;
slouken@617
   286
    Uint32 WAVEmagic;
slouken@0
   287
slouken@617
   288
    /* FMT chunk */
slouken@617
   289
    WaveFMT *format = NULL;
slouken@0
   290
slouken@617
   291
    was_error = 0;
slouken@29
   292
slouken@617
   293
    /* Check the magic header */
slouken@617
   294
    wavelen     = SDL_ReadLE32(src);
slouken@617
   295
    WAVEmagic   = SDL_ReadLE32(src);
slouken@0
   296
slouken@617
   297
    /* Read the audio data format chunk */
slouken@617
   298
    chunk.data = NULL;
slouken@617
   299
    do {
slouken@617
   300
        /* FIXME! Add this logic to SDL_LoadWAV_RW() */
slouken@617
   301
        if ( chunk.data ) {
slouken@617
   302
            SDL_free(chunk.data);
slouken@617
   303
        }
slouken@617
   304
        lenread = ReadChunk(src, &chunk, 1);
slouken@617
   305
        if ( lenread < 0 ) {
slouken@617
   306
            was_error = 1;
slouken@617
   307
            goto done;
slouken@617
   308
        }
slouken@693
   309
    } while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT) || (chunk.magic == JUNK));
slouken@0
   310
slouken@617
   311
    /* Decode the audio data format */
slouken@617
   312
    format = (WaveFMT *)chunk.data;
slouken@617
   313
    if ( chunk.magic != FMT ) {
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