wavestream.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Jan 2012 03:15:19 -0500
changeset 561 87bdb4c81c0b
parent 542 3de4970b36d4
child 601 05123263dab3
child 876 fab846266822
permissions -rw-r--r--
Fixed memory crash loading Ogg Vorbis files on Windows
The pointer to the audio data could come from SDL_LoadWAV_RW() or from our other loaders, and we need to use the correct free() to release the memory. So we'll just use the SDL memory functions for consistency.
This pretty much only matters on Windows where we can't guarantee a certain C runtime so we provide our own malloc() and friends.
slouken@0
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@518
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@0
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@0
    21
slouken@140
    22
/* $Id$ */
slouken@138
    23
slouken@0
    24
/* This file supports streaming WAV files, without volume adjustment */
slouken@0
    25
slouken@0
    26
#include <stdlib.h>
slouken@0
    27
#include <string.h>
slouken@0
    28
slouken@24
    29
#include "SDL_audio.h"
slouken@24
    30
#include "SDL_mutex.h"
slouken@24
    31
#include "SDL_rwops.h"
slouken@24
    32
#include "SDL_endian.h"
slouken@0
    33
slouken@135
    34
#include "SDL_mixer.h"
slouken@0
    35
#include "wavestream.h"
slouken@0
    36
slouken@111
    37
/*
slouken@111
    38
    Taken with permission from SDL_wave.h, part of the SDL library,
slouken@111
    39
    available at: http://www.libsdl.org/
slouken@111
    40
    and placed under the same license as this mixer library.
slouken@111
    41
*/
slouken@111
    42
slouken@111
    43
/* WAVE files are little-endian */
slouken@111
    44
slouken@111
    45
/*******************************************/
slouken@111
    46
/* Define values for Microsoft WAVE format */
slouken@111
    47
/*******************************************/
slouken@111
    48
#define RIFF		0x46464952		/* "RIFF" */
slouken@111
    49
#define WAVE		0x45564157		/* "WAVE" */
slouken@111
    50
#define FACT		0x74636166		/* "fact" */
slouken@111
    51
#define LIST		0x5453494c		/* "LIST" */
slouken@111
    52
#define FMT		0x20746D66		/* "fmt " */
slouken@111
    53
#define DATA		0x61746164		/* "data" */
slouken@111
    54
#define PCM_CODE	1
slouken@111
    55
#define ADPCM_CODE	2
slouken@111
    56
#define WAVE_MONO	1
slouken@111
    57
#define WAVE_STEREO	2
slouken@111
    58
slouken@111
    59
/* Normally, these three chunks come consecutively in a WAVE file */
slouken@111
    60
typedef struct WaveFMT {
slouken@111
    61
/* Not saved in the chunk we read:
slouken@111
    62
	Uint32	FMTchunk;
slouken@111
    63
	Uint32	fmtlen;
slouken@111
    64
*/
slouken@111
    65
	Uint16	encoding;	
slouken@111
    66
	Uint16	channels;		/* 1 = mono, 2 = stereo */
slouken@111
    67
	Uint32	frequency;		/* One of 11025, 22050, or 44100 Hz */
slouken@111
    68
	Uint32	byterate;		/* Average bytes per second */
slouken@111
    69
	Uint16	blockalign;		/* Bytes per sample block */
slouken@111
    70
	Uint16	bitspersample;		/* One of 8, 12, 16, or 4 for ADPCM */
slouken@111
    71
} WaveFMT;
slouken@111
    72
slouken@111
    73
/* The general chunk found in the WAVE file */
slouken@111
    74
typedef struct Chunk {
slouken@111
    75
	Uint32 magic;
slouken@111
    76
	Uint32 length;
slouken@111
    77
	Uint8 *data;			/* Data includes magic and length */
slouken@111
    78
} Chunk;
slouken@111
    79
slouken@111
    80
/*********************************************/
slouken@111
    81
/* Define values for AIFF (IFF audio) format */
slouken@111
    82
/*********************************************/
slouken@111
    83
#define FORM		0x4d524f46		/* "FORM" */
slouken@111
    84
#define AIFF		0x46464941		/* "AIFF" */
slouken@111
    85
#define SSND		0x444e5353		/* "SSND" */
slouken@111
    86
#define COMM		0x4d4d4f43		/* "COMM" */
slouken@111
    87
slouken@111
    88
slouken@64
    89
/* Currently we only support a single stream at a time */
slouken@173
    90
static WAVStream *music = NULL;
slouken@64
    91
slouken@0
    92
/* This is the format of the audio mixer data */
slouken@0
    93
static SDL_AudioSpec mixer;
slouken@214
    94
static int wavestream_volume = MIX_MAX_VOLUME;
slouken@0
    95
slouken@0
    96
/* Function to load the WAV/AIFF stream */
slouken@381
    97
static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@0
    98
					long *start, long *stop);
slouken@381
    99
static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
slouken@0
   100
					long *start, long *stop);
slouken@0
   101
slouken@0
   102
/* Initialize the WAVStream player, with the given mixer settings
slouken@0
   103
   This function returns 0, or -1 if there was an error.
slouken@0
   104
 */
slouken@0
   105
int WAVStream_Init(SDL_AudioSpec *mixerfmt)
slouken@0
   106
{
slouken@0
   107
	mixer = *mixerfmt;
slouken@0
   108
	return(0);
slouken@0
   109
}
slouken@0
   110
slouken@214
   111
void WAVStream_SetVolume(int volume)
slouken@0
   112
{
slouken@214
   113
	wavestream_volume = volume;
slouken@0
   114
}
slouken@0
   115
slouken@542
   116
/* Load a WAV stream from the given RWops object */
slouken@521
   117
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw)
slouken@0
   118
{
slouken@0
   119
	WAVStream *wave;
slouken@0
   120
	SDL_AudioSpec wavespec;
slouken@0
   121
slouken@0
   122
	if ( ! mixer.format ) {
slouken@134
   123
		Mix_SetError("WAV music output not started");
slouken@521
   124
		if ( freerw ) {
slouken@521
   125
			SDL_RWclose(rw);
slouken@521
   126
		}
slouken@0
   127
		return(NULL);
slouken@0
   128
	}
slouken@561
   129
	wave = (WAVStream *)SDL_malloc(sizeof *wave);
slouken@0
   130
	if ( wave ) {
slouken@0
   131
		memset(wave, 0, (sizeof *wave));
slouken@521
   132
		wave->freerw = freerw;
slouken@0
   133
		if ( strcmp(magic, "RIFF") == 0 ) {
slouken@381
   134
			wave->rw = LoadWAVStream(rw, &wavespec,
slouken@0
   135
					&wave->start, &wave->stop);
slouken@0
   136
		} else
slouken@0
   137
		if ( strcmp(magic, "FORM") == 0 ) {
slouken@381
   138
			wave->rw = LoadAIFFStream(rw, &wavespec,
slouken@0
   139
					&wave->start, &wave->stop);
slouken@135
   140
		} else {
slouken@135
   141
			Mix_SetError("Unknown WAVE format");
slouken@0
   142
		}
slouken@381
   143
		if ( wave->rw == NULL ) {
slouken@561
   144
			SDL_free(wave);
slouken@521
   145
			if ( freerw ) {
slouken@521
   146
				SDL_RWclose(rw);
slouken@521
   147
			}
slouken@0
   148
			return(NULL);
slouken@0
   149
		}
slouken@0
   150
		SDL_BuildAudioCVT(&wave->cvt,
slouken@0
   151
			wavespec.format, wavespec.channels, wavespec.freq,
slouken@0
   152
			mixer.format, mixer.channels, mixer.freq);
slouken@521
   153
	} else {
slouken@521
   154
		SDL_OutOfMemory();
slouken@521
   155
		if ( freerw ) {
slouken@521
   156
			SDL_RWclose(rw);
slouken@521
   157
		}
slouken@521
   158
		return(NULL);
slouken@0
   159
	}
slouken@0
   160
	return(wave);
slouken@0
   161
}
slouken@0
   162
slouken@0
   163
/* Start playback of a given WAV stream */
slouken@214
   164
void WAVStream_Start(WAVStream *wave)
slouken@0
   165
{
slouken@473
   166
	SDL_RWseek (wave->rw, wave->start, RW_SEEK_SET);
slouken@173
   167
	music = wave;
slouken@0
   168
}
slouken@0
   169
slouken@173
   170
/* Play some of a stream previously started with WAVStream_Start() */
slouken@407
   171
int WAVStream_PlaySome(Uint8 *stream, int len)
slouken@0
   172
{
slouken@0
   173
	long pos;
slouken@407
   174
	int left = 0;
slouken@0
   175
slouken@381
   176
	if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
slouken@173
   177
		if ( music->cvt.needed ) {
slouken@0
   178
			int original_len;
slouken@0
   179
slouken@173
   180
			original_len=(int)((double)len/music->cvt.len_ratio);
slouken@173
   181
			if ( music->cvt.len != original_len ) {
slouken@0
   182
				int worksize;
slouken@173
   183
				if ( music->cvt.buf != NULL ) {
slouken@561
   184
					SDL_free(music->cvt.buf);
slouken@0
   185
				}
slouken@173
   186
				worksize = original_len*music->cvt.len_mult;
slouken@561
   187
				music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
slouken@173
   188
				if ( music->cvt.buf == NULL ) {
slouken@408
   189
					return 0;
slouken@0
   190
				}
slouken@173
   191
				music->cvt.len = original_len;
slouken@0
   192
			}
slouken@173
   193
			if ( (music->stop - pos) < original_len ) {
slouken@407
   194
				left = (original_len - (music->stop - pos));
slouken@407
   195
				original_len -= left;
slouken@407
   196
				left = (int)((double)left*music->cvt.len_ratio);
slouken@0
   197
			}
slouken@381
   198
			original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
slouken@109
   199
			/* At least at the time of writing, SDL_ConvertAudio()
slouken@109
   200
			   does byte-order swapping starting at the end of the
slouken@109
   201
			   buffer. Thus, if we are reading 16-bit samples, we
slouken@109
   202
			   had better make damn sure that we get an even
slouken@109
   203
			   number of bytes, or we'll get garbage.
slouken@109
   204
			 */
slouken@173
   205
			if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
slouken@109
   206
				original_len--;
slouken@109
   207
			}
slouken@173
   208
			music->cvt.len = original_len;
slouken@173
   209
			SDL_ConvertAudio(&music->cvt);
slouken@214
   210
			SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
slouken@0
   211
		} else {
slouken@308
   212
			Uint8 *data;
slouken@173
   213
			if ( (music->stop - pos) < len ) {
slouken@407
   214
				left = (len - (music->stop - pos));
slouken@407
   215
				len -= left;
slouken@0
   216
			}
slouken@308
   217
			data = SDL_stack_alloc(Uint8, len);
slouken@308
   218
			if (data)
slouken@308
   219
			{		
slouken@381
   220
				SDL_RWread(music->rw, data, len, 1);
slouken@308
   221
				SDL_MixAudio(stream, data, len, wavestream_volume);
slouken@308
   222
				SDL_stack_free(data);
slouken@308
   223
			}	
slouken@0
   224
		}
slouken@0
   225
	}
slouken@407
   226
	return left;
slouken@0
   227
}
slouken@0
   228
slouken@0
   229
/* Stop playback of a stream previously started with WAVStream_Start() */
slouken@214
   230
void WAVStream_Stop(void)
slouken@0
   231
{
slouken@173
   232
	music = NULL;
slouken@0
   233
}
slouken@0
   234
slouken@0
   235
/* Close the given WAV stream */
slouken@214
   236
void WAVStream_FreeSong(WAVStream *wave)
slouken@0
   237
{
slouken@0
   238
	if ( wave ) {
slouken@0
   239
		/* Clean up associated data */
slouken@0
   240
		if ( wave->cvt.buf ) {
slouken@561
   241
			SDL_free(wave->cvt.buf);
slouken@0
   242
		}
slouken@521
   243
		if ( wave->freerw ) {
slouken@521
   244
			SDL_RWclose(wave->rw);
slouken@521
   245
		}
slouken@561
   246
		SDL_free(wave);
slouken@0
   247
	}
slouken@0
   248
}
slouken@0
   249
slouken@0
   250
/* Return non-zero if a stream is currently playing */
slouken@214
   251
int WAVStream_Active(void)
slouken@0
   252
{
slouken@0
   253
	int active;
slouken@0
   254
slouken@0
   255
	active = 0;
slouken@381
   256
	if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
slouken@0
   257
		active = 1;
slouken@0
   258
	}
slouken@0
   259
	return(active);
slouken@0
   260
}
slouken@0
   261
slouken@0
   262
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
slouken@0
   263
{
slouken@0
   264
	chunk->magic	= SDL_ReadLE32(src);
slouken@0
   265
	chunk->length	= SDL_ReadLE32(src);
slouken@0
   266
	if ( read_data ) {
slouken@561
   267
		chunk->data = (Uint8 *)SDL_malloc(chunk->length);
slouken@0
   268
		if ( chunk->data == NULL ) {
slouken@134
   269
			Mix_SetError("Out of memory");
slouken@0
   270
			return(-1);
slouken@0
   271
		}
slouken@0
   272
		if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
slouken@134
   273
			Mix_SetError("Couldn't read chunk");
slouken@561
   274
			SDL_free(chunk->data);
slouken@0
   275
			return(-1);
slouken@0
   276
		}
slouken@0
   277
	} else {
slouken@473
   278
		SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
slouken@0
   279
	}
slouken@0
   280
	return(chunk->length);
slouken@0
   281
}
slouken@0
   282
slouken@381
   283
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@0
   284
					long *start, long *stop)
slouken@0
   285
{
slouken@0
   286
	int was_error;
slouken@0
   287
	Chunk chunk;
slouken@0
   288
	int lenread;
slouken@0
   289
slouken@0
   290
	/* WAV magic header */
slouken@0
   291
	Uint32 RIFFchunk;
slouken@0
   292
	Uint32 wavelen;
slouken@0
   293
	Uint32 WAVEmagic;
slouken@0
   294
slouken@0
   295
	/* FMT chunk */
slouken@0
   296
	WaveFMT *format = NULL;
slouken@0
   297
slouken@0
   298
	was_error = 0;
slouken@29
   299
slouken@0
   300
	/* Check the magic header */
slouken@0
   301
	RIFFchunk	= SDL_ReadLE32(src);
slouken@0
   302
	wavelen		= SDL_ReadLE32(src);
slouken@0
   303
	WAVEmagic	= SDL_ReadLE32(src);
slouken@0
   304
	if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
slouken@134
   305
		Mix_SetError("Unrecognized file type (not WAVE)");
slouken@0
   306
		was_error = 1;
slouken@0
   307
		goto done;
slouken@0
   308
	}
slouken@0
   309
slouken@0
   310
	/* Read the audio data format chunk */
slouken@0
   311
	chunk.data = NULL;
slouken@0
   312
	do {
slouken@0
   313
		/* FIXME! Add this logic to SDL_LoadWAV_RW() */
slouken@0
   314
		if ( chunk.data ) {
slouken@561
   315
			SDL_free(chunk.data);
slouken@0
   316
		}
slouken@0
   317
		lenread = ReadChunk(src, &chunk, 1);
slouken@0
   318
		if ( lenread < 0 ) {
slouken@0
   319
			was_error = 1;
slouken@0
   320
			goto done;
slouken@0
   321
		}
slouken@0
   322
	} while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
slouken@0
   323
slouken@0
   324
	/* Decode the audio data format */
slouken@0
   325
	format = (WaveFMT *)chunk.data;
slouken@0
   326
	if ( chunk.magic != FMT ) {
slouken@561
   327
		SDL_free(chunk.data);
slouken@134
   328
		Mix_SetError("Complex WAVE files not supported");
slouken@0
   329
		was_error = 1;
slouken@0
   330
		goto done;
slouken@0
   331
	}
slouken@0
   332
	switch (SDL_SwapLE16(format->encoding)) {
slouken@0
   333
		case PCM_CODE:
slouken@0
   334
			/* We can understand this */
slouken@0
   335
			break;
slouken@0
   336
		default:
slouken@134
   337
			Mix_SetError("Unknown WAVE data format");
slouken@0
   338
			was_error = 1;
slouken@0
   339
			goto done;
slouken@0
   340
	}
slouken@0
   341
	memset(spec, 0, (sizeof *spec));
slouken@0
   342
	spec->freq = SDL_SwapLE32(format->frequency);
slouken@0
   343
	switch (SDL_SwapLE16(format->bitspersample)) {
slouken@0
   344
		case 8:
slouken@0
   345
			spec->format = AUDIO_U8;
slouken@0
   346
			break;
slouken@0
   347
		case 16:
slouken@0
   348
			spec->format = AUDIO_S16;
slouken@0
   349
			break;
slouken@0
   350
		default:
slouken@134
   351
			Mix_SetError("Unknown PCM data format");
slouken@0
   352
			was_error = 1;
slouken@0
   353
			goto done;
slouken@0
   354
	}
slouken@42
   355
	spec->channels = (Uint8) SDL_SwapLE16(format->channels);
slouken@0
   356
	spec->samples = 4096;		/* Good default buffer size */
slouken@0
   357
slouken@0
   358
	/* Set the file offset to the DATA chunk data */
slouken@0
   359
	chunk.data = NULL;
slouken@0
   360
	do {
slouken@0
   361
		*start = SDL_RWtell(src) + 2*sizeof(Uint32);
slouken@0
   362
		lenread = ReadChunk(src, &chunk, 0);
slouken@0
   363
		if ( lenread < 0 ) {
slouken@0
   364
			was_error = 1;
slouken@0
   365
			goto done;
slouken@0
   366
		}
slouken@0
   367
	} while ( chunk.magic != DATA );
slouken@0
   368
	*stop = SDL_RWtell(src);
slouken@0
   369
slouken@0
   370
done:
slouken@0
   371
	if ( format != NULL ) {
slouken@561
   372
		SDL_free(format);
slouken@0
   373
	}
slouken@381
   374
	if ( was_error ) {
slouken@381
   375
		return NULL;
slouken@0
   376
	}
slouken@381
   377
	return(src);
slouken@0
   378
}
slouken@0
   379
slouken@95
   380
/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
slouken@95
   381
 * I don't pretend to fully understand it.
slouken@95
   382
 */
slouken@95
   383
slouken@95
   384
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
slouken@0
   385
{
slouken@95
   386
	/* Negative number? */
slouken@95
   387
	if (sanebuf[0] & 0x80)
slouken@95
   388
		return 0;
slouken@0
   389
slouken@95
   390
	/* Less than 1? */
slouken@95
   391
	if (sanebuf[0] <= 0x3F)
slouken@95
   392
		return 1;
slouken@95
   393
slouken@95
   394
	/* Way too big? */
slouken@95
   395
	if (sanebuf[0] > 0x40)
slouken@95
   396
		return 0x4000000;
slouken@95
   397
slouken@95
   398
	/* Still too big? */
slouken@95
   399
	if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
slouken@95
   400
		return 800000000;
slouken@95
   401
slouken@95
   402
	return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
slouken@95
   403
		| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
slouken@0
   404
}
slouken@0
   405
slouken@381
   406
static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
slouken@0
   407
					long *start, long *stop)
slouken@0
   408
{
slouken@0
   409
	int was_error;
slouken@95
   410
	int found_SSND;
slouken@95
   411
	int found_COMM;
slouken@0
   412
slouken@95
   413
	Uint32 chunk_type;
slouken@95
   414
	Uint32 chunk_length;
slouken@95
   415
	long next_chunk;
slouken@95
   416
slouken@0
   417
	/* AIFF magic header */
slouken@0
   418
	Uint32 FORMchunk;
slouken@0
   419
	Uint32 AIFFmagic;
slouken@0
   420
	/* SSND chunk        */
slouken@0
   421
	Uint32 offset;
slouken@0
   422
	Uint32 blocksize;
slouken@0
   423
	/* COMM format chunk */
slouken@142
   424
	Uint16 channels = 0;
slouken@142
   425
	Uint32 numsamples = 0;
slouken@142
   426
	Uint16 samplesize = 0;
slouken@95
   427
	Uint8 sane_freq[10];
slouken@142
   428
	Uint32 frequency = 0;
slouken@0
   429
slouken@0
   430
	was_error = 0;
slouken@29
   431
slouken@0
   432
	/* Check the magic header */
slouken@0
   433
	FORMchunk	= SDL_ReadLE32(src);
slouken@95
   434
	chunk_length	= SDL_ReadBE32(src);
slouken@0
   435
	AIFFmagic	= SDL_ReadLE32(src);
slouken@0
   436
	if ( (FORMchunk != FORM) || (AIFFmagic != AIFF) ) {
slouken@134
   437
		Mix_SetError("Unrecognized file type (not AIFF)");
slouken@0
   438
		was_error = 1;
slouken@0
   439
		goto done;
slouken@0
   440
	}
slouken@0
   441
slouken@95
   442
	/* From what I understand of the specification, chunks may appear in
slouken@95
   443
         * any order, and we should just ignore unknown ones.
slouken@109
   444
	 *
slouken@109
   445
	 * TODO: Better sanity-checking. E.g. what happens if the AIFF file
slouken@109
   446
	 *       contains compressed sound data?
slouken@95
   447
         */
slouken@95
   448
slouken@95
   449
	found_SSND = 0;
slouken@95
   450
	found_COMM = 0;
slouken@95
   451
slouken@95
   452
	do {
slouken@95
   453
	    chunk_type		= SDL_ReadLE32(src);
slouken@95
   454
	    chunk_length	= SDL_ReadBE32(src);
slouken@95
   455
	    next_chunk		= SDL_RWtell(src) + chunk_length;
slouken@95
   456
slouken@95
   457
	    /* Paranoia to avoid infinite loops */
slouken@95
   458
	    if (chunk_length == 0)
slouken@95
   459
		break;
slouken@95
   460
slouken@95
   461
            switch (chunk_type) {
slouken@95
   462
		case SSND:
slouken@95
   463
		    found_SSND		= 1;
slouken@95
   464
		    offset		= SDL_ReadBE32(src);
slouken@95
   465
		    blocksize		= SDL_ReadBE32(src);
slouken@95
   466
		    *start		= SDL_RWtell(src) + offset;
slouken@95
   467
		    break;
slouken@95
   468
slouken@95
   469
		case COMM:
slouken@95
   470
		    found_COMM		= 1;
slouken@95
   471
slouken@95
   472
		    /* Read the audio data format chunk */
slouken@95
   473
		    channels		= SDL_ReadBE16(src);
slouken@95
   474
		    numsamples		= SDL_ReadBE32(src);
slouken@95
   475
		    samplesize		= SDL_ReadBE16(src);
slouken@95
   476
		    SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
slouken@95
   477
		    frequency		= SANE_to_Uint32(sane_freq);
slouken@95
   478
		    break;
slouken@95
   479
slouken@95
   480
		default:
slouken@95
   481
		    break;
slouken@95
   482
	    }
slouken@95
   483
	} while ((!found_SSND || !found_COMM)
slouken@473
   484
		 && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
slouken@95
   485
slouken@95
   486
	if (!found_SSND) {
slouken@134
   487
	    Mix_SetError("Bad AIFF file (no SSND chunk)");
slouken@95
   488
	    was_error = 1;
slouken@95
   489
	    goto done;
slouken@0
   490
	}
slouken@95
   491
		    
slouken@95
   492
	if (!found_COMM) {
slouken@134
   493
	    Mix_SetError("Bad AIFF file (no COMM chunk)");
slouken@95
   494
	    was_error = 1;
slouken@95
   495
	    goto done;
slouken@95
   496
	}
slouken@0
   497
slouken@109
   498
	*stop = *start + channels * numsamples * (samplesize / 8);
slouken@0
   499
slouken@0
   500
	/* Decode the audio data format */
slouken@0
   501
	memset(spec, 0, (sizeof *spec));
slouken@0
   502
	spec->freq = frequency;
slouken@0
   503
	switch (samplesize) {
slouken@0
   504
		case 8:
slouken@109
   505
			spec->format = AUDIO_S8;
slouken@0
   506
			break;
slouken@0
   507
		case 16:
slouken@95
   508
			spec->format = AUDIO_S16MSB;
slouken@0
   509
			break;
slouken@0
   510
		default:
slouken@134
   511
			Mix_SetError("Unknown samplesize in data format");
slouken@0
   512
			was_error = 1;
slouken@0
   513
			goto done;
slouken@0
   514
	}
slouken@42
   515
	spec->channels = (Uint8) channels;
slouken@0
   516
	spec->samples = 4096;		/* Good default buffer size */
slouken@0
   517
slouken@0
   518
done:
slouken@381
   519
	if ( was_error ) {
slouken@381
   520
		return NULL;
slouken@0
   521
	}
slouken@381
   522
	return(src);
slouken@0
   523
}
slouken@308
   524