music_wav.c
changeset 777 92882ef2ab81
parent 760 b94b48c76c69
child 779 a2b494c054d5
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/music_wav.c	Tue Oct 17 02:33:47 2017 -0700
     1.3 @@ -0,0 +1,625 @@
     1.4 +/*
     1.5 +  SDL_mixer:  An audio mixer library based on the SDL library
     1.6 +  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +
    1.25 +#ifdef MUSIC_WAV
    1.26 +
    1.27 +/* This file supports streaming WAV files */
    1.28 +
    1.29 +#include "music_wav.h"
    1.30 +
    1.31 +
    1.32 +typedef struct {
    1.33 +    SDL_bool active;
    1.34 +    Uint32 start;
    1.35 +    Uint32 stop;
    1.36 +    Uint32 initial_play_count;
    1.37 +    Uint32 current_play_count;
    1.38 +} WAVLoopPoint;
    1.39 +
    1.40 +typedef struct {
    1.41 +    SDL_RWops *src;
    1.42 +    SDL_bool freesrc;
    1.43 +    SDL_AudioSpec spec;
    1.44 +    int volume;
    1.45 +    Sint64 start;
    1.46 +    Sint64 stop;
    1.47 +    SDL_AudioCVT cvt;
    1.48 +    int numloops;
    1.49 +    WAVLoopPoint *loops;
    1.50 +} WAVStream;
    1.51 +
    1.52 +/*
    1.53 +    Taken with permission from SDL_wave.h, part of the SDL library,
    1.54 +    available at: http://www.libsdl.org/
    1.55 +    and placed under the same license as this mixer library.
    1.56 +*/
    1.57 +
    1.58 +/* WAVE files are little-endian */
    1.59 +
    1.60 +/*******************************************/
    1.61 +/* Define values for Microsoft WAVE format */
    1.62 +/*******************************************/
    1.63 +#define RIFF        0x46464952      /* "RIFF" */
    1.64 +#define WAVE        0x45564157      /* "WAVE" */
    1.65 +#define FMT         0x20746D66      /* "fmt " */
    1.66 +#define DATA        0x61746164      /* "data" */
    1.67 +#define SMPL        0x6c706d73      /* "smpl" */
    1.68 +#define PCM_CODE    1
    1.69 +#define ADPCM_CODE  2
    1.70 +#define WAVE_MONO   1
    1.71 +#define WAVE_STEREO 2
    1.72 +
    1.73 +typedef struct {
    1.74 +/* Not saved in the chunk we read:
    1.75 +    Uint32  chunkID;
    1.76 +    Uint32  chunkLen;
    1.77 +*/
    1.78 +    Uint16  encoding;
    1.79 +    Uint16  channels;       /* 1 = mono, 2 = stereo */
    1.80 +    Uint32  frequency;      /* One of 11025, 22050, or 44100 Hz */
    1.81 +    Uint32  byterate;       /* Average bytes per second */
    1.82 +    Uint16  blockalign;     /* Bytes per sample block */
    1.83 +    Uint16  bitspersample;      /* One of 8, 12, 16, or 4 for ADPCM */
    1.84 +} WaveFMT;
    1.85 +
    1.86 +typedef struct {
    1.87 +    Uint32 identifier;
    1.88 +    Uint32 type;
    1.89 +    Uint32 start;
    1.90 +    Uint32 end;
    1.91 +    Uint32 fraction;
    1.92 +    Uint32 play_count;
    1.93 +} SampleLoop;
    1.94 +
    1.95 +typedef struct {
    1.96 +/* Not saved in the chunk we read:
    1.97 +    Uint32  chunkID;
    1.98 +    Uint32  chunkLen;
    1.99 +*/
   1.100 +    Uint32  manufacturer;
   1.101 +    Uint32  product;
   1.102 +    Uint32  sample_period;
   1.103 +    Uint32  MIDI_unity_note;
   1.104 +    Uint32  MIDI_pitch_fraction;
   1.105 +    Uint32  SMTPE_format;
   1.106 +    Uint32  SMTPE_offset;
   1.107 +    Uint32  sample_loops;
   1.108 +    Uint32  sampler_data;
   1.109 +    SampleLoop loops[];
   1.110 +} SamplerChunk;
   1.111 +
   1.112 +/*********************************************/
   1.113 +/* Define values for AIFF (IFF audio) format */
   1.114 +/*********************************************/
   1.115 +#define FORM        0x4d524f46      /* "FORM" */
   1.116 +#define AIFF        0x46464941      /* "AIFF" */
   1.117 +#define SSND        0x444e5353      /* "SSND" */
   1.118 +#define COMM        0x4d4d4f43      /* "COMM" */
   1.119 +
   1.120 +
   1.121 +/* Function to load the WAV/AIFF stream */
   1.122 +static SDL_bool LoadWAVStream(WAVStream *wave);
   1.123 +static SDL_bool LoadAIFFStream(WAVStream *wave);
   1.124 +
   1.125 +
   1.126 +/* Load a WAV stream from the given RWops object */
   1.127 +static void *WAVStream_CreateFromRW(SDL_RWops *src, int freesrc)
   1.128 +{
   1.129 +    WAVStream *wave;
   1.130 +    SDL_bool loaded = SDL_FALSE;
   1.131 +
   1.132 +    wave = (WAVStream *)SDL_calloc(1, sizeof(*wave));
   1.133 +    if (wave) {
   1.134 +        Uint32 magic;
   1.135 +
   1.136 +        wave->src = src;
   1.137 +        wave->freesrc = freesrc;
   1.138 +
   1.139 +        magic = SDL_ReadLE32(src);
   1.140 +        if (magic == RIFF || magic == WAVE) {
   1.141 +            loaded = LoadWAVStream(wave);
   1.142 +        } else if (magic == FORM) {
   1.143 +            loaded = LoadAIFFStream(wave);
   1.144 +        } else {
   1.145 +            Mix_SetError("Unknown WAVE format");
   1.146 +        }
   1.147 +        if (!loaded) {
   1.148 +            SDL_free(wave);
   1.149 +            return(NULL);
   1.150 +        }
   1.151 +        SDL_BuildAudioCVT(&wave->cvt,
   1.152 +            wave->spec.format, wave->spec.channels, wave->spec.freq,
   1.153 +            music_spec.format, music_spec.channels, music_spec.freq);
   1.154 +        wave->volume = MIX_MAX_VOLUME;
   1.155 +    } else {
   1.156 +        SDL_OutOfMemory();
   1.157 +    }
   1.158 +    return wave;
   1.159 +}
   1.160 +
   1.161 +static void WAVStream_SetVolume(void *context, int volume)
   1.162 +{
   1.163 +    WAVStream *wave = (WAVStream *)context;
   1.164 +    wave->volume = volume;
   1.165 +}
   1.166 +
   1.167 +/* Start playback of a given WAV stream */
   1.168 +static int WAVStream_Play(void *context)
   1.169 +{
   1.170 +    WAVStream *wave = (WAVStream *)context;
   1.171 +    int i;
   1.172 +    for (i = 0; i < wave->numloops; ++i) {
   1.173 +        WAVLoopPoint *loop = &wave->loops[i];
   1.174 +        loop->active = SDL_TRUE;
   1.175 +        loop->current_play_count = loop->initial_play_count;
   1.176 +    }
   1.177 +    SDL_RWseek(wave->src, wave->start, RW_SEEK_SET);
   1.178 +    return 0;
   1.179 +}
   1.180 +
   1.181 +/* Play some of a stream previously started with WAVStream_Play() */
   1.182 +static int PlaySome(WAVStream *wave, Uint8 *stream, int len)
   1.183 +{
   1.184 +    Sint64 pos, stop;
   1.185 +    WAVLoopPoint *loop;
   1.186 +    Sint64 loop_start;
   1.187 +    Sint64 loop_stop;
   1.188 +    int i;
   1.189 +    int consumed;
   1.190 +
   1.191 +    pos = SDL_RWtell(wave->src);
   1.192 +    stop = wave->stop;
   1.193 +    loop = NULL;
   1.194 +    for (i = 0; i < wave->numloops; ++i) {
   1.195 +        loop = &wave->loops[i];
   1.196 +        if (loop->active) {
   1.197 +            const int bytes_per_sample = (SDL_AUDIO_BITSIZE(wave->spec.format) / 8) * wave->spec.channels;
   1.198 +            loop_start = wave->start + loop->start * bytes_per_sample;
   1.199 +            loop_stop = wave->start + (loop->stop + 1) * bytes_per_sample;
   1.200 +            if (pos >= loop_start && pos < loop_stop)
   1.201 +            {
   1.202 +                stop = loop_stop;
   1.203 +                break;
   1.204 +            }
   1.205 +        }
   1.206 +        loop = NULL;
   1.207 +    }
   1.208 +
   1.209 +    if (wave->cvt.needed) {
   1.210 +        int original_len = (int)((double)len/wave->cvt.len_ratio); 
   1.211 +        /* Make sure the length is a multiple of the sample size */
   1.212 +        {
   1.213 +            const int bytes_per_sample = (SDL_AUDIO_BITSIZE(wave->spec.format) / 8) * wave->spec.channels;
   1.214 +            const int alignment_mask = (bytes_per_sample - 1);
   1.215 +            original_len &= ~alignment_mask;
   1.216 +        }
   1.217 +        if (wave->cvt.len != original_len) {
   1.218 +            int worksize;
   1.219 +            if (wave->cvt.buf != NULL) {
   1.220 +                SDL_free(wave->cvt.buf);
   1.221 +            }
   1.222 +            worksize = original_len*wave->cvt.len_mult;
   1.223 +            wave->cvt.buf=(Uint8 *)SDL_malloc(worksize);
   1.224 +            if (wave->cvt.buf == NULL) {
   1.225 +                return 0;
   1.226 +            }
   1.227 +            wave->cvt.len = original_len;
   1.228 +        }
   1.229 +        if ((stop - pos) < original_len) {
   1.230 +            original_len = (int)(stop - pos);
   1.231 +        }
   1.232 +        original_len = (int)SDL_RWread(wave->src, wave->cvt.buf, 1, original_len);
   1.233 +        wave->cvt.len = original_len;
   1.234 +        SDL_ConvertAudio(&wave->cvt);
   1.235 +        SDL_MixAudioFormat(stream, wave->cvt.buf, music_spec.format, wave->cvt.len_cvt, wave->volume);
   1.236 +        consumed = wave->cvt.len_cvt;
   1.237 +    } else {
   1.238 +        Uint8 *data;
   1.239 +        if ((stop - pos) < len) {
   1.240 +            len = (int)(stop - pos);
   1.241 +        }
   1.242 +        data = SDL_stack_alloc(Uint8, len);
   1.243 +        if (data) {
   1.244 +            len = (int)SDL_RWread(wave->src, data, 1, len);
   1.245 +            SDL_MixAudioFormat(stream, data, music_spec.format, len, wave->volume);
   1.246 +            SDL_stack_free(data);
   1.247 +        }
   1.248 +        consumed = len;
   1.249 +    }
   1.250 +
   1.251 +    if (loop && SDL_RWtell(wave->src) >= stop) {
   1.252 +        if (loop->current_play_count == 1) {
   1.253 +            loop->active = SDL_FALSE;
   1.254 +        } else {
   1.255 +            if (loop->current_play_count > 0) {
   1.256 +                --loop->current_play_count;
   1.257 +            }
   1.258 +            SDL_RWseek(wave->src, loop_start, RW_SEEK_SET);
   1.259 +        }
   1.260 +    }
   1.261 +    return consumed;
   1.262 +}
   1.263 +
   1.264 +static int WAVStream_GetAudio(void *context, void *data, int bytes)
   1.265 +{
   1.266 +    WAVStream *wave = (WAVStream *)context;
   1.267 +    Uint8 *stream = (Uint8 *)data;
   1.268 +    int len = bytes;
   1.269 +
   1.270 +    while ((SDL_RWtell(wave->src) < wave->stop) && (len > 0)) {
   1.271 +        int consumed = PlaySome(wave, stream, len);
   1.272 +        if (!consumed)
   1.273 +            break;
   1.274 +
   1.275 +        stream += consumed;
   1.276 +        len -= consumed;
   1.277 +    }
   1.278 +    return len;
   1.279 +}
   1.280 +
   1.281 +/* Close the given WAV stream */
   1.282 +static void WAVStream_Delete(void *context)
   1.283 +{
   1.284 +    WAVStream *wave = (WAVStream *)context;
   1.285 +
   1.286 +    /* Clean up associated data */
   1.287 +    if (wave->loops) {
   1.288 +        SDL_free(wave->loops);
   1.289 +    }
   1.290 +    if (wave->cvt.buf) {
   1.291 +        SDL_free(wave->cvt.buf);
   1.292 +    }
   1.293 +    if (wave->freesrc) {
   1.294 +        SDL_RWclose(wave->src);
   1.295 +    }
   1.296 +    SDL_free(wave);
   1.297 +}
   1.298 +
   1.299 +static SDL_bool ParseFMT(WAVStream *wave, Uint32 chunk_length)
   1.300 +{
   1.301 +    SDL_RWops *src = wave->src;
   1.302 +    SDL_AudioSpec *spec = &wave->spec;
   1.303 +    WaveFMT *format;
   1.304 +    Uint8 *data;
   1.305 +    SDL_bool loaded = SDL_FALSE;
   1.306 +
   1.307 +    if (chunk_length < sizeof(*format)) {
   1.308 +        Mix_SetError("Wave format chunk too small");
   1.309 +        return SDL_FALSE;
   1.310 +    }
   1.311 +
   1.312 +    data = (Uint8 *)SDL_malloc(chunk_length);
   1.313 +    if (!data) {
   1.314 +        Mix_SetError("Out of memory");
   1.315 +        return SDL_FALSE;
   1.316 +    }
   1.317 +    if (!SDL_RWread(wave->src, data, chunk_length, 1)) {
   1.318 +        Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
   1.319 +        return SDL_FALSE;
   1.320 +    }
   1.321 +    format = (WaveFMT *)data;
   1.322 +
   1.323 +    /* Decode the audio data format */
   1.324 +    switch (SDL_SwapLE16(format->encoding)) {
   1.325 +        case PCM_CODE:
   1.326 +            /* We can understand this */
   1.327 +            break;
   1.328 +        default:
   1.329 +            Mix_SetError("Unknown WAVE data format");
   1.330 +            goto done;
   1.331 +    }
   1.332 +    spec->freq = SDL_SwapLE32(format->frequency);
   1.333 +    switch (SDL_SwapLE16(format->bitspersample)) {
   1.334 +        case 8:
   1.335 +            spec->format = AUDIO_U8;
   1.336 +            break;
   1.337 +        case 16:
   1.338 +            spec->format = AUDIO_S16;
   1.339 +            break;
   1.340 +        default:
   1.341 +            Mix_SetError("Unknown PCM data format");
   1.342 +            goto done;
   1.343 +    }
   1.344 +    spec->channels = (Uint8) SDL_SwapLE16(format->channels);
   1.345 +    spec->samples = 4096;       /* Good default buffer size */
   1.346 +
   1.347 +    loaded = SDL_TRUE;
   1.348 +
   1.349 +done:
   1.350 +    SDL_free(data);
   1.351 +    return loaded;
   1.352 +}
   1.353 +
   1.354 +static SDL_bool ParseDATA(WAVStream *wave, Uint32 chunk_length)
   1.355 +{
   1.356 +    wave->start = SDL_RWtell(wave->src);
   1.357 +    wave->stop = wave->start + chunk_length;
   1.358 +    SDL_RWseek(wave->src, chunk_length, RW_SEEK_CUR);
   1.359 +    return SDL_TRUE;
   1.360 +}
   1.361 +
   1.362 +static SDL_bool AddLoopPoint(WAVStream *wave, Uint32 play_count, Uint32 start, Uint32 stop)
   1.363 +{
   1.364 +    WAVLoopPoint *loop;
   1.365 +    WAVLoopPoint *loops = SDL_realloc(wave->loops, (wave->numloops + 1)*sizeof(*wave->loops));
   1.366 +    if (!loops) {
   1.367 +        Mix_SetError("Out of memory");
   1.368 +        return SDL_FALSE;
   1.369 +    }
   1.370 +
   1.371 +    loop = &loops[ wave->numloops ];
   1.372 +    loop->start = start;
   1.373 +    loop->stop = stop;
   1.374 +    loop->initial_play_count = play_count;
   1.375 +    loop->current_play_count = play_count;
   1.376 +
   1.377 +    wave->loops = loops;
   1.378 +    ++wave->numloops;
   1.379 +    return SDL_TRUE;
   1.380 +}
   1.381 +
   1.382 +static SDL_bool ParseSMPL(WAVStream *wave, Uint32 chunk_length)
   1.383 +{
   1.384 +    SamplerChunk *chunk;
   1.385 +    Uint8 *data;
   1.386 +    Uint32 i;
   1.387 +    SDL_bool loaded = SDL_FALSE;
   1.388 +
   1.389 +    data = (Uint8 *)SDL_malloc(chunk_length);
   1.390 +    if (!data) {
   1.391 +        Mix_SetError("Out of memory");
   1.392 +        return SDL_FALSE;
   1.393 +    }
   1.394 +    if (!SDL_RWread(wave->src, data, chunk_length, 1)) {
   1.395 +        Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
   1.396 +        return SDL_FALSE;
   1.397 +    }
   1.398 +    chunk = (SamplerChunk *)data;
   1.399 +
   1.400 +    for (i = 0; i < SDL_SwapLE32(chunk->sample_loops); ++i) {
   1.401 +        const Uint32 LOOP_TYPE_FORWARD = 0;
   1.402 +        Uint32 loop_type = SDL_SwapLE32(chunk->loops[i].type);
   1.403 +        if (loop_type == LOOP_TYPE_FORWARD) {
   1.404 +            AddLoopPoint(wave, SDL_SwapLE32(chunk->loops[i].play_count), SDL_SwapLE32(chunk->loops[i].start), SDL_SwapLE32(chunk->loops[i].end));
   1.405 +        }
   1.406 +    }
   1.407 +
   1.408 +    loaded = SDL_TRUE;
   1.409 +    SDL_free(data);
   1.410 +    return loaded;
   1.411 +}
   1.412 +
   1.413 +static SDL_bool LoadWAVStream(WAVStream *wave)
   1.414 +{
   1.415 +    SDL_RWops *src = wave->src;
   1.416 +    Uint32 chunk_type;
   1.417 +    Uint32 chunk_length;
   1.418 +    SDL_bool found_FMT = SDL_FALSE;
   1.419 +    SDL_bool found_DATA = SDL_FALSE;
   1.420 +
   1.421 +    /* WAV magic header */
   1.422 +    Uint32 wavelen;
   1.423 +    Uint32 WAVEmagic;
   1.424 +
   1.425 +    /* Check the magic header */
   1.426 +    wavelen = SDL_ReadLE32(src);
   1.427 +    WAVEmagic = SDL_ReadLE32(src);
   1.428 +
   1.429 +    /* Read the chunks */
   1.430 +    for (; ;) {
   1.431 +        chunk_type = SDL_ReadLE32(src);
   1.432 +        chunk_length = SDL_ReadLE32(src);
   1.433 +
   1.434 +        if (chunk_length == 0)
   1.435 +            break;
   1.436 +
   1.437 +        switch (chunk_type)
   1.438 +        {
   1.439 +        case FMT:
   1.440 +            found_FMT = SDL_TRUE;
   1.441 +            if (!ParseFMT(wave, chunk_length))
   1.442 +                return SDL_FALSE;
   1.443 +            break;
   1.444 +        case DATA:
   1.445 +            found_DATA = SDL_TRUE;
   1.446 +            if (!ParseDATA(wave, chunk_length))
   1.447 +                return SDL_FALSE;
   1.448 +            break;
   1.449 +        case SMPL:
   1.450 +            if (!ParseSMPL(wave, chunk_length))
   1.451 +                return SDL_FALSE;
   1.452 +            break;
   1.453 +        default:
   1.454 +            SDL_RWseek(src, chunk_length, RW_SEEK_CUR);
   1.455 +            break;
   1.456 +        }
   1.457 +    }
   1.458 +
   1.459 +    if (!found_FMT) {
   1.460 +        Mix_SetError("Bad WAV file (no FMT chunk)");
   1.461 +        return SDL_FALSE;
   1.462 +    }
   1.463 +
   1.464 +    if (!found_DATA) {
   1.465 +        Mix_SetError("Bad WAV file (no DATA chunk)");
   1.466 +        return SDL_FALSE;
   1.467 +    }
   1.468 +
   1.469 +    return SDL_TRUE;
   1.470 +}
   1.471 +
   1.472 +/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
   1.473 + * I don't pretend to fully understand it.
   1.474 + */
   1.475 +
   1.476 +static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
   1.477 +{
   1.478 +    /* Negative number? */
   1.479 +    if (sanebuf[0] & 0x80)
   1.480 +        return 0;
   1.481 +
   1.482 +    /* Less than 1? */
   1.483 +    if (sanebuf[0] <= 0x3F)
   1.484 +        return 1;
   1.485 +
   1.486 +    /* Way too big? */
   1.487 +    if (sanebuf[0] > 0x40)
   1.488 +        return 0x4000000;
   1.489 +
   1.490 +    /* Still too big? */
   1.491 +    if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
   1.492 +        return 800000000;
   1.493 +
   1.494 +    return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) |
   1.495 +            (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
   1.496 +}
   1.497 +
   1.498 +static SDL_bool LoadAIFFStream(WAVStream *wave)
   1.499 +{
   1.500 +    SDL_RWops *src = wave->src;
   1.501 +    SDL_AudioSpec *spec = &wave->spec;
   1.502 +    SDL_bool found_SSND = SDL_FALSE;
   1.503 +    SDL_bool found_COMM = SDL_FALSE;
   1.504 +
   1.505 +    Uint32 chunk_type;
   1.506 +    Uint32 chunk_length;
   1.507 +    Sint64 next_chunk;
   1.508 +
   1.509 +    /* AIFF magic header */
   1.510 +    Uint32 AIFFmagic;
   1.511 +    /* SSND chunk        */
   1.512 +    Uint32 offset;
   1.513 +    Uint32 blocksize;
   1.514 +    /* COMM format chunk */
   1.515 +    Uint16 channels = 0;
   1.516 +    Uint32 numsamples = 0;
   1.517 +    Uint16 samplesize = 0;
   1.518 +    Uint8 sane_freq[10];
   1.519 +    Uint32 frequency = 0;
   1.520 +
   1.521 +    /* Check the magic header */
   1.522 +    chunk_length = SDL_ReadBE32(src);
   1.523 +    AIFFmagic = SDL_ReadLE32(src);
   1.524 +    if (AIFFmagic != AIFF) {
   1.525 +        Mix_SetError("Unrecognized file type (not AIFF)");
   1.526 +        return SDL_FALSE;
   1.527 +    }
   1.528 +
   1.529 +    /* From what I understand of the specification, chunks may appear in
   1.530 +     * any order, and we should just ignore unknown ones.
   1.531 +     *
   1.532 +     * TODO: Better sanity-checking. E.g. what happens if the AIFF file
   1.533 +     *       contains compressed sound data?
   1.534 +     */
   1.535 +    do {
   1.536 +        chunk_type      = SDL_ReadLE32(src);
   1.537 +        chunk_length    = SDL_ReadBE32(src);
   1.538 +        next_chunk      = SDL_RWtell(src) + chunk_length;
   1.539 +
   1.540 +        /* Paranoia to avoid infinite loops */
   1.541 +        if (chunk_length == 0)
   1.542 +            break;
   1.543 +
   1.544 +        switch (chunk_type) {
   1.545 +        case SSND:
   1.546 +            found_SSND = SDL_TRUE;
   1.547 +            offset = SDL_ReadBE32(src);
   1.548 +            blocksize = SDL_ReadBE32(src);
   1.549 +            wave->start = SDL_RWtell(src) + offset;
   1.550 +            break;
   1.551 +
   1.552 +        case COMM:
   1.553 +            found_COMM = SDL_TRUE;
   1.554 +
   1.555 +            /* Read the audio data format chunk */
   1.556 +            channels = SDL_ReadBE16(src);
   1.557 +            numsamples = SDL_ReadBE32(src);
   1.558 +            samplesize = SDL_ReadBE16(src);
   1.559 +            SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
   1.560 +            frequency = SANE_to_Uint32(sane_freq);
   1.561 +            break;
   1.562 +
   1.563 +        default:
   1.564 +            break;
   1.565 +        }
   1.566 +    } while ((!found_SSND || !found_COMM)
   1.567 +         && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
   1.568 +
   1.569 +    if (!found_SSND) {
   1.570 +        Mix_SetError("Bad AIFF file (no SSND chunk)");
   1.571 +        return SDL_FALSE;
   1.572 +    }
   1.573 +
   1.574 +    if (!found_COMM) {
   1.575 +        Mix_SetError("Bad AIFF file (no COMM chunk)");
   1.576 +        return SDL_FALSE;
   1.577 +    }
   1.578 +
   1.579 +    wave->stop = wave->start + channels * numsamples * (samplesize / 8);
   1.580 +
   1.581 +    /* Decode the audio data format */
   1.582 +    SDL_memset(spec, 0, (sizeof *spec));
   1.583 +    spec->freq = frequency;
   1.584 +    switch (samplesize) {
   1.585 +        case 8:
   1.586 +            spec->format = AUDIO_S8;
   1.587 +            break;
   1.588 +        case 16:
   1.589 +            spec->format = AUDIO_S16MSB;
   1.590 +            break;
   1.591 +        default:
   1.592 +            Mix_SetError("Unknown samplesize in data format");
   1.593 +            return SDL_FALSE;
   1.594 +    }
   1.595 +    spec->channels = (Uint8) channels;
   1.596 +    spec->samples = 4096;       /* Good default buffer size */
   1.597 +
   1.598 +    return SDL_TRUE;
   1.599 +}
   1.600 +
   1.601 +Mix_MusicInterface Mix_MusicInterface_WAV =
   1.602 +{
   1.603 +    "WAVE",
   1.604 +    MIX_MUSIC_WAVE,
   1.605 +    MUS_WAV,
   1.606 +    SDL_FALSE,
   1.607 +    SDL_FALSE,
   1.608 +
   1.609 +    NULL,   /* Load */
   1.610 +    NULL,   /* Open */
   1.611 +    WAVStream_CreateFromRW,
   1.612 +    NULL,   /* CreateFromFile */
   1.613 +    WAVStream_SetVolume,
   1.614 +    WAVStream_Play,
   1.615 +    NULL,   /* IsPlaying */
   1.616 +    WAVStream_GetAudio,
   1.617 +    NULL,   /* Seek */
   1.618 +    NULL,   /* Pause */
   1.619 +    NULL,   /* Resume */
   1.620 +    NULL,   /* Stop */
   1.621 +    WAVStream_Delete,
   1.622 +    NULL,   /* Close */
   1.623 +    NULL,   /* Unload */
   1.624 +};
   1.625 +
   1.626 +#endif /* MUSIC_WAV */
   1.627 +
   1.628 +/* vi: set ts=4 sw=4 expandtab: */