src/audio/SDL_wave.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 12 Nov 2008 17:23:40 +0000
branchSDL-1.2
changeset 4158 96ce26f24b01
parent 1818 7995cc87b777
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Date: Sun, 7 Sep 2008 15:17:00 +0200
From: c2woody@gmx.net
Subject: [SDL] SDL 1.2 doube free/pointer zeroing missing

Hello,

this is about a crash/debug breakage for the current SDL 1.2
source tree (today's svn checkout, same problem in 1.2.13 and
before as far as relevant).
In some places memory is free()d but the associated pointer
is not zeroed, leading to for example double free()s.

For me this happened because SDL_StopEventThread() was executed
twice (during restart of the subsystems), once for the close
down in SDL_VideoQuit() and once at the startup, right at the
beginning of SDL_StartEventLoop(). Thus the code
SDL_DestroyMutex(SDL_EventQ.lock);
(see SDL_events.c) was called twice and executed the SDL_free(mutex);
twice as well, leading to a crash (msvc 64bit for which it was noticed).

I've tried to check all other occurrences of SDL_free and similar
code in msvc, see the attached patch (udiff against revision 4082).
Non-windows only codepaths have neither been checked nor touched.

Comments/ideas welcome.

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