src/audio/SDL_wave.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1659 14717b52abc0
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

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