cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_wave.c (19592B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../SDL_internal.h"
     22
     23/* Microsoft WAVE file loading routines */
     24
     25#include "SDL_audio.h"
     26#include "SDL_wave.h"
     27
     28
     29static int ReadChunk(SDL_RWops * src, Chunk * chunk);
     30
     31struct MS_ADPCM_decodestate
     32{
     33    Uint8 hPredictor;
     34    Uint16 iDelta;
     35    Sint16 iSamp1;
     36    Sint16 iSamp2;
     37};
     38static struct MS_ADPCM_decoder
     39{
     40    WaveFMT wavefmt;
     41    Uint16 wSamplesPerBlock;
     42    Uint16 wNumCoef;
     43    Sint16 aCoeff[7][2];
     44    /* * * */
     45    struct MS_ADPCM_decodestate state[2];
     46} MS_ADPCM_state;
     47
     48static int
     49InitMS_ADPCM(WaveFMT * format)
     50{
     51    Uint8 *rogue_feel;
     52    int i;
     53
     54    /* Set the rogue pointer to the MS_ADPCM specific data */
     55    MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
     56    MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
     57    MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
     58    MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
     59    MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
     60    MS_ADPCM_state.wavefmt.bitspersample =
     61        SDL_SwapLE16(format->bitspersample);
     62    rogue_feel = (Uint8 *) format + sizeof(*format);
     63    if (sizeof(*format) == 16) {
     64        /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
     65        rogue_feel += sizeof(Uint16);
     66    }
     67    MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
     68    rogue_feel += sizeof(Uint16);
     69    MS_ADPCM_state.wNumCoef = ((rogue_feel[1] << 8) | rogue_feel[0]);
     70    rogue_feel += sizeof(Uint16);
     71    if (MS_ADPCM_state.wNumCoef != 7) {
     72        SDL_SetError("Unknown set of MS_ADPCM coefficients");
     73        return (-1);
     74    }
     75    for (i = 0; i < MS_ADPCM_state.wNumCoef; ++i) {
     76        MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1] << 8) | rogue_feel[0]);
     77        rogue_feel += sizeof(Uint16);
     78        MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1] << 8) | rogue_feel[0]);
     79        rogue_feel += sizeof(Uint16);
     80    }
     81    return (0);
     82}
     83
     84static Sint32
     85MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
     86                Uint8 nybble, Sint16 * coeff)
     87{
     88    const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
     89    const Sint32 min_audioval = -(1 << (16 - 1));
     90    const Sint32 adaptive[] = {
     91        230, 230, 230, 230, 307, 409, 512, 614,
     92        768, 614, 512, 409, 307, 230, 230, 230
     93    };
     94    Sint32 new_sample, delta;
     95
     96    new_sample = ((state->iSamp1 * coeff[0]) +
     97                  (state->iSamp2 * coeff[1])) / 256;
     98    if (nybble & 0x08) {
     99        new_sample += state->iDelta * (nybble - 0x10);
    100    } else {
    101        new_sample += state->iDelta * nybble;
    102    }
    103    if (new_sample < min_audioval) {
    104        new_sample = min_audioval;
    105    } else if (new_sample > max_audioval) {
    106        new_sample = max_audioval;
    107    }
    108    delta = ((Sint32) state->iDelta * adaptive[nybble]) / 256;
    109    if (delta < 16) {
    110        delta = 16;
    111    }
    112    state->iDelta = (Uint16) delta;
    113    state->iSamp2 = state->iSamp1;
    114    state->iSamp1 = (Sint16) new_sample;
    115    return (new_sample);
    116}
    117
    118static int
    119MS_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
    120{
    121    struct MS_ADPCM_decodestate *state[2];
    122    Uint8 *freeable, *encoded, *decoded;
    123    Sint32 encoded_len, samplesleft;
    124    Sint8 nybble;
    125    Uint8 stereo;
    126    Sint16 *coeff[2];
    127    Sint32 new_sample;
    128
    129    /* Allocate the proper sized output buffer */
    130    encoded_len = *audio_len;
    131    encoded = *audio_buf;
    132    freeable = *audio_buf;
    133    *audio_len = (encoded_len / MS_ADPCM_state.wavefmt.blockalign) *
    134        MS_ADPCM_state.wSamplesPerBlock *
    135        MS_ADPCM_state.wavefmt.channels * sizeof(Sint16);
    136    *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
    137    if (*audio_buf == NULL) {
    138        return SDL_OutOfMemory();
    139    }
    140    decoded = *audio_buf;
    141
    142    /* Get ready... Go! */
    143    stereo = (MS_ADPCM_state.wavefmt.channels == 2);
    144    state[0] = &MS_ADPCM_state.state[0];
    145    state[1] = &MS_ADPCM_state.state[stereo];
    146    while (encoded_len >= MS_ADPCM_state.wavefmt.blockalign) {
    147        /* Grab the initial information for this block */
    148        state[0]->hPredictor = *encoded++;
    149        if (stereo) {
    150            state[1]->hPredictor = *encoded++;
    151        }
    152        state[0]->iDelta = ((encoded[1] << 8) | encoded[0]);
    153        encoded += sizeof(Sint16);
    154        if (stereo) {
    155            state[1]->iDelta = ((encoded[1] << 8) | encoded[0]);
    156            encoded += sizeof(Sint16);
    157        }
    158        state[0]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
    159        encoded += sizeof(Sint16);
    160        if (stereo) {
    161            state[1]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
    162            encoded += sizeof(Sint16);
    163        }
    164        state[0]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
    165        encoded += sizeof(Sint16);
    166        if (stereo) {
    167            state[1]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
    168            encoded += sizeof(Sint16);
    169        }
    170        coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
    171        coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
    172
    173        /* Store the two initial samples we start with */
    174        decoded[0] = state[0]->iSamp2 & 0xFF;
    175        decoded[1] = state[0]->iSamp2 >> 8;
    176        decoded += 2;
    177        if (stereo) {
    178            decoded[0] = state[1]->iSamp2 & 0xFF;
    179            decoded[1] = state[1]->iSamp2 >> 8;
    180            decoded += 2;
    181        }
    182        decoded[0] = state[0]->iSamp1 & 0xFF;
    183        decoded[1] = state[0]->iSamp1 >> 8;
    184        decoded += 2;
    185        if (stereo) {
    186            decoded[0] = state[1]->iSamp1 & 0xFF;
    187            decoded[1] = state[1]->iSamp1 >> 8;
    188            decoded += 2;
    189        }
    190
    191        /* Decode and store the other samples in this block */
    192        samplesleft = (MS_ADPCM_state.wSamplesPerBlock - 2) *
    193            MS_ADPCM_state.wavefmt.channels;
    194        while (samplesleft > 0) {
    195            nybble = (*encoded) >> 4;
    196            new_sample = MS_ADPCM_nibble(state[0], nybble, coeff[0]);
    197            decoded[0] = new_sample & 0xFF;
    198            new_sample >>= 8;
    199            decoded[1] = new_sample & 0xFF;
    200            decoded += 2;
    201
    202            nybble = (*encoded) & 0x0F;
    203            new_sample = MS_ADPCM_nibble(state[1], nybble, coeff[1]);
    204            decoded[0] = new_sample & 0xFF;
    205            new_sample >>= 8;
    206            decoded[1] = new_sample & 0xFF;
    207            decoded += 2;
    208
    209            ++encoded;
    210            samplesleft -= 2;
    211        }
    212        encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
    213    }
    214    SDL_free(freeable);
    215    return (0);
    216}
    217
    218struct IMA_ADPCM_decodestate
    219{
    220    Sint32 sample;
    221    Sint8 index;
    222};
    223static struct IMA_ADPCM_decoder
    224{
    225    WaveFMT wavefmt;
    226    Uint16 wSamplesPerBlock;
    227    /* * * */
    228    struct IMA_ADPCM_decodestate state[2];
    229} IMA_ADPCM_state;
    230
    231static int
    232InitIMA_ADPCM(WaveFMT * format)
    233{
    234    Uint8 *rogue_feel;
    235
    236    /* Set the rogue pointer to the IMA_ADPCM specific data */
    237    IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
    238    IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
    239    IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
    240    IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
    241    IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
    242    IMA_ADPCM_state.wavefmt.bitspersample =
    243        SDL_SwapLE16(format->bitspersample);
    244    rogue_feel = (Uint8 *) format + sizeof(*format);
    245    if (sizeof(*format) == 16) {
    246        /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
    247        rogue_feel += sizeof(Uint16);
    248    }
    249    IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
    250    return (0);
    251}
    252
    253static Sint32
    254IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state, Uint8 nybble)
    255{
    256    const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
    257    const Sint32 min_audioval = -(1 << (16 - 1));
    258    const int index_table[16] = {
    259        -1, -1, -1, -1,
    260        2, 4, 6, 8,
    261        -1, -1, -1, -1,
    262        2, 4, 6, 8
    263    };
    264    const Sint32 step_table[89] = {
    265        7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
    266        34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
    267        143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
    268        449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
    269        1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
    270        3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
    271        9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
    272        22385, 24623, 27086, 29794, 32767
    273    };
    274    Sint32 delta, step;
    275
    276    /* Compute difference and new sample value */
    277    if (state->index > 88) {
    278        state->index = 88;
    279    } else if (state->index < 0) {
    280        state->index = 0;
    281    }
    282    /* explicit cast to avoid gcc warning about using 'char' as array index */
    283    step = step_table[(int)state->index];
    284    delta = step >> 3;
    285    if (nybble & 0x04)
    286        delta += step;
    287    if (nybble & 0x02)
    288        delta += (step >> 1);
    289    if (nybble & 0x01)
    290        delta += (step >> 2);
    291    if (nybble & 0x08)
    292        delta = -delta;
    293    state->sample += delta;
    294
    295    /* Update index value */
    296    state->index += index_table[nybble];
    297
    298    /* Clamp output sample */
    299    if (state->sample > max_audioval) {
    300        state->sample = max_audioval;
    301    } else if (state->sample < min_audioval) {
    302        state->sample = min_audioval;
    303    }
    304    return (state->sample);
    305}
    306
    307/* Fill the decode buffer with a channel block of data (8 samples) */
    308static void
    309Fill_IMA_ADPCM_block(Uint8 * decoded, Uint8 * encoded,
    310                     int channel, int numchannels,
    311                     struct IMA_ADPCM_decodestate *state)
    312{
    313    int i;
    314    Sint8 nybble;
    315    Sint32 new_sample;
    316
    317    decoded += (channel * 2);
    318    for (i = 0; i < 4; ++i) {
    319        nybble = (*encoded) & 0x0F;
    320        new_sample = IMA_ADPCM_nibble(state, nybble);
    321        decoded[0] = new_sample & 0xFF;
    322        new_sample >>= 8;
    323        decoded[1] = new_sample & 0xFF;
    324        decoded += 2 * numchannels;
    325
    326        nybble = (*encoded) >> 4;
    327        new_sample = IMA_ADPCM_nibble(state, nybble);
    328        decoded[0] = new_sample & 0xFF;
    329        new_sample >>= 8;
    330        decoded[1] = new_sample & 0xFF;
    331        decoded += 2 * numchannels;
    332
    333        ++encoded;
    334    }
    335}
    336
    337static int
    338IMA_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
    339{
    340    struct IMA_ADPCM_decodestate *state;
    341    Uint8 *freeable, *encoded, *decoded;
    342    Sint32 encoded_len, samplesleft;
    343    unsigned int c, channels;
    344
    345    /* Check to make sure we have enough variables in the state array */
    346    channels = IMA_ADPCM_state.wavefmt.channels;
    347    if (channels > SDL_arraysize(IMA_ADPCM_state.state)) {
    348        SDL_SetError("IMA ADPCM decoder can only handle %u channels",
    349                     (unsigned int)SDL_arraysize(IMA_ADPCM_state.state));
    350        return (-1);
    351    }
    352    state = IMA_ADPCM_state.state;
    353
    354    /* Allocate the proper sized output buffer */
    355    encoded_len = *audio_len;
    356    encoded = *audio_buf;
    357    freeable = *audio_buf;
    358    *audio_len = (encoded_len / IMA_ADPCM_state.wavefmt.blockalign) *
    359        IMA_ADPCM_state.wSamplesPerBlock *
    360        IMA_ADPCM_state.wavefmt.channels * sizeof(Sint16);
    361    *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
    362    if (*audio_buf == NULL) {
    363        return SDL_OutOfMemory();
    364    }
    365    decoded = *audio_buf;
    366
    367    /* Get ready... Go! */
    368    while (encoded_len >= IMA_ADPCM_state.wavefmt.blockalign) {
    369        /* Grab the initial information for this block */
    370        for (c = 0; c < channels; ++c) {
    371            /* Fill the state information for this block */
    372            state[c].sample = ((encoded[1] << 8) | encoded[0]);
    373            encoded += 2;
    374            if (state[c].sample & 0x8000) {
    375                state[c].sample -= 0x10000;
    376            }
    377            state[c].index = *encoded++;
    378            /* Reserved byte in buffer header, should be 0 */
    379            if (*encoded++ != 0) {
    380                /* Uh oh, corrupt data?  Buggy code? */ ;
    381            }
    382
    383            /* Store the initial sample we start with */
    384            decoded[0] = (Uint8) (state[c].sample & 0xFF);
    385            decoded[1] = (Uint8) (state[c].sample >> 8);
    386            decoded += 2;
    387        }
    388
    389        /* Decode and store the other samples in this block */
    390        samplesleft = (IMA_ADPCM_state.wSamplesPerBlock - 1) * channels;
    391        while (samplesleft > 0) {
    392            for (c = 0; c < channels; ++c) {
    393                Fill_IMA_ADPCM_block(decoded, encoded,
    394                                     c, channels, &state[c]);
    395                encoded += 4;
    396                samplesleft -= 8;
    397            }
    398            decoded += (channels * 8 * 2);
    399        }
    400        encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
    401    }
    402    SDL_free(freeable);
    403    return (0);
    404}
    405
    406SDL_AudioSpec *
    407SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
    408               SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len)
    409{
    410    int was_error;
    411    Chunk chunk;
    412    int lenread;
    413    int IEEE_float_encoded, MS_ADPCM_encoded, IMA_ADPCM_encoded;
    414    int samplesize;
    415
    416    /* WAV magic header */
    417    Uint32 RIFFchunk;
    418    Uint32 wavelen = 0;
    419    Uint32 WAVEmagic;
    420    Uint32 headerDiff = 0;
    421
    422    /* FMT chunk */
    423    WaveFMT *format = NULL;
    424
    425    SDL_zero(chunk);
    426
    427    /* Make sure we are passed a valid data source */
    428    was_error = 0;
    429    if (src == NULL) {
    430        was_error = 1;
    431        goto done;
    432    }
    433
    434    /* Check the magic header */
    435    RIFFchunk = SDL_ReadLE32(src);
    436    wavelen = SDL_ReadLE32(src);
    437    if (wavelen == WAVE) {      /* The RIFFchunk has already been read */
    438        WAVEmagic = wavelen;
    439        wavelen = RIFFchunk;
    440        RIFFchunk = RIFF;
    441    } else {
    442        WAVEmagic = SDL_ReadLE32(src);
    443    }
    444    if ((RIFFchunk != RIFF) || (WAVEmagic != WAVE)) {
    445        SDL_SetError("Unrecognized file type (not WAVE)");
    446        was_error = 1;
    447        goto done;
    448    }
    449    headerDiff += sizeof(Uint32);       /* for WAVE */
    450
    451    /* Read the audio data format chunk */
    452    chunk.data = NULL;
    453    do {
    454        SDL_free(chunk.data);
    455        chunk.data = NULL;
    456        lenread = ReadChunk(src, &chunk);
    457        if (lenread < 0) {
    458            was_error = 1;
    459            goto done;
    460        }
    461        /* 2 Uint32's for chunk header+len, plus the lenread */
    462        headerDiff += lenread + 2 * sizeof(Uint32);
    463    } while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT) || (chunk.magic == JUNK));
    464
    465    /* Decode the audio data format */
    466    format = (WaveFMT *) chunk.data;
    467    if (chunk.magic != FMT) {
    468        SDL_SetError("Complex WAVE files not supported");
    469        was_error = 1;
    470        goto done;
    471    }
    472    IEEE_float_encoded = MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
    473    switch (SDL_SwapLE16(format->encoding)) {
    474    case PCM_CODE:
    475        /* We can understand this */
    476        break;
    477    case IEEE_FLOAT_CODE:
    478        IEEE_float_encoded = 1;
    479        /* We can understand this */
    480        break;
    481    case MS_ADPCM_CODE:
    482        /* Try to understand this */
    483        if (InitMS_ADPCM(format) < 0) {
    484            was_error = 1;
    485            goto done;
    486        }
    487        MS_ADPCM_encoded = 1;
    488        break;
    489    case IMA_ADPCM_CODE:
    490        /* Try to understand this */
    491        if (InitIMA_ADPCM(format) < 0) {
    492            was_error = 1;
    493            goto done;
    494        }
    495        IMA_ADPCM_encoded = 1;
    496        break;
    497    case MP3_CODE:
    498        SDL_SetError("MPEG Layer 3 data not supported");
    499        was_error = 1;
    500        goto done;
    501    default:
    502        SDL_SetError("Unknown WAVE data format: 0x%.4x",
    503                     SDL_SwapLE16(format->encoding));
    504        was_error = 1;
    505        goto done;
    506    }
    507    SDL_memset(spec, 0, (sizeof *spec));
    508    spec->freq = SDL_SwapLE32(format->frequency);
    509
    510    if (IEEE_float_encoded) {
    511        if ((SDL_SwapLE16(format->bitspersample)) != 32) {
    512            was_error = 1;
    513        } else {
    514            spec->format = AUDIO_F32;
    515        }
    516    } else {
    517        switch (SDL_SwapLE16(format->bitspersample)) {
    518        case 4:
    519            if (MS_ADPCM_encoded || IMA_ADPCM_encoded) {
    520                spec->format = AUDIO_S16;
    521            } else {
    522                was_error = 1;
    523            }
    524            break;
    525        case 8:
    526            spec->format = AUDIO_U8;
    527            break;
    528        case 16:
    529            spec->format = AUDIO_S16;
    530            break;
    531        case 32:
    532            spec->format = AUDIO_S32;
    533            break;
    534        default:
    535            was_error = 1;
    536            break;
    537        }
    538    }
    539
    540    if (was_error) {
    541        SDL_SetError("Unknown %d-bit PCM data format",
    542                     SDL_SwapLE16(format->bitspersample));
    543        goto done;
    544    }
    545    spec->channels = (Uint8) SDL_SwapLE16(format->channels);
    546    spec->samples = 4096;       /* Good default buffer size */
    547
    548    /* Read the audio data chunk */
    549    *audio_buf = NULL;
    550    do {
    551        SDL_free(*audio_buf);
    552        *audio_buf = NULL;
    553        lenread = ReadChunk(src, &chunk);
    554        if (lenread < 0) {
    555            was_error = 1;
    556            goto done;
    557        }
    558        *audio_len = lenread;
    559        *audio_buf = chunk.data;
    560        if (chunk.magic != DATA)
    561            headerDiff += lenread + 2 * sizeof(Uint32);
    562    } while (chunk.magic != DATA);
    563    headerDiff += 2 * sizeof(Uint32);   /* for the data chunk and len */
    564
    565    if (MS_ADPCM_encoded) {
    566        if (MS_ADPCM_decode(audio_buf, audio_len) < 0) {
    567            was_error = 1;
    568            goto done;
    569        }
    570    }
    571    if (IMA_ADPCM_encoded) {
    572        if (IMA_ADPCM_decode(audio_buf, audio_len) < 0) {
    573            was_error = 1;
    574            goto done;
    575        }
    576    }
    577
    578    /* Don't return a buffer that isn't a multiple of samplesize */
    579    samplesize = ((SDL_AUDIO_BITSIZE(spec->format)) / 8) * spec->channels;
    580    *audio_len &= ~(samplesize - 1);
    581
    582  done:
    583    SDL_free(format);
    584    if (src) {
    585        if (freesrc) {
    586            SDL_RWclose(src);
    587        } else {
    588            /* seek to the end of the file (given by the RIFF chunk) */
    589            SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR);
    590        }
    591    }
    592    if (was_error) {
    593        spec = NULL;
    594    }
    595    return (spec);
    596}
    597
    598/* Since the WAV memory is allocated in the shared library, it must also
    599   be freed here.  (Necessary under Win32, VC++)
    600 */
    601void
    602SDL_FreeWAV(Uint8 * audio_buf)
    603{
    604    SDL_free(audio_buf);
    605}
    606
    607static int
    608ReadChunk(SDL_RWops * src, Chunk * chunk)
    609{
    610    chunk->magic = SDL_ReadLE32(src);
    611    chunk->length = SDL_ReadLE32(src);
    612    chunk->data = (Uint8 *) SDL_malloc(chunk->length);
    613    if (chunk->data == NULL) {
    614        return SDL_OutOfMemory();
    615    }
    616    if (SDL_RWread(src, chunk->data, chunk->length, 1) != 1) {
    617        SDL_free(chunk->data);
    618        chunk->data = NULL;
    619        return SDL_Error(SDL_EFREAD);
    620    }
    621    return (chunk->length);
    622}
    623
    624/* vi: set ts=4 sw=4 expandtab: */