forked from len0rd/rockbox
		
	This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
		
			
				
	
	
		
			593 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			593 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|   SDL_mixer:  An audio mixer library based on the SDL library
 | |
|   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 | |
| 
 | |
|   This software is provided 'as-is', without any express or implied
 | |
|   warranty.  In no event will the authors be held liable for any damages
 | |
|   arising from the use of this software.
 | |
| 
 | |
|   Permission is granted to anyone to use this software for any purpose,
 | |
|   including commercial applications, and to alter it and redistribute it
 | |
|   freely, subject to the following restrictions:
 | |
| 
 | |
|   1. The origin of this software must not be misrepresented; you must not
 | |
|      claim that you wrote the original software. If you use this software
 | |
|      in a product, an acknowledgment in the product documentation would be
 | |
|      appreciated but is not required.
 | |
|   2. Altered source versions must be plainly marked as such, and must not be
 | |
|      misrepresented as being the original software.
 | |
|   3. This notice may not be removed or altered from any source distribution.
 | |
| 
 | |
|   This file is used to support SDL_LoadMUS playback of FLAC files.
 | |
|   	~ Austen Dicken (admin@cvpcs.org)
 | |
| */
 | |
| 
 | |
| #ifdef FLAC_MUSIC
 | |
| 
 | |
| #include "SDL_mixer.h"
 | |
| #include "dynamic_flac.h"
 | |
| #include "music_flac.h"
 | |
| 
 | |
| /* This is the format of the audio mixer data */
 | |
| static SDL_AudioSpec mixer;
 | |
| 
 | |
| /* Initialize the FLAC player, with the given mixer settings
 | |
|    This function returns 0, or -1 if there was an error.
 | |
|  */
 | |
| int FLAC_init(SDL_AudioSpec *mixerfmt)
 | |
| {
 | |
| 	mixer = *mixerfmt;
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| /* Set the volume for an FLAC stream */
 | |
| void FLAC_setvolume(FLAC_music *music, int volume)
 | |
| {
 | |
| 	music->volume = volume;
 | |
| }
 | |
| 
 | |
| static FLAC__StreamDecoderReadStatus flac_read_music_cb(
 | |
| 									const FLAC__StreamDecoder *decoder,
 | |
| 									FLAC__byte buffer[],
 | |
| 									size_t *bytes,
 | |
| 									void *client_data)
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music*)client_data;
 | |
| 
 | |
| 	// make sure there is something to be reading
 | |
| 	if (*bytes > 0) {
 | |
| 		*bytes = SDL_RWread (data->rwops, buffer, sizeof (FLAC__byte), *bytes);
 | |
| 
 | |
| 		if (*bytes < 0) { // error in read
 | |
| 			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
 | |
| 		}
 | |
| 		else if (*bytes == 0 ) { // no data was read (EOF)
 | |
| 			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
 | |
| 		}
 | |
| 		else { // data was read, continue
 | |
| 			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
 | |
| 									const FLAC__StreamDecoder *decoder,
 | |
| 									FLAC__uint64 absolute_byte_offset,
 | |
| 									void *client_data)
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music*)client_data;
 | |
| 
 | |
| 	if (SDL_RWseek (data->rwops, absolute_byte_offset, RW_SEEK_SET) < 0) {
 | |
| 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
 | |
| 	}
 | |
| 	else {
 | |
| 		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
 | |
| 									const FLAC__StreamDecoder *decoder,
 | |
| 									FLAC__uint64 *absolute_byte_offset,
 | |
| 									void *client_data )
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music*)client_data;
 | |
| 
 | |
| 	int pos = SDL_RWtell (data->rwops);
 | |
| 
 | |
| 	if (pos < 0) {
 | |
| 		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
 | |
| 	}
 | |
| 	else {
 | |
| 		*absolute_byte_offset = (FLAC__uint64)pos;
 | |
| 		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
 | |
| 									const FLAC__StreamDecoder *decoder,
 | |
| 									FLAC__uint64 *stream_length,
 | |
| 									void *client_data)
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music*)client_data;
 | |
| 
 | |
| 	int pos = SDL_RWtell (data->rwops);
 | |
| 	int length = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
 | |
| 
 | |
| 	if (SDL_RWseek (data->rwops, pos, RW_SEEK_SET) != pos || length < 0) {
 | |
| 		/* there was an error attempting to return the stream to the original
 | |
| 		 * position, or the length was invalid. */
 | |
| 		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
 | |
| 	}
 | |
| 	else {
 | |
| 		*stream_length = (FLAC__uint64)length;
 | |
| 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static FLAC__bool flac_eof_music_cb(
 | |
| 								const FLAC__StreamDecoder *decoder,
 | |
| 								void *client_data )
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music*)client_data;
 | |
| 
 | |
| 	int pos = SDL_RWtell (data->rwops);
 | |
| 	int end = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
 | |
| 
 | |
| 	// was the original position equal to the end (a.k.a. the seek didn't move)?
 | |
| 	if (pos == end) {
 | |
| 		// must be EOF
 | |
| 		return true;
 | |
| 	}
 | |
| 	else {
 | |
| 		// not EOF, return to the original position
 | |
| 		SDL_RWseek (data->rwops, pos, RW_SEEK_SET);
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
 | |
| 									const FLAC__StreamDecoder *decoder,
 | |
| 									const FLAC__Frame *frame,
 | |
| 									const FLAC__int32 *const buffer[],
 | |
| 									void *client_data)
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music *)client_data;
 | |
| 	size_t i;
 | |
| 
 | |
| 	if (data->flac_data.total_samples == 0) {
 | |
| 		SDL_SetError ("Given FLAC file does not specify its sample count.");
 | |
| 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | |
| 	}
 | |
| 
 | |
| 	if (data->flac_data.channels != 2 ||
 | |
| 		data->flac_data.bits_per_sample != 16) {
 | |
| 		SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
 | |
| 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < frame->header.blocksize; i++) {
 | |
| 		FLAC__int16 i16;
 | |
| 		FLAC__uint16 ui16;
 | |
| 
 | |
| 		// make sure we still have at least two bytes that can be read (one for
 | |
| 		// each channel)
 | |
| 		if (data->flac_data.max_to_read >= 4) {
 | |
| 			// does the data block exist?
 | |
| 			if (!data->flac_data.data) {
 | |
| 				data->flac_data.data_len = data->flac_data.max_to_read;
 | |
| 				data->flac_data.data_read = 0;
 | |
| 
 | |
| 				// create it
 | |
| 				data->flac_data.data =
 | |
| 					(char *)SDL_malloc (data->flac_data.data_len);
 | |
| 
 | |
| 				if (!data->flac_data.data) {
 | |
| 					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			i16 = (FLAC__int16)buffer[0][i];
 | |
| 			ui16 = (FLAC__uint16)i16;
 | |
| 
 | |
| 			*((data->flac_data.data) + (data->flac_data.data_read++)) =
 | |
| 															(char)(ui16);
 | |
| 			*((data->flac_data.data) + (data->flac_data.data_read++)) =
 | |
| 															(char)(ui16 >> 8);
 | |
| 
 | |
| 			i16 = (FLAC__int16)buffer[1][i];
 | |
| 			ui16 = (FLAC__uint16)i16;
 | |
| 
 | |
| 			*((data->flac_data.data) + (data->flac_data.data_read++)) =
 | |
| 															(char)(ui16);
 | |
| 			*((data->flac_data.data) + (data->flac_data.data_read++)) =
 | |
| 															(char)(ui16 >> 8);
 | |
| 
 | |
| 			data->flac_data.max_to_read -= 4;
 | |
| 
 | |
| 			if (data->flac_data.max_to_read < 4) {
 | |
| 				// we need to set this so that the read halts from the
 | |
| 				// FLAC_getsome function.
 | |
| 				data->flac_data.max_to_read = 0;
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			// we need to write to the overflow
 | |
| 			if (!data->flac_data.overflow) {
 | |
| 				data->flac_data.overflow_len =
 | |
| 											4 * (frame->header.blocksize - i);
 | |
| 				data->flac_data.overflow_read = 0;
 | |
| 
 | |
| 				// make it big enough for the rest of the block
 | |
| 				data->flac_data.overflow =
 | |
| 					(char *)SDL_malloc (data->flac_data.overflow_len);
 | |
| 
 | |
| 				if (!data->flac_data.overflow) {
 | |
| 					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			i16 = (FLAC__int16)buffer[0][i];
 | |
| 			ui16 = (FLAC__uint16)i16;
 | |
| 
 | |
| 			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
 | |
| 															(char)(ui16);
 | |
| 			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
 | |
| 															(char)(ui16 >> 8);
 | |
| 
 | |
| 			i16 = (FLAC__int16)buffer[1][i];
 | |
| 			ui16 = (FLAC__uint16)i16;
 | |
| 
 | |
| 			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
 | |
| 															(char)(ui16);
 | |
| 			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
 | |
| 															(char)(ui16 >> 8);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 | |
| }
 | |
| 
 | |
| static void flac_metadata_music_cb(
 | |
| 					const FLAC__StreamDecoder *decoder,
 | |
| 					const FLAC__StreamMetadata *metadata,
 | |
| 					void *client_data)
 | |
| {
 | |
| 	FLAC_music *data = (FLAC_music *)client_data;
 | |
| 
 | |
| 	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
 | |
| 		data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
 | |
| 		data->flac_data.channels = metadata->data.stream_info.channels;
 | |
| 		data->flac_data.total_samples =
 | |
| 							metadata->data.stream_info.total_samples;
 | |
| 		data->flac_data.bits_per_sample =
 | |
| 							metadata->data.stream_info.bits_per_sample;
 | |
| 		data->flac_data.sample_size = data->flac_data.channels *
 | |
| 										((data->flac_data.bits_per_sample) / 8);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void flac_error_music_cb(
 | |
| 				const FLAC__StreamDecoder *decoder,
 | |
| 				FLAC__StreamDecoderErrorStatus status,
 | |
| 				void *client_data)
 | |
| {
 | |
| 	// print an SDL error based on the error status
 | |
| 	switch (status) {
 | |
| 		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
 | |
| 			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
 | |
| 		break;
 | |
| 		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
 | |
| 			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
 | |
| 		break;
 | |
| 		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
 | |
| 			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
 | |
| 		break;
 | |
| 		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
 | |
| 			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
 | |
| 		break;
 | |
| 		default:
 | |
| 			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Load an FLAC stream from an SDL_RWops object */
 | |
| FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw)
 | |
| {
 | |
| 	FLAC_music *music;
 | |
| 	int init_stage = 0;
 | |
| 	int was_error = 1;
 | |
| 
 | |
| 	if (!Mix_Init(MIX_INIT_FLAC)) {
 | |
| 		if (freerw) {
 | |
| 			SDL_RWclose(rw);
 | |
| 		}
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	music = (FLAC_music *)SDL_malloc ( sizeof (*music));
 | |
| 	if (music) {
 | |
| 		/* Initialize the music structure */
 | |
| 		memset (music, 0, (sizeof (*music)));
 | |
| 		FLAC_stop (music);
 | |
| 		FLAC_setvolume (music, MIX_MAX_VOLUME);
 | |
| 		music->section = -1;
 | |
| 		music->rwops = rw;
 | |
| 		music->freerw = freerw;
 | |
| 		music->flac_data.max_to_read = 0;
 | |
| 		music->flac_data.overflow = NULL;
 | |
| 		music->flac_data.overflow_len = 0;
 | |
| 		music->flac_data.overflow_read = 0;
 | |
| 		music->flac_data.data = NULL;
 | |
| 		music->flac_data.data_len = 0;
 | |
| 		music->flac_data.data_read = 0;
 | |
| 
 | |
| 		init_stage++; // stage 1!
 | |
| 
 | |
| 		music->flac_decoder = flac.FLAC__stream_decoder_new ();
 | |
| 
 | |
| 		if (music->flac_decoder != NULL) {
 | |
| 			init_stage++; // stage 2!
 | |
| 
 | |
| 			if (flac.FLAC__stream_decoder_init_stream(
 | |
| 						music->flac_decoder,
 | |
| 						flac_read_music_cb, flac_seek_music_cb,
 | |
| 						flac_tell_music_cb, flac_length_music_cb,
 | |
| 						flac_eof_music_cb, flac_write_music_cb,
 | |
| 						flac_metadata_music_cb, flac_error_music_cb,
 | |
| 						music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
 | |
| 				init_stage++; // stage 3!
 | |
| 
 | |
| 				if (flac.FLAC__stream_decoder_process_until_end_of_metadata
 | |
| 										(music->flac_decoder)) {
 | |
| 					was_error = 0;
 | |
| 				} else {
 | |
| 					SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
 | |
| 				}
 | |
| 			} else {
 | |
| 				SDL_SetError("FLAC__stream_decoder_init_stream() failed");
 | |
| 			}
 | |
| 		} else {
 | |
| 			SDL_SetError("FLAC__stream_decoder_new() failed");
 | |
| 		}
 | |
| 
 | |
| 		if (was_error) {
 | |
| 			switch (init_stage) {
 | |
| 				case 3:
 | |
| 					flac.FLAC__stream_decoder_finish( music->flac_decoder );
 | |
| 				case 2:
 | |
| 					flac.FLAC__stream_decoder_delete( music->flac_decoder );
 | |
| 				case 1:
 | |
| 				case 0:
 | |
| 					SDL_free(music);
 | |
| 					if (freerw) {
 | |
| 						SDL_RWclose(rw);
 | |
| 					}
 | |
| 					break;
 | |
| 			}
 | |
| 			return NULL;
 | |
| 		}
 | |
| 	} else {
 | |
| 		SDL_OutOfMemory();
 | |
| 		if (freerw) {
 | |
| 			SDL_RWclose(rw);
 | |
| 		}
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	return music;
 | |
| }
 | |
| 
 | |
| /* Start playback of a given FLAC stream */
 | |
| void FLAC_play(FLAC_music *music)
 | |
| {
 | |
| 	music->playing = 1;
 | |
| }
 | |
| 
 | |
| /* Return non-zero if a stream is currently playing */
 | |
| int FLAC_playing(FLAC_music *music)
 | |
| {
 | |
| 	return(music->playing);
 | |
| }
 | |
| 
 | |
| /* Read some FLAC stream data and convert it for output */
 | |
| static void FLAC_getsome(FLAC_music *music)
 | |
| {
 | |
| 	SDL_AudioCVT *cvt;
 | |
| 
 | |
| 	/* GET AUDIO WAVE DATA */
 | |
| 	// set the max number of characters to read
 | |
| 	music->flac_data.max_to_read = 8192;
 | |
| 	music->flac_data.data_len = music->flac_data.max_to_read;
 | |
| 	music->flac_data.data_read = 0;
 | |
| 	if (!music->flac_data.data) {
 | |
| 		music->flac_data.data = (char *)SDL_malloc (music->flac_data.data_len);
 | |
| 	}
 | |
| 
 | |
| 	// we have data to read
 | |
| 	while(music->flac_data.max_to_read > 0) {
 | |
| 		// first check if there is data in the overflow from before
 | |
| 		if (music->flac_data.overflow) {
 | |
| 			size_t overflow_len = music->flac_data.overflow_read;
 | |
| 
 | |
| 			if (overflow_len > music->flac_data.max_to_read) {
 | |
| 				size_t overflow_extra_len = overflow_len -
 | |
| 												music->flac_data.max_to_read;
 | |
| 
 | |
| 				memcpy (music->flac_data.data+music->flac_data.data_read,
 | |
| 					music->flac_data.overflow, music->flac_data.max_to_read);
 | |
| 				music->flac_data.data_read += music->flac_data.max_to_read;
 | |
| 				memcpy (music->flac_data.overflow,
 | |
| 					music->flac_data.overflow + music->flac_data.max_to_read,
 | |
| 					overflow_extra_len);
 | |
| 				music->flac_data.overflow_len = overflow_extra_len;
 | |
| 				music->flac_data.overflow_read = overflow_extra_len;
 | |
| 				music->flac_data.max_to_read = 0;
 | |
| 			}
 | |
| 			else {
 | |
| 				memcpy (music->flac_data.data+music->flac_data.data_read,
 | |
| 					music->flac_data.overflow, overflow_len);
 | |
| 				music->flac_data.data_read += overflow_len;
 | |
| 				free (music->flac_data.overflow);
 | |
| 				music->flac_data.overflow = NULL;
 | |
| 				music->flac_data.overflow_len = 0;
 | |
| 				music->flac_data.overflow_read = 0;
 | |
| 				music->flac_data.max_to_read -= overflow_len;
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			if (!flac.FLAC__stream_decoder_process_single (
 | |
| 														music->flac_decoder)) {
 | |
| 				music->flac_data.max_to_read = 0;
 | |
| 			}
 | |
| 
 | |
| 			if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
 | |
| 									== FLAC__STREAM_DECODER_END_OF_STREAM) {
 | |
| 				music->flac_data.max_to_read = 0;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (music->flac_data.data_read <= 0) {
 | |
| 		if (music->flac_data.data_read == 0) {
 | |
| 			music->playing = 0;
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	cvt = &music->cvt;
 | |
| 	if (music->section < 0) {
 | |
| 
 | |
| 		SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
 | |
| 						(int)music->flac_data.sample_rate, mixer.format,
 | |
| 		                mixer.channels, mixer.freq);
 | |
| 		if (cvt->buf) {
 | |
| 			free (cvt->buf);
 | |
| 		}
 | |
| 		cvt->buf = (Uint8 *)SDL_malloc (music->flac_data.data_len * cvt->len_mult);
 | |
| 		music->section = 0;
 | |
| 	}
 | |
| 	if (cvt->buf) {
 | |
| 		memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
 | |
| 		if (cvt->needed) {
 | |
| 			cvt->len = music->flac_data.data_read;
 | |
| 			SDL_ConvertAudio (cvt);
 | |
| 		}
 | |
| 		else {
 | |
| 			cvt->len_cvt = music->flac_data.data_read;
 | |
| 		}
 | |
| 		music->len_available = music->cvt.len_cvt;
 | |
| 		music->snd_available = music->cvt.buf;
 | |
| 	}
 | |
| 	else {
 | |
| 		SDL_SetError ("Out of memory");
 | |
| 		music->playing = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Play some of a stream previously started with FLAC_play() */
 | |
| int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len)
 | |
| {
 | |
| 	int mixable;
 | |
| 
 | |
| 	while ((len > 0) && music->playing) {
 | |
| 		if (!music->len_available) {
 | |
| 			FLAC_getsome (music);
 | |
| 		}
 | |
| 		mixable = len;
 | |
| 		if (mixable > music->len_available) {
 | |
| 			mixable = music->len_available;
 | |
| 		}
 | |
| 		if (music->volume == MIX_MAX_VOLUME) {
 | |
| 			memcpy (snd, music->snd_available, mixable);
 | |
| 		}
 | |
| 		else {
 | |
| 			SDL_MixAudio (snd, music->snd_available, mixable, music->volume);
 | |
| 		}
 | |
| 		music->len_available -= mixable;
 | |
| 		music->snd_available += mixable;
 | |
| 		len -= mixable;
 | |
| 		snd += mixable;
 | |
| 	}
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| /* Stop playback of a stream previously started with FLAC_play() */
 | |
| void FLAC_stop(FLAC_music *music)
 | |
| {
 | |
| 	music->playing = 0;
 | |
| }
 | |
| 
 | |
| /* Close the given FLAC_music object */
 | |
| void FLAC_delete(FLAC_music *music)
 | |
| {
 | |
| 	if (music) {
 | |
| 		if (music->flac_decoder) {
 | |
| 			flac.FLAC__stream_decoder_finish (music->flac_decoder);
 | |
| 			flac.FLAC__stream_decoder_delete (music->flac_decoder);
 | |
| 		}
 | |
| 
 | |
| 		if (music->flac_data.data) {
 | |
| 			free (music->flac_data.data);
 | |
| 		}
 | |
| 
 | |
| 		if (music->flac_data.overflow) {
 | |
| 			free (music->flac_data.overflow);
 | |
| 		}
 | |
| 
 | |
| 		if (music->cvt.buf) {
 | |
| 			free (music->cvt.buf);
 | |
| 		}
 | |
| 
 | |
| 		if (music->freerw) {
 | |
| 			SDL_RWclose(music->rwops);
 | |
| 		}
 | |
| 		free (music);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Jump (seek) to a given position (time is in seconds) */
 | |
| void FLAC_jump_to_time(FLAC_music *music, double time)
 | |
| {
 | |
| 	if (music) {
 | |
| 		if (music->flac_decoder) {
 | |
| 			double seek_sample = music->flac_data.sample_rate * time;
 | |
| 
 | |
| 			// clear data if it has data
 | |
| 			if (music->flac_data.data) {
 | |
| 				free (music->flac_data.data);
 | |
| 				music->flac_data.data = NULL;
 | |
| 			}
 | |
| 
 | |
| 			// clear overflow if it has data
 | |
| 			if (music->flac_data.overflow) {
 | |
| 				free (music->flac_data.overflow);
 | |
| 				music->flac_data.overflow = NULL;
 | |
| 			}
 | |
| 
 | |
| 			if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
 | |
| 												(FLAC__uint64)seek_sample)) {
 | |
| 				if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
 | |
| 										== FLAC__STREAM_DECODER_SEEK_ERROR) {
 | |
| 					flac.FLAC__stream_decoder_flush (music->flac_decoder);
 | |
| 				}
 | |
| 
 | |
| 				SDL_SetError
 | |
| 					("Seeking of FLAC stream failed: libFLAC seek failed.");
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			SDL_SetError
 | |
| 				("Seeking of FLAC stream failed: FLAC decoder was NULL.");
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #endif /* FLAC_MUSIC */
 |