music_flac.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Jan 2012 03:15:19 -0500
changeset 561 87bdb4c81c0b
parent 545 32e5ed415a34
child 601 05123263dab3
child 947 41422d16ee01
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@382
     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@382
     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@382
     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@382
    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@382
    20
slouken@518
    21
  This file is used to support SDL_LoadMUS playback of FLAC files.
slouken@518
    22
  	~ Austen Dicken (admin@cvpcs.org)
slouken@382
    23
*/
slouken@382
    24
slouken@382
    25
#ifdef FLAC_MUSIC
slouken@382
    26
slouken@382
    27
#include <stdio.h>
slouken@382
    28
#include <stdlib.h>
slouken@382
    29
#include <string.h>
slouken@382
    30
slouken@382
    31
#include "SDL_mixer.h"
slouken@382
    32
#include "dynamic_flac.h"
slouken@382
    33
#include "music_flac.h"
slouken@382
    34
slouken@382
    35
/* This is the format of the audio mixer data */
slouken@382
    36
static SDL_AudioSpec mixer;
slouken@382
    37
slouken@382
    38
/* Initialize the FLAC player, with the given mixer settings
slouken@382
    39
   This function returns 0, or -1 if there was an error.
slouken@382
    40
 */
slouken@409
    41
int FLAC_init(SDL_AudioSpec *mixerfmt)
slouken@409
    42
{
slouken@382
    43
	mixer = *mixerfmt;
slouken@382
    44
	return(0);
slouken@382
    45
}
slouken@382
    46
slouken@382
    47
/* Set the volume for an FLAC stream */
slouken@409
    48
void FLAC_setvolume(FLAC_music *music, int volume)
slouken@409
    49
{
slouken@382
    50
	music->volume = volume;
slouken@382
    51
}
slouken@382
    52
slouken@382
    53
static FLAC__StreamDecoderReadStatus flac_read_music_cb(
slouken@382
    54
									const FLAC__StreamDecoder *decoder,
slouken@382
    55
									FLAC__byte buffer[],
slouken@382
    56
									size_t *bytes,
slouken@409
    57
									void *client_data)
slouken@409
    58
{
slouken@382
    59
	FLAC_music *data = (FLAC_music*)client_data;
slouken@382
    60
slouken@382
    61
	// make sure there is something to be reading
slouken@382
    62
	if (*bytes > 0) {
slouken@382
    63
		*bytes = SDL_RWread (data->rwops, buffer, sizeof (FLAC__byte), *bytes);
slouken@382
    64
slouken@382
    65
		if (*bytes < 0) { // error in read
slouken@382
    66
			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
slouken@382
    67
		}
slouken@382
    68
		else if (*bytes == 0 ) { // no data was read (EOF)
slouken@382
    69
			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
slouken@382
    70
		}
slouken@382
    71
		else { // data was read, continue
slouken@382
    72
			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
slouken@382
    73
		}
slouken@382
    74
	}
slouken@382
    75
	else {
slouken@382
    76
		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
slouken@382
    77
	}
slouken@382
    78
}
slouken@382
    79
slouken@382
    80
static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
slouken@382
    81
									const FLAC__StreamDecoder *decoder,
slouken@382
    82
									FLAC__uint64 absolute_byte_offset,
slouken@409
    83
									void *client_data)
slouken@409
    84
{
slouken@382
    85
	FLAC_music *data = (FLAC_music*)client_data;
slouken@382
    86
slouken@473
    87
	if (SDL_RWseek (data->rwops, absolute_byte_offset, RW_SEEK_SET) < 0) {
slouken@382
    88
		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
slouken@382
    89
	}
slouken@382
    90
	else {
slouken@382
    91
		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
slouken@382
    92
	}
slouken@382
    93
}
slouken@382
    94
slouken@382
    95
static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
slouken@382
    96
									const FLAC__StreamDecoder *decoder,
slouken@382
    97
									FLAC__uint64 *absolute_byte_offset,
slouken@409
    98
									void *client_data )
slouken@409
    99
{
slouken@382
   100
	FLAC_music *data = (FLAC_music*)client_data;
slouken@382
   101
slouken@382
   102
	int pos = SDL_RWtell (data->rwops);
slouken@382
   103
slouken@382
   104
	if (pos < 0) {
slouken@382
   105
		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
slouken@382
   106
	}
slouken@382
   107
	else {
slouken@382
   108
		*absolute_byte_offset = (FLAC__uint64)pos;
slouken@382
   109
		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
slouken@382
   110
	}
slouken@382
   111
}
slouken@382
   112
slouken@382
   113
static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
slouken@382
   114
									const FLAC__StreamDecoder *decoder,
slouken@382
   115
									FLAC__uint64 *stream_length,
slouken@409
   116
									void *client_data)
slouken@409
   117
{
slouken@382
   118
	FLAC_music *data = (FLAC_music*)client_data;
slouken@382
   119
slouken@382
   120
	int pos = SDL_RWtell (data->rwops);
slouken@473
   121
	int length = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
slouken@382
   122
slouken@473
   123
	if (SDL_RWseek (data->rwops, pos, RW_SEEK_SET) != pos || length < 0) {
slouken@382
   124
		/* there was an error attempting to return the stream to the original
slouken@382
   125
		 * position, or the length was invalid. */
slouken@382
   126
		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
slouken@382
   127
	}
slouken@382
   128
	else {
slouken@382
   129
		*stream_length = (FLAC__uint64)length;
slouken@382
   130
		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
slouken@382
   131
	}
slouken@382
   132
}
slouken@382
   133
slouken@382
   134
static FLAC__bool flac_eof_music_cb(
slouken@382
   135
								const FLAC__StreamDecoder *decoder,
slouken@409
   136
								void *client_data )
slouken@409
   137
{
slouken@382
   138
	FLAC_music *data = (FLAC_music*)client_data;
slouken@382
   139
slouken@382
   140
	int pos = SDL_RWtell (data->rwops);
slouken@473
   141
	int end = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
slouken@382
   142
slouken@382
   143
	// was the original position equal to the end (a.k.a. the seek didn't move)?
slouken@382
   144
	if (pos == end) {
slouken@382
   145
		// must be EOF
slouken@382
   146
		return true;
slouken@382
   147
	}
slouken@382
   148
	else {
slouken@382
   149
		// not EOF, return to the original position
slouken@473
   150
		SDL_RWseek (data->rwops, pos, RW_SEEK_SET);
slouken@382
   151
slouken@382
   152
		return false;
slouken@382
   153
	}
slouken@382
   154
}
slouken@382
   155
slouken@382
   156
static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
slouken@382
   157
									const FLAC__StreamDecoder *decoder,
slouken@382
   158
									const FLAC__Frame *frame,
slouken@382
   159
									const FLAC__int32 *const buffer[],
slouken@409
   160
									void *client_data)
slouken@409
   161
{
slouken@382
   162
	FLAC_music *data = (FLAC_music *)client_data;
slouken@382
   163
	size_t i;
slouken@382
   164
slouken@382
   165
	if (data->flac_data.total_samples == 0) {
slouken@382
   166
		SDL_SetError ("Given FLAC file does not specify its sample count.");
slouken@382
   167
		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@382
   168
	}
slouken@382
   169
slouken@382
   170
	if (data->flac_data.channels != 2 ||
slouken@382
   171
		data->flac_data.bits_per_sample != 16) {
slouken@382
   172
		SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
slouken@382
   173
		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@382
   174
	}
slouken@382
   175
slouken@382
   176
	for (i = 0; i < frame->header.blocksize; i++) {
slouken@436
   177
		FLAC__int16 i16;
slouken@436
   178
		FLAC__uint16 ui16;
slouken@436
   179
slouken@382
   180
		// make sure we still have at least two bytes that can be read (one for
slouken@382
   181
		// each channel)
slouken@382
   182
		if (data->flac_data.max_to_read >= 4) {
slouken@382
   183
			// does the data block exist?
slouken@382
   184
			if (!data->flac_data.data) {
slouken@382
   185
				data->flac_data.data_len = data->flac_data.max_to_read;
slouken@382
   186
				data->flac_data.data_read = 0;
slouken@382
   187
slouken@382
   188
				// create it
slouken@382
   189
				data->flac_data.data =
slouken@561
   190
					(char *)SDL_malloc (data->flac_data.data_len);
slouken@382
   191
slouken@382
   192
				if (!data->flac_data.data) {
slouken@382
   193
					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@382
   194
				}
slouken@382
   195
			}
slouken@382
   196
slouken@382
   197
			i16 = (FLAC__int16)buffer[0][i];
slouken@382
   198
			ui16 = (FLAC__uint16)i16;
slouken@382
   199
slouken@382
   200
			*((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@382
   201
															(char)(ui16);
slouken@382
   202
			*((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@382
   203
															(char)(ui16 >> 8);
slouken@382
   204
slouken@382
   205
			i16 = (FLAC__int16)buffer[1][i];
slouken@382
   206
			ui16 = (FLAC__uint16)i16;
slouken@382
   207
slouken@382
   208
			*((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@382
   209
															(char)(ui16);
slouken@382
   210
			*((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@382
   211
															(char)(ui16 >> 8);
slouken@382
   212
slouken@382
   213
			data->flac_data.max_to_read -= 4;
slouken@382
   214
slouken@382
   215
			if (data->flac_data.max_to_read < 4) {
slouken@382
   216
				// we need to set this so that the read halts from the
slouken@382
   217
				// FLAC_getsome function.
slouken@382
   218
				data->flac_data.max_to_read = 0;
slouken@382
   219
			}
slouken@382
   220
		}
slouken@382
   221
		else {
slouken@382
   222
			// we need to write to the overflow
slouken@382
   223
			if (!data->flac_data.overflow) {
slouken@382
   224
				data->flac_data.overflow_len =
slouken@382
   225
											4 * (frame->header.blocksize - i);
slouken@382
   226
				data->flac_data.overflow_read = 0;
slouken@382
   227
slouken@382
   228
				// make it big enough for the rest of the block
slouken@382
   229
				data->flac_data.overflow =
slouken@561
   230
					(char *)SDL_malloc (data->flac_data.overflow_len);
slouken@382
   231
slouken@382
   232
				if (!data->flac_data.overflow) {
slouken@382
   233
					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@382
   234
				}
slouken@382
   235
			}
slouken@382
   236
slouken@382
   237
			i16 = (FLAC__int16)buffer[0][i];
slouken@382
   238
			ui16 = (FLAC__uint16)i16;
slouken@382
   239
slouken@382
   240
			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@382
   241
															(char)(ui16);
slouken@382
   242
			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@382
   243
															(char)(ui16 >> 8);
slouken@382
   244
slouken@382
   245
			i16 = (FLAC__int16)buffer[1][i];
slouken@382
   246
			ui16 = (FLAC__uint16)i16;
slouken@382
   247
slouken@382
   248
			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@382
   249
															(char)(ui16);
slouken@382
   250
			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@382
   251
															(char)(ui16 >> 8);
slouken@382
   252
		}
slouken@382
   253
	}
slouken@382
   254
slouken@382
   255
	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
slouken@382
   256
}
slouken@382
   257
slouken@382
   258
static void flac_metadata_music_cb(
slouken@382
   259
					const FLAC__StreamDecoder *decoder,
slouken@382
   260
					const FLAC__StreamMetadata *metadata,
slouken@409
   261
					void *client_data)
slouken@409
   262
{
slouken@382
   263
	FLAC_music *data = (FLAC_music *)client_data;
slouken@382
   264
slouken@382
   265
	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
slouken@382
   266
		data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
slouken@382
   267
		data->flac_data.channels = metadata->data.stream_info.channels;
slouken@382
   268
		data->flac_data.total_samples =
slouken@382
   269
							metadata->data.stream_info.total_samples;
slouken@382
   270
		data->flac_data.bits_per_sample =
slouken@382
   271
							metadata->data.stream_info.bits_per_sample;
slouken@382
   272
		data->flac_data.sample_size = data->flac_data.channels *
slouken@382
   273
										((data->flac_data.bits_per_sample) / 8);
slouken@382
   274
	}
slouken@382
   275
}
slouken@382
   276
slouken@382
   277
static void flac_error_music_cb(
slouken@382
   278
				const FLAC__StreamDecoder *decoder,
slouken@382
   279
				FLAC__StreamDecoderErrorStatus status,
slouken@409
   280
				void *client_data)
slouken@409
   281
{
slouken@382
   282
	// print an SDL error based on the error status
slouken@382
   283
	switch (status) {
slouken@382
   284
		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
slouken@382
   285
			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
slouken@382
   286
		break;
slouken@382
   287
		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
slouken@382
   288
			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
slouken@382
   289
		break;
slouken@382
   290
		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
slouken@382
   291
			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
slouken@382
   292
		break;
slouken@382
   293
		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
slouken@382
   294
			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
slouken@382
   295
		break;
slouken@382
   296
		default:
slouken@382
   297
			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
slouken@382
   298
		break;
slouken@382
   299
	}
slouken@382
   300
}
slouken@382
   301
slouken@382
   302
/* Load an FLAC stream from an SDL_RWops object */
slouken@521
   303
FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw)
slouken@409
   304
{
slouken@382
   305
	FLAC_music *music;
slouken@382
   306
	int init_stage = 0;
slouken@382
   307
	int was_error = 1;
slouken@382
   308
slouken@545
   309
	if (!Mix_Init(MIX_INIT_FLAC)) {
slouken@545
   310
		if (freerw) {
slouken@545
   311
			SDL_RWclose(rw);
slouken@545
   312
		}
slouken@545
   313
		return NULL;
slouken@545
   314
	}
slouken@545
   315
slouken@561
   316
	music = (FLAC_music *)SDL_malloc ( sizeof (*music));
slouken@382
   317
	if (music) {
slouken@382
   318
		/* Initialize the music structure */
slouken@382
   319
		memset (music, 0, (sizeof (*music)));
slouken@382
   320
		FLAC_stop (music);
slouken@382
   321
		FLAC_setvolume (music, MIX_MAX_VOLUME);
slouken@382
   322
		music->section = -1;
slouken@382
   323
		music->rwops = rw;
slouken@521
   324
		music->freerw = freerw;
slouken@382
   325
		music->flac_data.max_to_read = 0;
slouken@382
   326
		music->flac_data.overflow = NULL;
slouken@382
   327
		music->flac_data.overflow_len = 0;
slouken@382
   328
		music->flac_data.overflow_read = 0;
slouken@382
   329
		music->flac_data.data = NULL;
slouken@382
   330
		music->flac_data.data_len = 0;
slouken@382
   331
		music->flac_data.data_read = 0;
slouken@382
   332
slouken@545
   333
		init_stage++; // stage 1!
slouken@382
   334
slouken@545
   335
		music->flac_decoder = flac.FLAC__stream_decoder_new ();
slouken@382
   336
slouken@545
   337
		if (music->flac_decoder != NULL) {
slouken@545
   338
			init_stage++; // stage 2!
slouken@382
   339
slouken@545
   340
			if (flac.FLAC__stream_decoder_init_stream(
slouken@545
   341
						music->flac_decoder,
slouken@545
   342
						flac_read_music_cb, flac_seek_music_cb,
slouken@545
   343
						flac_tell_music_cb, flac_length_music_cb,
slouken@545
   344
						flac_eof_music_cb, flac_write_music_cb,
slouken@545
   345
						flac_metadata_music_cb, flac_error_music_cb,
slouken@545
   346
						music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
slouken@545
   347
				init_stage++; // stage 3!
slouken@382
   348
slouken@545
   349
				if (flac.FLAC__stream_decoder_process_until_end_of_metadata
slouken@545
   350
										(music->flac_decoder)) {
slouken@545
   351
					was_error = 0;
slouken@470
   352
				} else {
slouken@545
   353
					SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
slouken@382
   354
				}
slouken@470
   355
			} else {
slouken@545
   356
				SDL_SetError("FLAC__stream_decoder_init_stream() failed");
slouken@382
   357
			}
slouken@545
   358
		} else {
slouken@545
   359
			SDL_SetError("FLAC__stream_decoder_new() failed");
slouken@382
   360
		}
slouken@382
   361
slouken@382
   362
		if (was_error) {
slouken@382
   363
			switch (init_stage) {
slouken@382
   364
				case 3:
slouken@382
   365
					flac.FLAC__stream_decoder_finish( music->flac_decoder );
slouken@382
   366
				case 2:
slouken@382
   367
					flac.FLAC__stream_decoder_delete( music->flac_decoder );
slouken@382
   368
				case 1:
slouken@382
   369
				case 0:
slouken@561
   370
					SDL_free(music);
slouken@521
   371
					if (freerw) {
slouken@521
   372
						SDL_RWclose(rw);
slouken@521
   373
					}
slouken@382
   374
					break;
slouken@382
   375
			}
slouken@382
   376
			return NULL;
slouken@382
   377
		}
slouken@521
   378
	} else {
slouken@382
   379
		SDL_OutOfMemory();
slouken@521
   380
		if (freerw) {
slouken@521
   381
			SDL_RWclose(rw);
slouken@521
   382
		}
slouken@521
   383
		return NULL;
slouken@382
   384
	}
slouken@382
   385
slouken@382
   386
	return music;
slouken@382
   387
}
slouken@382
   388
slouken@382
   389
/* Start playback of a given FLAC stream */
slouken@409
   390
void FLAC_play(FLAC_music *music)
slouken@409
   391
{
slouken@382
   392
	music->playing = 1;
slouken@382
   393
}
slouken@382
   394
slouken@382
   395
/* Return non-zero if a stream is currently playing */
slouken@409
   396
int FLAC_playing(FLAC_music *music)
slouken@409
   397
{
slouken@382
   398
	return(music->playing);
slouken@382
   399
}
slouken@382
   400
slouken@382
   401
/* Read some FLAC stream data and convert it for output */
slouken@409
   402
static void FLAC_getsome(FLAC_music *music)
slouken@409
   403
{
slouken@382
   404
	SDL_AudioCVT *cvt;
slouken@382
   405
slouken@522
   406
	/* GET AUDIO WAVE DATA */
slouken@382
   407
	// set the max number of characters to read
slouken@382
   408
	music->flac_data.max_to_read = 8192;
slouken@382
   409
	music->flac_data.data_len = music->flac_data.max_to_read;
slouken@382
   410
	music->flac_data.data_read = 0;
slouken@524
   411
	if (!music->flac_data.data) {
slouken@561
   412
		music->flac_data.data = (char *)SDL_malloc (music->flac_data.data_len);
slouken@524
   413
	}
slouken@382
   414
slouken@382
   415
	// we have data to read
slouken@382
   416
	while(music->flac_data.max_to_read > 0) {
slouken@382
   417
		// first check if there is data in the overflow from before
slouken@382
   418
		if (music->flac_data.overflow) {
slouken@382
   419
			size_t overflow_len = music->flac_data.overflow_read;
slouken@382
   420
slouken@382
   421
			if (overflow_len > music->flac_data.max_to_read) {
slouken@382
   422
				size_t overflow_extra_len = overflow_len -
slouken@382
   423
												music->flac_data.max_to_read;
slouken@382
   424
slouken@382
   425
				memcpy (music->flac_data.data+music->flac_data.data_read,
slouken@382
   426
					music->flac_data.overflow, music->flac_data.max_to_read);
slouken@382
   427
				music->flac_data.data_read += music->flac_data.max_to_read;
slouken@524
   428
				memcpy (music->flac_data.overflow,
slouken@382
   429
					music->flac_data.overflow + music->flac_data.max_to_read,
slouken@382
   430
					overflow_extra_len);
slouken@382
   431
				music->flac_data.overflow_len = overflow_extra_len;
slouken@522
   432
				music->flac_data.overflow_read = overflow_extra_len;
slouken@382
   433
				music->flac_data.max_to_read = 0;
slouken@382
   434
			}
slouken@382
   435
			else {
slouken@382
   436
				memcpy (music->flac_data.data+music->flac_data.data_read,
slouken@382
   437
					music->flac_data.overflow, overflow_len);
slouken@382
   438
				music->flac_data.data_read += overflow_len;
slouken@382
   439
				free (music->flac_data.overflow);
slouken@382
   440
				music->flac_data.overflow = NULL;
slouken@382
   441
				music->flac_data.overflow_len = 0;
slouken@382
   442
				music->flac_data.overflow_read = 0;
slouken@382
   443
				music->flac_data.max_to_read -= overflow_len;
slouken@382
   444
			}
slouken@382
   445
		}
slouken@382
   446
		else {
slouken@382
   447
			if (!flac.FLAC__stream_decoder_process_single (
slouken@382
   448
														music->flac_decoder)) {
slouken@382
   449
				music->flac_data.max_to_read = 0;
slouken@382
   450
			}
slouken@382
   451
slouken@382
   452
			if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
slouken@382
   453
									== FLAC__STREAM_DECODER_END_OF_STREAM) {
slouken@382
   454
				music->flac_data.max_to_read = 0;
slouken@382
   455
			}
slouken@382
   456
		}
slouken@382
   457
	}
slouken@382
   458
slouken@382
   459
	if (music->flac_data.data_read <= 0) {
slouken@382
   460
		if (music->flac_data.data_read == 0) {
slouken@382
   461
			music->playing = 0;
slouken@382
   462
		}
slouken@382
   463
		return;
slouken@382
   464
	}
slouken@382
   465
	cvt = &music->cvt;
slouken@487
   466
	if (music->section < 0) {
slouken@382
   467
slouken@382
   468
		SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
slouken@382
   469
						(int)music->flac_data.sample_rate, mixer.format,
slouken@382
   470
		                mixer.channels, mixer.freq);
slouken@382
   471
		if (cvt->buf) {
slouken@382
   472
			free (cvt->buf);
slouken@382
   473
		}
slouken@561
   474
		cvt->buf = (Uint8 *)SDL_malloc (music->flac_data.data_len * cvt->len_mult);
slouken@487
   475
		music->section = 0;
slouken@382
   476
	}
slouken@382
   477
	if (cvt->buf) {
slouken@382
   478
		memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
slouken@382
   479
		if (cvt->needed) {
slouken@382
   480
			cvt->len = music->flac_data.data_read;
slouken@382
   481
			SDL_ConvertAudio (cvt);
slouken@382
   482
		}
slouken@382
   483
		else {
slouken@382
   484
			cvt->len_cvt = music->flac_data.data_read;
slouken@382
   485
		}
slouken@382
   486
		music->len_available = music->cvt.len_cvt;
slouken@382
   487
		music->snd_available = music->cvt.buf;
slouken@382
   488
	}
slouken@382
   489
	else {
slouken@382
   490
		SDL_SetError ("Out of memory");
slouken@382
   491
		music->playing = 0;
slouken@382
   492
	}
slouken@382
   493
}
slouken@382
   494
slouken@382
   495
/* Play some of a stream previously started with FLAC_play() */
slouken@409
   496
int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len)
slouken@409
   497
{
slouken@382
   498
	int mixable;
slouken@382
   499
slouken@382
   500
	while ((len > 0) && music->playing) {
slouken@382
   501
		if (!music->len_available) {
slouken@382
   502
			FLAC_getsome (music);
slouken@382
   503
		}
slouken@382
   504
		mixable = len;
slouken@382
   505
		if (mixable > music->len_available) {
slouken@382
   506
			mixable = music->len_available;
slouken@382
   507
		}
slouken@382
   508
		if (music->volume == MIX_MAX_VOLUME) {
slouken@382
   509
			memcpy (snd, music->snd_available, mixable);
slouken@382
   510
		}
slouken@382
   511
		else {
slouken@382
   512
			SDL_MixAudio (snd, music->snd_available, mixable, music->volume);
slouken@382
   513
		}
slouken@382
   514
		music->len_available -= mixable;
slouken@382
   515
		music->snd_available += mixable;
slouken@382
   516
		len -= mixable;
slouken@382
   517
		snd += mixable;
slouken@382
   518
	}
slouken@382
   519
slouken@382
   520
	return len;
slouken@382
   521
}
slouken@382
   522
slouken@382
   523
/* Stop playback of a stream previously started with FLAC_play() */
slouken@409
   524
void FLAC_stop(FLAC_music *music)
slouken@409
   525
{
slouken@382
   526
	music->playing = 0;
slouken@382
   527
}
slouken@382
   528
slouken@382
   529
/* Close the given FLAC_music object */
slouken@409
   530
void FLAC_delete(FLAC_music *music)
slouken@409
   531
{
slouken@382
   532
	if (music) {
slouken@382
   533
		if (music->flac_decoder) {
slouken@382
   534
			flac.FLAC__stream_decoder_finish (music->flac_decoder);
slouken@382
   535
			flac.FLAC__stream_decoder_delete (music->flac_decoder);
slouken@382
   536
		}
slouken@382
   537
slouken@382
   538
		if (music->flac_data.data) {
slouken@382
   539
			free (music->flac_data.data);
slouken@382
   540
		}
slouken@382
   541
slouken@382
   542
		if (music->flac_data.overflow) {
slouken@382
   543
			free (music->flac_data.overflow);
slouken@382
   544
		}
slouken@382
   545
slouken@382
   546
		if (music->cvt.buf) {
slouken@382
   547
			free (music->cvt.buf);
slouken@382
   548
		}
slouken@382
   549
slouken@521
   550
		if (music->freerw) {
slouken@521
   551
			SDL_RWclose(music->rwops);
slouken@521
   552
		}
slouken@382
   553
		free (music);
slouken@382
   554
	}
slouken@382
   555
}
slouken@382
   556
slouken@382
   557
/* Jump (seek) to a given position (time is in seconds) */
slouken@409
   558
void FLAC_jump_to_time(FLAC_music *music, double time)
slouken@409
   559
{
slouken@382
   560
	if (music) {
slouken@382
   561
		if (music->flac_decoder) {
slouken@382
   562
			double seek_sample = music->flac_data.sample_rate * time;
slouken@382
   563
slouken@382
   564
			// clear data if it has data
slouken@382
   565
			if (music->flac_data.data) {
slouken@382
   566
				free (music->flac_data.data);
slouken@382
   567
				music->flac_data.data = NULL;
slouken@382
   568
			}
slouken@382
   569
slouken@382
   570
			// clear overflow if it has data
slouken@382
   571
			if (music->flac_data.overflow) {
slouken@382
   572
				free (music->flac_data.overflow);
slouken@382
   573
				music->flac_data.overflow = NULL;
slouken@382
   574
			}
slouken@382
   575
slouken@382
   576
			if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
slouken@382
   577
												(FLAC__uint64)seek_sample)) {
slouken@382
   578
				if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
slouken@382
   579
										== FLAC__STREAM_DECODER_SEEK_ERROR) {
slouken@382
   580
					flac.FLAC__stream_decoder_flush (music->flac_decoder);
slouken@382
   581
				}
slouken@382
   582
slouken@382
   583
				SDL_SetError
slouken@382
   584
					("Seeking of FLAC stream failed: libFLAC seek failed.");
slouken@382
   585
			}
slouken@382
   586
		}
slouken@382
   587
		else {
slouken@382
   588
			SDL_SetError
slouken@382
   589
				("Seeking of FLAC stream failed: FLAC decoder was NULL.");
slouken@382
   590
		}
slouken@382
   591
	}
slouken@382
   592
	else {
slouken@382
   593
		SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
slouken@382
   594
	}
slouken@382
   595
}
slouken@382
   596
slouken@382
   597
#endif /* FLAC_MUSIC */