music_flac.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Feb 2008 07:31:03 +0000
changeset 382 50501e45c57b
child 386 695494546b3c
permissions -rw-r--r--
Austen Dicken - Tue Feb 26 23:28:27 PST 2008

Ok, here is the patch I made for FLAC support.

I have tested it relatively thoroughly and currently the patch allows:
1. Pre-loading FLAC files and playing them via LoadWAV
2. The patch allows for FLAC support in the LoadMUS setting as well as:
* Pause / Resume
* Volume control
* Seeking

I also did a little benchmarking by comparing memory/cpu usage of playmus to
that of mplayer, and the results were very good. playmus typically took about
half the RAM as mplayer, though that may be attributed to mplayer being a more
"bulky" program. As such I would say that the two are probably about equal in
efficiency.

Also, it is important to note that, similar to the OGG support currently
built-in, my FLAC patch only supports 16 bit stereo-encoded sound. Also, it
is only for Native FLAC (standard) and not the derivative, Ogg-FLAC.

I have tried to find a simple way to detect Ogg-FLAC files, as the only
difference between Ogg-FLAC and Native FLAC support is changing the init_
function call, but after digging a little deeper it seems that Ogg-FLAC is
basically FLAC wrapped in an Ogg transport layer, so it would be better to have
a way to read the Ogg transport layer which then reads the inner audio files
according to the proper codec.

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