src/audio/SDL_wave.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 24 Jan 2006 07:20:18 +0000
changeset 1260 80f8c94b5199
parent 769 b8d311d90021
child 1312 c9b51268668f
permissions -rw-r--r--
Date: 10 Jun 2003 15:30:59 -0400
From: Mike Shal
Subject: [SDL] Bug in SDL_wave.c?

Hey everyone, I'm not sure if this is a bug in SDL, or if I just have
incorrect WAV files. The problem I'm having is loading multiple
concatenated WAVs from SDL_LoadWAV_RW. Some WAV files put comments at
the end of the file (which may be bad form), and SDL doesn't skip past
them when reading from the RWops. So the next WAV I try to load will
start at the comment section of the previous WAV, which obviously
doesn't work. If anyone else is having this problem, one quick fix you
can do is run sox on the bad WAVs, which strips out all of the comment
sections.
Eg:

$ sox sound.wav tmp.wav
$ mv -f tmp.wav sound.wav

The other fix is to patch SDL_wave.c, which is included with this email.
(Assuming I made the patch correctly :). All it does is calculate how
much remaining space there is in the WAV file after the data chunk, and
does SDL_RWseek to skip it. I don't think it should interfere with
anything else, but if someone could check it that would be nice :). If
the bug is really with SDL and not with my WAVs, can someone work this
into the next version of SDL? Thanks,

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