Austen Dicken - Tue Feb 26 23:28:27 PST 2008
authorSam Lantinga <slouken@libsdl.org>
Wed, 27 Feb 2008 07:31:03 +0000
changeset 38250501e45c57b
parent 381 2064088ea781
child 383 0d05ac848d6a
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!
CHANGES
SDL_mixer.h
configure.in
dynamic_flac.c
dynamic_flac.h
load_flac.c
load_flac.h
mixer.c
music.c
music_flac.c
music_flac.h
     1.1 --- a/CHANGES	Tue Feb 26 11:46:22 2008 +0000
     1.2 +++ b/CHANGES	Wed Feb 27 07:31:03 2008 +0000
     1.3 @@ -1,4 +1,6 @@
     1.4  1.2.9:
     1.5 +Austen Dicken - Tue Feb 26 23:28:27 PST 2008
     1.6 + * Added support for FLAC audio both as chunks and streaming
     1.7  Tilman Sauerbeck - Tue Feb 26 03:44:47 PST 2008
     1.8   * Added support for streaming WAV files with Mix_LoadMUS_RW()
     1.9  
     2.1 --- a/SDL_mixer.h	Tue Feb 26 11:46:22 2008 +0000
     2.2 +++ b/SDL_mixer.h	Wed Feb 27 07:31:03 2008 +0000
     2.3 @@ -103,6 +103,7 @@
     2.4  	MUS_MOD,
     2.5  	MUS_MID,
     2.6  	MUS_OGG,
     2.7 +	MUS_FLAC,
     2.8  	MUS_MP3,
     2.9  	MUS_MP3_MAD
    2.10  } Mix_MusicType;
     3.1 --- a/configure.in	Tue Feb 26 11:46:22 2008 +0000
     3.2 +++ b/configure.in	Wed Feb 27 07:31:03 2008 +0000
     3.3 @@ -318,6 +318,41 @@
     3.4          fi
     3.5      fi
     3.6  fi
     3.7 +AC_ARG_ENABLE([music-flac],
     3.8 +AC_HELP_STRING([--enable-music-flac], [enable FLAC music [[default=yes]]]),
     3.9 +              [], [enable_music_flac=yes])
    3.10 +AC_ARG_ENABLE([music-flac-shared],
    3.11 +AC_HELP_STRING([--enable-music-flac-shared],
    3.12 +              [dynamically load FLAC support [[default=yes]]]),
    3.13 +              [], [enable_music_flac_shared=yes])
    3.14 +if test x$enable_music_flac = xyes; then
    3.15 +    AC_CHECK_HEADER([FLAC/stream_decoder.h], [have_flac_hdr=yes])
    3.16 +    AC_CHECK_LIB([FLAC], [FLAC__stream_decoder_new], [have_flac_lib=yes])
    3.17 +    if test x$have_flac_hdr = xyes -a x$have_flac_lib = xyes; then
    3.18 +        case "$host" in
    3.19 +            *-*-darwin*)
    3.20 +                flac_lib=[`find_lib FLAC*.dylib`]
    3.21 +                ;;
    3.22 +            *-*-cygwin* | *-*-mingw32*)
    3.23 +                flac_lib=[`find_lib "libFLAC*.dll"`]
    3.24 +                ;;
    3.25 +            *)
    3.26 +                flac_lib=[`find_lib "libFLAC.so.[0-9]"`]
    3.27 +                if test x$flac_lib = x; then
    3.28 +                    flac_lib=[`find_lib "libFLAC.so.[0-9]*"`]
    3.29 +                fi
    3.30 +                ;;
    3.31 +        esac
    3.32 +        SOURCES="$SOURCES $srcdir/*_flac.c"
    3.33 +        EXTRA_CFLAGS="$EXTRA_CFLAGS -DFLAC_MUSIC"
    3.34 +        if test x$enable_music_flac_shared = xyes && test x$flac_lib != x; then
    3.35 +            echo "-- dynamic libFLAC -> $flac_lib"
    3.36 +            EXTRA_CFLAGS="$EXTRA_CFLAGS -DFLAC_DYNAMIC=\\\"$flac_lib\\\""
    3.37 +        else
    3.38 +            EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lFLAC"
    3.39 +        fi
    3.40 +    fi
    3.41 +fi
    3.42  AC_ARG_ENABLE(music-mp3,
    3.43  [  --enable-music-mp3      enable MP3 music via smpeg [[default=yes]]],
    3.44                , enable_music_mp3=yes)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/dynamic_flac.c	Wed Feb 27 07:31:03 2008 +0000
     4.3 @@ -0,0 +1,176 @@
     4.4 +/*
     4.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     4.6 +    Copyright (C) 1997-2004 Sam Lantinga
     4.7 +
     4.8 +    This library is free software; you can redistribute it and/or
     4.9 +    modify it under the terms of the GNU Library General Public
    4.10 +    License as published by the Free Software Foundation; either
    4.11 +    version 2 of the License, or (at your option) any later version.
    4.12 +
    4.13 +    This library is distributed in the hope that it will be useful,
    4.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    4.16 +    Library General Public License for more details.
    4.17 +
    4.18 +    You should have received a copy of the GNU Library General Public
    4.19 +    License along with this library; if not, write to the Free
    4.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.21 +
    4.22 +    Sam Lantinga
    4.23 +    slouken@libsdl.org
    4.24 +
    4.25 +
    4.26 +    Implementation of the dynamic loading functionality for libFLAC.
    4.27 +    									~ Austen Dicken (admin@cvpcs.org)
    4.28 +*/
    4.29 +
    4.30 +#ifdef FLAC_MUSIC
    4.31 +
    4.32 +#include "SDL_loadso.h"
    4.33 +
    4.34 +#include "dynamic_flac.h"
    4.35 +
    4.36 +flac_loader flac = {
    4.37 +	0, NULL
    4.38 +};
    4.39 +
    4.40 +#ifdef FLAC_DYNAMIC
    4.41 +
    4.42 +int Mix_InitFLAC() {
    4.43 +	if ( flac.loaded == 0 ) {
    4.44 +		flac.handle = SDL_LoadObject(FLAC_DYNAMIC);
    4.45 +		if ( flac.handle == NULL ) {
    4.46 +			return -1;
    4.47 +		}
    4.48 +		flac.FLAC__stream_decoder_new =
    4.49 +			(FLAC__StreamDecoder *(*)())
    4.50 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_new");
    4.51 +		if ( flac.FLAC__stream_decoder_new == NULL ) {
    4.52 +			SDL_UnloadObject(flac.handle);
    4.53 +			return -1;
    4.54 +		}
    4.55 +		flac.FLAC__stream_decoder_delete =
    4.56 +			(void (*)(FLAC__StreamDecoder *))
    4.57 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_delete");
    4.58 +		if ( flac.FLAC__stream_decoder_delete == NULL ) {
    4.59 +			SDL_UnloadObject(flac.handle);
    4.60 +			return -1;
    4.61 +		}
    4.62 +		flac.FLAC__stream_decoder_init_stream =
    4.63 +			(FLAC__StreamDecoderInitStatus (*)(
    4.64 +						FLAC__StreamDecoder *,
    4.65 +						FLAC__StreamDecoderReadCallback,
    4.66 +						FLAC__StreamDecoderSeekCallback,
    4.67 +						FLAC__StreamDecoderTellCallback,
    4.68 +						FLAC__StreamDecoderLengthCallback,
    4.69 +						FLAC__StreamDecoderEofCallback,
    4.70 +						FLAC__StreamDecoderWriteCallback,
    4.71 +						FLAC__StreamDecoderMetadataCallback,
    4.72 +						FLAC__StreamDecoderErrorCallback,
    4.73 +						void *))
    4.74 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_init_stream");
    4.75 +		if ( flac.FLAC__stream_decoder_init_stream == NULL ) {
    4.76 +			SDL_UnloadObject(flac.handle);
    4.77 +			return -1;
    4.78 +		}
    4.79 +		flac.FLAC__stream_decoder_finish =
    4.80 +			(FLAC__bool (*)(FLAC__StreamDecoder *))
    4.81 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_finish");
    4.82 +		if ( flac.FLAC__stream_decoder_finish == NULL ) {
    4.83 +			SDL_UnloadObject(flac.handle);
    4.84 +			return -1;
    4.85 +		}
    4.86 +		flac.FLAC__stream_decoder_flush =
    4.87 +			(FLAC__bool (*)(FLAC__StreamDecoder *))
    4.88 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_flush");
    4.89 +		if ( flac.FLAC__stream_decoder_flush == NULL ) {
    4.90 +			SDL_UnloadObject(flac.handle);
    4.91 +			return -1;
    4.92 +		}
    4.93 +		flac.FLAC__stream_decoder_process_single =
    4.94 +			(FLAC__bool (*)(FLAC__StreamDecoder *))
    4.95 +			SDL_LoadFunction(flac.handle,
    4.96 +						"FLAC__stream_decoder_process_single");
    4.97 +		if ( flac.FLAC__stream_decoder_process_single == NULL ) {
    4.98 +			SDL_UnloadObject(flac.handle);
    4.99 +			return -1;
   4.100 +		}
   4.101 +		flac.FLAC__stream_decoder_process_until_end_of_metadata =
   4.102 +			(FLAC__bool (*)(FLAC__StreamDecoder *))
   4.103 +			SDL_LoadFunction(flac.handle,
   4.104 +						"FLAC__stream_decoder_process_until_end_of_metadata");
   4.105 +		if ( flac.FLAC__stream_decoder_process_until_end_of_metadata == NULL ) {
   4.106 +			SDL_UnloadObject(flac.handle);
   4.107 +			return -1;
   4.108 +		}
   4.109 +		flac.FLAC__stream_decoder_process_until_end_of_stream =
   4.110 +			(FLAC__bool (*)(FLAC__StreamDecoder *))
   4.111 +			SDL_LoadFunction(flac.handle,
   4.112 +						"FLAC__stream_decoder_process_until_end_of_stream");
   4.113 +		if ( flac.FLAC__stream_decoder_process_until_end_of_stream == NULL ) {
   4.114 +			SDL_UnloadObject(flac.handle);
   4.115 +			return -1;
   4.116 +		}
   4.117 +		flac.FLAC__stream_decoder_seek_absolute =
   4.118 +			(FLAC__bool (*)(FLAC__StreamDecoder *, FLAC__uint64))
   4.119 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_seek_absolute");
   4.120 +		if ( flac.FLAC__stream_decoder_seek_absolute == NULL ) {
   4.121 +			SDL_UnloadObject(flac.handle);
   4.122 +			return -1;
   4.123 +		}
   4.124 +		flac.FLAC__stream_decoder_get_state =
   4.125 +			(FLAC__StreamDecoderState (*)(const FLAC__StreamDecoder *decoder))
   4.126 +			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_get_state");
   4.127 +		if ( flac.FLAC__stream_decoder_get_state == NULL ) {
   4.128 +			SDL_UnloadObject(flac.handle);
   4.129 +			return -1;
   4.130 +		}
   4.131 +	}
   4.132 +	++flac.loaded;
   4.133 +
   4.134 +	return 0;
   4.135 +}
   4.136 +void Mix_QuitFLAC() {
   4.137 +	if ( flac.loaded == 0 ) {
   4.138 +		return;
   4.139 +	}
   4.140 +	if ( flac.loaded == 1 ) {
   4.141 +		SDL_UnloadObject(flac.handle);
   4.142 +	}
   4.143 +	--flac.loaded;
   4.144 +}
   4.145 +#else
   4.146 +int Mix_InitFLAC() {
   4.147 +	if ( flac.loaded == 0 ) {
   4.148 +		flac.FLAC__stream_decoder_new = FLAC__stream_decoder_new;
   4.149 +		flac.FLAC__stream_decoder_delete = FLAC__stream_decoder_delete;
   4.150 +		flac.FLAC__stream_decoder_init_stream =
   4.151 +							FLAC__stream_decoder_init_stream;
   4.152 +		flac.FLAC__stream_decoder_finish = FLAC__stream_decoder_finish;
   4.153 +		flac.FLAC__stream_decoder_flush = FLAC__stream_decoder_flush;
   4.154 +		flac.FLAC__stream_decoder_process_single =
   4.155 +							FLAC__stream_decoder_process_single;
   4.156 +		flac.FLAC__stream_decoder_process_until_end_of_metadata =
   4.157 +							FLAC__stream_decoder_process_until_end_of_metadata;
   4.158 +		flac.FLAC__stream_decoder_process_until_end_of_stream =
   4.159 +							FLAC__stream_decoder_process_until_end_of_stream;
   4.160 +		flac.FLAC__stream_decoder_seek_absolute =
   4.161 +							FLAC__stream_decoder_seek_absolute;
   4.162 +		flac.FLAC__stream_decoder_get_state =
   4.163 +							FLAC__stream_decoder_get_state;
   4.164 +	}
   4.165 +	++flac.loaded;
   4.166 +
   4.167 +	return 0;
   4.168 +}
   4.169 +void Mix_QuitFLAC() {
   4.170 +	if ( flac.loaded == 0 ) {
   4.171 +		return;
   4.172 +	}
   4.173 +	if ( flac.loaded == 1 ) {
   4.174 +	}
   4.175 +	--flac.loaded;
   4.176 +}
   4.177 +#endif // FLAC_DYNAMIC
   4.178 +
   4.179 +#endif // FLAC_MUSIC
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/dynamic_flac.h	Wed Feb 27 07:31:03 2008 +0000
     5.3 @@ -0,0 +1,68 @@
     5.4 +/*
     5.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     5.6 +    Copyright (C) 1997-2004 Sam Lantinga
     5.7 +
     5.8 +    This library is free software; you can redistribute it and/or
     5.9 +    modify it under the terms of the GNU Library General Public
    5.10 +    License as published by the Free Software Foundation; either
    5.11 +    version 2 of the License, or (at your option) any later version.
    5.12 +
    5.13 +    This library is distributed in the hope that it will be useful,
    5.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5.16 +    Library General Public License for more details.
    5.17 +
    5.18 +    You should have received a copy of the GNU Library General Public
    5.19 +    License along with this library; if not, write to the Free
    5.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    5.21 +
    5.22 +    Sam Lantinga
    5.23 +    slouken@libsdl.org
    5.24 +
    5.25 +
    5.26 +    The following file defines all of the functions/objects used to dynamically
    5.27 +    link to the libFLAC library.
    5.28 +    										~ Austen Dicken (admin@cvpcs.org)
    5.29 +*/
    5.30 +
    5.31 +#ifdef FLAC_MUSIC
    5.32 +
    5.33 +#include <FLAC/stream_decoder.h>
    5.34 +
    5.35 +typedef struct {
    5.36 +	int loaded;
    5.37 +	void *handle;
    5.38 +	FLAC__StreamDecoder *(*FLAC__stream_decoder_new)();
    5.39 +	void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder);
    5.40 +	FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)(
    5.41 +						FLAC__StreamDecoder *decoder,
    5.42 +						FLAC__StreamDecoderReadCallback read_callback,
    5.43 +						FLAC__StreamDecoderSeekCallback seek_callback,
    5.44 +						FLAC__StreamDecoderTellCallback tell_callback,
    5.45 +						FLAC__StreamDecoderLengthCallback length_callback,
    5.46 +						FLAC__StreamDecoderEofCallback eof_callback,
    5.47 +						FLAC__StreamDecoderWriteCallback write_callback,
    5.48 +						FLAC__StreamDecoderMetadataCallback metadata_callback,
    5.49 +						FLAC__StreamDecoderErrorCallback error_callback,
    5.50 +						void *client_data);
    5.51 +	FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder);
    5.52 +	FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder);
    5.53 +	FLAC__bool (*FLAC__stream_decoder_process_single)(
    5.54 +						FLAC__StreamDecoder *decoder);
    5.55 +	FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(
    5.56 +						FLAC__StreamDecoder *decoder);
    5.57 +	FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(
    5.58 +						FLAC__StreamDecoder *decoder);
    5.59 +	FLAC__bool (*FLAC__stream_decoder_seek_absolute)(
    5.60 +						FLAC__StreamDecoder *decoder,
    5.61 +						FLAC__uint64 sample);
    5.62 +	FLAC__StreamDecoderState (*FLAC__stream_decoder_get_state)(
    5.63 +						const FLAC__StreamDecoder *decoder);
    5.64 +} flac_loader;
    5.65 +
    5.66 +extern flac_loader flac;
    5.67 +
    5.68 +extern int Mix_InitFLAC();
    5.69 +extern void Mix_QuitFLAC();
    5.70 +
    5.71 +#endif // FLAC_MUSIC
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/load_flac.c	Wed Feb 27 07:31:03 2008 +0000
     6.3 @@ -0,0 +1,332 @@
     6.4 +/*
     6.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     6.6 +    Copyright (C) 1997-2004 Sam Lantinga
     6.7 +
     6.8 +    This library is free software; you can redistribute it and/or
     6.9 +    modify it under the terms of the GNU Library General Public
    6.10 +    License as published by the Free Software Foundation; either
    6.11 +    version 2 of the License, or (at your option) any later version.
    6.12 +
    6.13 +    This library is distributed in the hope that it will be useful,
    6.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    6.16 +    Library General Public License for more details.
    6.17 +
    6.18 +    You should have received a copy of the GNU Library General Public
    6.19 +    License along with this library; if not, write to the Free
    6.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    6.21 +
    6.22 +    This is the source needed to decode a FLAC into a waveform.
    6.23 +    										~ Austen Dicken (admin@cvpcs.org).
    6.24 +*/
    6.25 +
    6.26 +#ifdef FLAC_MUSIC
    6.27 +
    6.28 +#include <stdio.h>
    6.29 +#include <stdlib.h>
    6.30 +#include <string.h>
    6.31 +
    6.32 +#include "SDL_mutex.h"
    6.33 +#include "SDL_endian.h"
    6.34 +#include "SDL_timer.h"
    6.35 +
    6.36 +#include "SDL_mixer.h"
    6.37 +#include "dynamic_flac.h"
    6.38 +#include "load_flac.h"
    6.39 +
    6.40 +#include <FLAC/stream_decoder.h>
    6.41 +
    6.42 +typedef struct {
    6.43 +	SDL_RWops* sdl_src;
    6.44 +	SDL_AudioSpec* sdl_spec;
    6.45 +	Uint8** sdl_audio_buf;
    6.46 +	Uint32* sdl_audio_len;
    6.47 +	int sdl_audio_read;
    6.48 +	FLAC__uint64 flac_total_samples;
    6.49 +	unsigned flac_bps;
    6.50 +} FLAC_SDL_Data;
    6.51 +
    6.52 +static FLAC__StreamDecoderReadStatus flac_read_load_cb(
    6.53 +									const FLAC__StreamDecoder *decoder,
    6.54 +									FLAC__byte buffer[],
    6.55 +									size_t *bytes,
    6.56 +									void *client_data) {
    6.57 +	// make sure there is something to be reading
    6.58 +	if (*bytes > 0) {
    6.59 +		FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    6.60 +
    6.61 +		*bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
    6.62 +								*bytes);
    6.63 +
    6.64 +		if(*bytes < 0) { // error in read
    6.65 +			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    6.66 +		}
    6.67 +		else if(*bytes == 0) { // no data was read (EOF)
    6.68 +			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    6.69 +		}
    6.70 +		else { // data was read, continue
    6.71 +			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    6.72 +		}
    6.73 +	}
    6.74 +	else {
    6.75 +		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    6.76 +	}
    6.77 +}
    6.78 +
    6.79 +static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
    6.80 +									const FLAC__StreamDecoder *decoder,
    6.81 +									FLAC__uint64 absolute_byte_offset,
    6.82 +									void *client_data) {
    6.83 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    6.84 +
    6.85 +	if (SDL_RWseek (data->sdl_src, absolute_byte_offset, SEEK_SET) < 0) {
    6.86 +		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    6.87 +	}
    6.88 +	else {
    6.89 +		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    6.90 +	}
    6.91 +}
    6.92 +
    6.93 +static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    6.94 +									const FLAC__StreamDecoder *decoder,
    6.95 +									FLAC__uint64 *absolute_byte_offset,
    6.96 +									void *client_data) {
    6.97 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    6.98 +
    6.99 +	int pos = SDL_RWtell (data->sdl_src);
   6.100 +
   6.101 +	if (pos < 0) {
   6.102 +		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   6.103 +	}
   6.104 +	else {
   6.105 +		*absolute_byte_offset = (FLAC__uint64)pos;
   6.106 +		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   6.107 +	}
   6.108 +}
   6.109 +
   6.110 +static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   6.111 +									const FLAC__StreamDecoder *decoder,
   6.112 +									FLAC__uint64 *stream_length,
   6.113 +									void *client_data) {
   6.114 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   6.115 +
   6.116 +	int pos = SDL_RWtell (data->sdl_src);
   6.117 +	int length = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   6.118 +
   6.119 +	if (SDL_RWseek (data->sdl_src, pos, SEEK_SET) != pos || length < 0) {
   6.120 +		/* there was an error attempting to return the stream to the original
   6.121 +		 * position, or the length was invalid. */
   6.122 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   6.123 +	}
   6.124 +	else {
   6.125 +		*stream_length = (FLAC__uint64)length;
   6.126 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   6.127 +	}
   6.128 +}
   6.129 +
   6.130 +static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   6.131 +									void *client_data) {
   6.132 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   6.133 +
   6.134 +	int pos = SDL_RWtell (data->sdl_src);
   6.135 +	int end = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   6.136 +
   6.137 +	// was the original position equal to the end (a.k.a. the seek didn't move)?
   6.138 +	if (pos == end) {
   6.139 +		// must be EOF
   6.140 +		return true;
   6.141 +	}
   6.142 +	else {
   6.143 +		// not EOF, return to the original position
   6.144 +		SDL_RWseek (data->sdl_src, pos, SEEK_SET);
   6.145 +
   6.146 +		return false;
   6.147 +	}
   6.148 +}
   6.149 +
   6.150 +static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   6.151 +									const FLAC__StreamDecoder *decoder,
   6.152 +									const FLAC__Frame *frame,
   6.153 +									const FLAC__int32 *const buffer[],
   6.154 +									void *client_data) {
   6.155 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   6.156 +	size_t i;
   6.157 +
   6.158 +	if (data->flac_total_samples == 0) {
   6.159 +		SDL_SetError ("Given FLAC file does not specify its sample count.");
   6.160 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   6.161 +	}
   6.162 +
   6.163 +	if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   6.164 +		SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   6.165 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   6.166 +	}
   6.167 +
   6.168 +	// check if it is the first audio frame so we can initialize the output
   6.169 +	// buffer
   6.170 +	if (frame->header.number.sample_number == 0) {
   6.171 +		*(data->sdl_audio_len) = data->sdl_spec->size;
   6.172 +		data->sdl_audio_read = 0;
   6.173 +    	*(data->sdl_audio_buf) = malloc (*(data->sdl_audio_len));
   6.174 +
   6.175 +    	if (*(data->sdl_audio_buf) == NULL) {
   6.176 +    		SDL_SetError
   6.177 +					("Unable to allocate memory to store the FLAC stream.");
   6.178 +    		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   6.179 +    	}
   6.180 +	}
   6.181 +
   6.182 +	Uint8 *buf = *(data->sdl_audio_buf);
   6.183 +
   6.184 +	for (i = 0; i < frame->header.blocksize; i++) {
   6.185 +		FLAC__int16 i16;
   6.186 +		FLAC__uint16 ui16;
   6.187 +
   6.188 +		i16 = (FLAC__int16)buffer[0][i];
   6.189 +		ui16 = (FLAC__uint16)i16;
   6.190 +
   6.191 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   6.192 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   6.193 +
   6.194 +		i16 = (FLAC__int16)buffer[1][i];
   6.195 +		ui16 = (FLAC__uint16)i16;
   6.196 +
   6.197 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   6.198 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   6.199 +	}
   6.200 +
   6.201 +	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   6.202 +}
   6.203 +
   6.204 +static void flac_metadata_load_cb(
   6.205 +					const FLAC__StreamDecoder *decoder,
   6.206 +					const FLAC__StreamMetadata *metadata,
   6.207 +					void *client_data) {
   6.208 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   6.209 +	FLAC__uint64 total_samples;
   6.210 +	unsigned bps;
   6.211 +
   6.212 +	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   6.213 +		// save the metadata right now for use later on
   6.214 +		*(data->sdl_audio_buf) = NULL;
   6.215 +		*(data->sdl_audio_len) = 0;
   6.216 +		memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
   6.217 +
   6.218 +		data->sdl_spec->format = AUDIO_S16;
   6.219 +		data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
   6.220 +		data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
   6.221 +		data->sdl_spec->samples = 8192; /* buffer size */
   6.222 +
   6.223 +		total_samples = metadata->data.stream_info.total_samples;
   6.224 +		bps = metadata->data.stream_info.bits_per_sample;
   6.225 +
   6.226 +		data->sdl_spec->size = total_samples * data->sdl_spec->channels *
   6.227 +								(bps / 8);
   6.228 +		data->flac_total_samples = total_samples;
   6.229 +		data->flac_bps = bps;
   6.230 +	}
   6.231 +}
   6.232 +
   6.233 +static void flac_error_load_cb(
   6.234 +				const FLAC__StreamDecoder *decoder,
   6.235 +				FLAC__StreamDecoderErrorStatus status,
   6.236 +				void *client_data) {
   6.237 +	// print an SDL error based on the error status
   6.238 +	switch (status) {
   6.239 +		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   6.240 +			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
   6.241 +		break;
   6.242 +		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   6.243 +			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
   6.244 +		break;
   6.245 +		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   6.246 +			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
   6.247 +		break;
   6.248 +		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   6.249 +			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
   6.250 +		break;
   6.251 +		default:
   6.252 +			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
   6.253 +		break;
   6.254 +	}
   6.255 +}
   6.256 +
   6.257 +/* don't call this directly; use Mix_LoadWAV_RW() for now. */
   6.258 +SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
   6.259 +        SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) {
   6.260 +	FLAC__StreamDecoder *decoder = 0;
   6.261 +	FLAC__StreamDecoderInitStatus init_status;
   6.262 +	int was_error = 1;
   6.263 +	int was_init = 0;
   6.264 +	Uint32 samplesize;
   6.265 +
   6.266 +	// create the client data passing information
   6.267 +	FLAC_SDL_Data* client_data;
   6.268 +	client_data = (FLAC_SDL_Data *)malloc (sizeof (FLAC_SDL_Data));
   6.269 +
   6.270 +    if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   6.271 +        goto done;
   6.272 +
   6.273 +    if (Mix_InitFLAC() < 0)
   6.274 +        goto done;
   6.275 +
   6.276 +	if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   6.277 +		SDL_SetError ("Unable to allocate FLAC decoder.");
   6.278 +		goto done;
   6.279 +	}
   6.280 +
   6.281 +	init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   6.282 +								flac_read_load_cb, flac_seek_load_cb,
   6.283 +								flac_tell_load_cb, flac_length_load_cb,
   6.284 +								flac_eof_load_cb, flac_write_load_cb,
   6.285 +								flac_metadata_load_cb, flac_error_load_cb,
   6.286 +								client_data);
   6.287 +
   6.288 +	if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   6.289 +		SDL_SetError ("Unable to initialize FLAC stream decoder.");
   6.290 +		goto done;
   6.291 +	}
   6.292 +
   6.293 +	was_init = 1;
   6.294 +
   6.295 +	client_data->sdl_src = src;
   6.296 +	client_data->sdl_spec = spec;
   6.297 +	client_data->sdl_audio_buf = audio_buf;
   6.298 +	client_data->sdl_audio_len = audio_len;
   6.299 +
   6.300 +	if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   6.301 +		SDL_SetError ("Unable to process FLAC file.");
   6.302 +		goto done;
   6.303 +	}
   6.304 +
   6.305 +	was_error = 0;
   6.306 +
   6.307 +    /* Don't return a buffer that isn't a multiple of samplesize */
   6.308 +    samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   6.309 +    *audio_len &= ~(samplesize - 1);
   6.310 +
   6.311 +done:
   6.312 +	if(was_init && decoder) {
   6.313 +		flac.FLAC__stream_decoder_finish (decoder);
   6.314 +	}
   6.315 +
   6.316 +	if(decoder) {
   6.317 +		flac.FLAC__stream_decoder_delete (decoder);
   6.318 +	}
   6.319 +
   6.320 +    if (src) {
   6.321 +        if (freesrc)
   6.322 +            SDL_RWclose (src);
   6.323 +        else
   6.324 +            SDL_RWseek (src, 0, SEEK_SET);
   6.325 +    }
   6.326 +
   6.327 +    if (was_error)
   6.328 +        spec = NULL;
   6.329 +
   6.330 +    Mix_QuitFLAC ();
   6.331 +
   6.332 +    return spec;
   6.333 +}
   6.334 +
   6.335 +#endif // FLAC_MUSIC
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/load_flac.h	Wed Feb 27 07:31:03 2008 +0000
     7.3 @@ -0,0 +1,29 @@
     7.4 +/*
     7.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     7.6 +    Copyright (C) 1997-2004 Sam Lantinga
     7.7 +
     7.8 +    This library is free software; you can redistribute it and/or
     7.9 +    modify it under the terms of the GNU Library General Public
    7.10 +    License as published by the Free Software Foundation; either
    7.11 +    version 2 of the License, or (at your option) any later version.
    7.12 +
    7.13 +    This library is distributed in the hope that it will be useful,
    7.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    7.16 +    Library General Public License for more details.
    7.17 +
    7.18 +    You should have received a copy of the GNU Library General Public
    7.19 +    License along with this library; if not, write to the Free
    7.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    7.21 +
    7.22 +    This is the source needed to decode a FLAC into a waveform.
    7.23 +    									~ Austen Dicken (admin@cvpcs.org).
    7.24 +*/
    7.25 +
    7.26 +/* $Id: $ */
    7.27 +
    7.28 +#ifdef FLAC_MUSIC
    7.29 +/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
    7.30 +SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
    7.31 +		SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
    7.32 +#endif
     8.1 --- a/mixer.c	Tue Feb 26 11:46:22 2008 +0000
     8.2 +++ b/mixer.c	Wed Feb 27 07:31:03 2008 +0000
     8.3 @@ -34,6 +34,7 @@
     8.4  #include "load_aiff.h"
     8.5  #include "load_voc.h"
     8.6  #include "load_ogg.h"
     8.7 +#include "load_flac.h"
     8.8  
     8.9  #define __MIX_INTERNAL_EFFECT__
    8.10  #include "effects_internal.h"
    8.11 @@ -43,7 +44,8 @@
    8.12  #define WAVE		0x45564157		/* "WAVE" */
    8.13  #define FORM		0x4d524f46		/* "FORM" */
    8.14  #define OGGS		0x5367674f		/* "OggS" */
    8.15 -#define CREA	    	0x61657243		/* "Crea" */
    8.16 +#define CREA		0x61657243		/* "Crea" */
    8.17 +#define FLAC		0x43614C66		/* "fLaC" */
    8.18  
    8.19  static int audio_opened = 0;
    8.20  static SDL_AudioSpec mixer;
    8.21 @@ -455,6 +457,12 @@
    8.22  					(Uint8 **)&chunk->abuf, &chunk->alen);
    8.23  			break;
    8.24  #endif
    8.25 +#ifdef FLAC_MUSIC
    8.26 +		case FLAC:
    8.27 +			loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
    8.28 +					(Uint8 **)&chunk->abuf, &chunk->alen);
    8.29 +			break;
    8.30 +#endif
    8.31  		case CREA:
    8.32  			loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
    8.33  					(Uint8 **)&chunk->abuf, &chunk->alen);
     9.1 --- a/music.c	Tue Feb 26 11:46:22 2008 +0000
     9.2 +++ b/music.c	Wed Feb 27 07:31:03 2008 +0000
     9.3 @@ -89,6 +89,9 @@
     9.4  #ifdef MP3_MAD_MUSIC
     9.5  #include "music_mad.h"
     9.6  #endif
     9.7 +#ifdef FLAC_MUSIC
     9.8 +#include "music_flac.h"
     9.9 +#endif
    9.10  
    9.11  #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    9.12  static SDL_AudioSpec used_mixer;
    9.13 @@ -133,6 +136,9 @@
    9.14  #ifdef MP3_MAD_MUSIC
    9.15  		mad_data *mp3_mad;
    9.16  #endif
    9.17 +#ifdef FLAC_MUSIC
    9.18 +		FLAC_music *flac;
    9.19 +#endif
    9.20  	} data;
    9.21  	Mix_Fading fading;
    9.22  	int fade_step;
    9.23 @@ -345,6 +351,13 @@
    9.24  			
    9.25  				break;
    9.26  #endif
    9.27 +#ifdef FLAC_MUSIC
    9.28 +			case MUS_FLAC:
    9.29 +				len = FLAC_playAudio(music_playing->data.flac, stream, len);
    9.30 +				if (len > 0 && music_halt_or_loop())
    9.31 +					FLAC_playAudio(music_playing->data.flac, stream, len);
    9.32 +				break;
    9.33 +#endif
    9.34  #ifdef MP3_MUSIC
    9.35  			case MUS_MP3:
    9.36  				smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len);
    9.37 @@ -469,6 +482,11 @@
    9.38  		++music_error;
    9.39  	}
    9.40  #endif
    9.41 +#ifdef FLAC_MUSIC
    9.42 +	if ( FLAC_init(mixer) < 0 ) {
    9.43 +		++music_error;
    9.44 +	}
    9.45 +#endif
    9.46  #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    9.47  	/* Keep a copy of the mixer */
    9.48  	used_mixer = *mixer;
    9.49 @@ -602,6 +620,17 @@
    9.50  		}
    9.51  	} else
    9.52  #endif
    9.53 +#ifdef FLAC_MUSIC
    9.54 +	/* FLAC files have the magic four bytes "fLaC" */
    9.55 +	if ( (ext && MIX_string_equals(ext, "FLAC")) ||
    9.56 +		 strcmp((char *)magic, "fLaC") == 0 ) {
    9.57 +		music->type = MUS_FLAC;
    9.58 +		music->data.flac = FLAC_new(file);
    9.59 +		if ( music->data.flac == NULL ) {
    9.60 +			music->error = 1;
    9.61 +		}
    9.62 +	} else
    9.63 +#endif
    9.64  #ifdef MP3_MUSIC
    9.65  	if ( (ext && MIX_string_equals(ext, "MPG")) ||
    9.66  	     (ext && MIX_string_equals(ext, "MP3")) ||
    9.67 @@ -720,6 +749,11 @@
    9.68  				OGG_delete(music->data.ogg);
    9.69  				break;
    9.70  #endif
    9.71 +#ifdef FLAC_MUSIC
    9.72 +			case MUS_FLAC:
    9.73 +				FLAC_delete(music->data.flac);
    9.74 +				break;
    9.75 +#endif
    9.76  #ifdef MP3_MUSIC
    9.77  			case MUS_MP3:
    9.78  				smpeg.SMPEG_delete(music->data.mp3);
    9.79 @@ -813,6 +847,11 @@
    9.80  		OGG_play(music->data.ogg);
    9.81  		break;
    9.82  #endif
    9.83 +#ifdef FLAC_MUSIC
    9.84 +	    case MUS_FLAC:
    9.85 +		FLAC_play(music->data.flac);
    9.86 +		break;
    9.87 +#endif
    9.88  #ifdef MP3_MUSIC
    9.89  	    case MUS_MP3:
    9.90  		smpeg.SMPEG_enableaudio(music->data.mp3,1);
    9.91 @@ -908,6 +947,11 @@
    9.92  		OGG_jump_to_time(music_playing->data.ogg, position);
    9.93  		break;
    9.94  #endif
    9.95 +#ifdef FLAC_MUSIC
    9.96 +	    case MUS_FLAC:
    9.97 +		FLAC_jump_to_time(music_playing->data.flac, position);
    9.98 +		break;
    9.99 +#endif
   9.100  #ifdef MP3_MUSIC
   9.101  	    case MUS_MP3:
   9.102  		if ( position > 0.0 ) {
   9.103 @@ -997,6 +1041,11 @@
   9.104  		OGG_setvolume(music_playing->data.ogg, volume);
   9.105  		break;
   9.106  #endif
   9.107 +#ifdef FLAC_MUSIC
   9.108 +	    case MUS_FLAC:
   9.109 +		FLAC_setvolume(music_playing->data.flac, volume);
   9.110 +		break;
   9.111 +#endif
   9.112  #ifdef MP3_MUSIC
   9.113  	    case MUS_MP3:
   9.114  		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
   9.115 @@ -1070,6 +1119,11 @@
   9.116  		OGG_stop(music_playing->data.ogg);
   9.117  		break;
   9.118  #endif
   9.119 +#ifdef FLAC_MUSIC
   9.120 +	    case MUS_FLAC:
   9.121 +		FLAC_stop(music_playing->data.flac);
   9.122 +		break;
   9.123 +#endif
   9.124  #ifdef MP3_MUSIC
   9.125  	    case MUS_MP3:
   9.126  		smpeg.SMPEG_stop(music_playing->data.mp3);
   9.127 @@ -1217,6 +1271,13 @@
   9.128  		}
   9.129  		break;
   9.130  #endif
   9.131 +#ifdef FLAC_MUSIC
   9.132 +	    case MUS_FLAC:
   9.133 +		if ( ! FLAC_playing(music_playing->data.flac) ) {
   9.134 +			playing = 0;
   9.135 +		}
   9.136 +		break;
   9.137 +#endif
   9.138  #ifdef MP3_MUSIC
   9.139  	    case MUS_MP3:
   9.140  		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
   9.141 @@ -1474,6 +1535,16 @@
   9.142  		}
   9.143  	} else
   9.144  #endif
   9.145 +#ifdef FLAC_MUSIC
   9.146 +	/* FLAC files have the magic four bytes "fLaC" */
   9.147 +	if ( strcmp((char *)magic, "fLaC") == 0 ) {
   9.148 +		music->type = MUS_FLAC;
   9.149 +		music->data.flac = FLAC_new_RW(rw);
   9.150 +		if ( music->data.flac == NULL ) {
   9.151 +			music->error = 1;
   9.152 +		}
   9.153 +	} else
   9.154 +#endif
   9.155  #ifdef MP3_MUSIC
   9.156  	if ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0 ) {
   9.157  		if ( Mix_InitMP3() == 0 ) {
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/music_flac.c	Wed Feb 27 07:31:03 2008 +0000
    10.3 @@ -0,0 +1,591 @@
    10.4 +/*
    10.5 +    SDL_mixer:  An audio mixer library based on the SDL library
    10.6 +    Copyright (C) 1997-2004 Sam Lantinga
    10.7 +
    10.8 +    This library is free software; you can redistribute it and/or
    10.9 +    modify it under the terms of the GNU Library General Public
   10.10 +    License as published by the Free Software Foundation; either
   10.11 +    version 2 of the License, or (at your option) any later version.
   10.12 +
   10.13 +    This library is distributed in the hope that it will be useful,
   10.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   10.16 +    Library General Public License for more details.
   10.17 +
   10.18 +    You should have received a copy of the GNU Library General Public
   10.19 +    License along with this library; if not, write to the Free
   10.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   10.21 +
   10.22 +    Sam Lantinga
   10.23 +    slouken@libsdl.org
   10.24 +
   10.25 +
   10.26 +    This file is used to support SDL_LoadMUS playback of FLAC files.
   10.27 +   											~ Austen Dicken (admin@cvpcs.org)
   10.28 +*/
   10.29 +
   10.30 +#ifdef FLAC_MUSIC
   10.31 +
   10.32 +#include <stdio.h>
   10.33 +#include <stdlib.h>
   10.34 +#include <string.h>
   10.35 +
   10.36 +#include "SDL_mixer.h"
   10.37 +#include "dynamic_flac.h"
   10.38 +#include "music_flac.h"
   10.39 +
   10.40 +/* This is the format of the audio mixer data */
   10.41 +static SDL_AudioSpec mixer;
   10.42 +
   10.43 +/* Initialize the FLAC player, with the given mixer settings
   10.44 +   This function returns 0, or -1 if there was an error.
   10.45 + */
   10.46 +int FLAC_init(SDL_AudioSpec *mixerfmt) {
   10.47 +	mixer = *mixerfmt;
   10.48 +	return(0);
   10.49 +}
   10.50 +
   10.51 +/* Set the volume for an FLAC stream */
   10.52 +void FLAC_setvolume(FLAC_music *music, int volume) {
   10.53 +	music->volume = volume;
   10.54 +}
   10.55 +
   10.56 +/* Load an FLAC stream from the given file */
   10.57 +FLAC_music *FLAC_new(const char *file) {
   10.58 +	SDL_RWops *rw;
   10.59 +
   10.60 +	rw = SDL_RWFromFile (file, "rb");
   10.61 +	if (rw == NULL) {
   10.62 +		SDL_SetError ("Couldn't open %s", file);
   10.63 +		return NULL;
   10.64 +	}
   10.65 +	return FLAC_new_RW (rw);
   10.66 +}
   10.67 +
   10.68 +static FLAC__StreamDecoderReadStatus flac_read_music_cb(
   10.69 +									const FLAC__StreamDecoder *decoder,
   10.70 +									FLAC__byte buffer[],
   10.71 +									size_t *bytes,
   10.72 +									void *client_data) {
   10.73 +	FLAC_music *data = (FLAC_music*)client_data;
   10.74 +
   10.75 +	// make sure there is something to be reading
   10.76 +	if (*bytes > 0) {
   10.77 +		*bytes = SDL_RWread (data->rwops, buffer, sizeof (FLAC__byte), *bytes);
   10.78 +
   10.79 +		if (*bytes < 0) { // error in read
   10.80 +			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
   10.81 +		}
   10.82 +		else if (*bytes == 0 ) { // no data was read (EOF)
   10.83 +			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
   10.84 +		}
   10.85 +		else { // data was read, continue
   10.86 +			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
   10.87 +		}
   10.88 +	}
   10.89 +	else {
   10.90 +		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
   10.91 +	}
   10.92 +}
   10.93 +
   10.94 +static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
   10.95 +									const FLAC__StreamDecoder *decoder,
   10.96 +									FLAC__uint64 absolute_byte_offset,
   10.97 +									void *client_data) {
   10.98 +	FLAC_music *data = (FLAC_music*)client_data;
   10.99 +
  10.100 +	if (SDL_RWseek (data->rwops, absolute_byte_offset, SEEK_SET) < 0) {
  10.101 +		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
  10.102 +	}
  10.103 +	else {
  10.104 +		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
  10.105 +	}
  10.106 +}
  10.107 +
  10.108 +static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
  10.109 +									const FLAC__StreamDecoder *decoder,
  10.110 +									FLAC__uint64 *absolute_byte_offset,
  10.111 +									void *client_data ) {
  10.112 +	FLAC_music *data = (FLAC_music*)client_data;
  10.113 +
  10.114 +	int pos = SDL_RWtell (data->rwops);
  10.115 +
  10.116 +	if (pos < 0) {
  10.117 +		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
  10.118 +	}
  10.119 +	else {
  10.120 +		*absolute_byte_offset = (FLAC__uint64)pos;
  10.121 +		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
  10.122 +	}
  10.123 +}
  10.124 +
  10.125 +static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
  10.126 +									const FLAC__StreamDecoder *decoder,
  10.127 +									FLAC__uint64 *stream_length,
  10.128 +									void *client_data) {
  10.129 +	FLAC_music *data = (FLAC_music*)client_data;
  10.130 +
  10.131 +	int pos = SDL_RWtell (data->rwops);
  10.132 +	int length = SDL_RWseek (data->rwops, 0, SEEK_END);
  10.133 +
  10.134 +	if (SDL_RWseek (data->rwops, pos, SEEK_SET) != pos || length < 0) {
  10.135 +		/* there was an error attempting to return the stream to the original
  10.136 +		 * position, or the length was invalid. */
  10.137 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
  10.138 +	}
  10.139 +	else {
  10.140 +		*stream_length = (FLAC__uint64)length;
  10.141 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
  10.142 +	}
  10.143 +}
  10.144 +
  10.145 +static FLAC__bool flac_eof_music_cb(
  10.146 +								const FLAC__StreamDecoder *decoder,
  10.147 +								void *client_data ) {
  10.148 +	FLAC_music *data = (FLAC_music*)client_data;
  10.149 +
  10.150 +	int pos = SDL_RWtell (data->rwops);
  10.151 +	int end = SDL_RWseek (data->rwops, 0, SEEK_END);
  10.152 +
  10.153 +	// was the original position equal to the end (a.k.a. the seek didn't move)?
  10.154 +	if (pos == end) {
  10.155 +		// must be EOF
  10.156 +		return true;
  10.157 +	}
  10.158 +	else {
  10.159 +		// not EOF, return to the original position
  10.160 +		SDL_RWseek (data->rwops, pos, SEEK_SET);
  10.161 +
  10.162 +		return false;
  10.163 +	}
  10.164 +}
  10.165 +
  10.166 +static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
  10.167 +									const FLAC__StreamDecoder *decoder,
  10.168 +									const FLAC__Frame *frame,
  10.169 +									const FLAC__int32 *const buffer[],
  10.170 +									void *client_data) {
  10.171 +	FLAC_music *data = (FLAC_music *)client_data;
  10.172 +	size_t i;
  10.173 +
  10.174 +	if (data->flac_data.total_samples == 0) {
  10.175 +		SDL_SetError ("Given FLAC file does not specify its sample count.");
  10.176 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  10.177 +	}
  10.178 +
  10.179 +	if (data->flac_data.channels != 2 ||
  10.180 +		data->flac_data.bits_per_sample != 16) {
  10.181 +		SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
  10.182 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  10.183 +	}
  10.184 +
  10.185 +	for (i = 0; i < frame->header.blocksize; i++) {
  10.186 +		// make sure we still have at least two bytes that can be read (one for
  10.187 +		// each channel)
  10.188 +		if (data->flac_data.max_to_read >= 4) {
  10.189 +			// does the data block exist?
  10.190 +			if (!data->flac_data.data) {
  10.191 +				data->flac_data.data_len = data->flac_data.max_to_read;
  10.192 +				data->flac_data.data_read = 0;
  10.193 +
  10.194 +				// create it
  10.195 +				data->flac_data.data =
  10.196 +									(char *)malloc (data->flac_data.data_len);
  10.197 +
  10.198 +				if (!data->flac_data.data) {
  10.199 +					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  10.200 +				}
  10.201 +			}
  10.202 +
  10.203 +			FLAC__int16 i16;
  10.204 +			FLAC__uint16 ui16;
  10.205 +
  10.206 +			i16 = (FLAC__int16)buffer[0][i];
  10.207 +			ui16 = (FLAC__uint16)i16;
  10.208 +
  10.209 +			*((data->flac_data.data) + (data->flac_data.data_read++)) =
  10.210 +															(char)(ui16);
  10.211 +			*((data->flac_data.data) + (data->flac_data.data_read++)) =
  10.212 +															(char)(ui16 >> 8);
  10.213 +
  10.214 +			i16 = (FLAC__int16)buffer[1][i];
  10.215 +			ui16 = (FLAC__uint16)i16;
  10.216 +
  10.217 +			*((data->flac_data.data) + (data->flac_data.data_read++)) =
  10.218 +															(char)(ui16);
  10.219 +			*((data->flac_data.data) + (data->flac_data.data_read++)) =
  10.220 +															(char)(ui16 >> 8);
  10.221 +
  10.222 +			data->flac_data.max_to_read -= 4;
  10.223 +
  10.224 +			if (data->flac_data.max_to_read < 4) {
  10.225 +				// we need to set this so that the read halts from the
  10.226 +				// FLAC_getsome function.
  10.227 +				data->flac_data.max_to_read = 0;
  10.228 +			}
  10.229 +		}
  10.230 +		else {
  10.231 +			// we need to write to the overflow
  10.232 +			if (!data->flac_data.overflow) {
  10.233 +				data->flac_data.overflow_len =
  10.234 +											4 * (frame->header.blocksize - i);
  10.235 +				data->flac_data.overflow_read = 0;
  10.236 +
  10.237 +				// make it big enough for the rest of the block
  10.238 +				data->flac_data.overflow =
  10.239 +								(char *)malloc (data->flac_data.overflow_len);
  10.240 +
  10.241 +				if (!data->flac_data.overflow) {
  10.242 +					return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  10.243 +				}
  10.244 +			}
  10.245 +
  10.246 +			FLAC__int16 i16;
  10.247 +			FLAC__uint16 ui16;
  10.248 +
  10.249 +			i16 = (FLAC__int16)buffer[0][i];
  10.250 +			ui16 = (FLAC__uint16)i16;
  10.251 +
  10.252 +			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
  10.253 +															(char)(ui16);
  10.254 +			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
  10.255 +															(char)(ui16 >> 8);
  10.256 +
  10.257 +			i16 = (FLAC__int16)buffer[1][i];
  10.258 +			ui16 = (FLAC__uint16)i16;
  10.259 +
  10.260 +			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
  10.261 +															(char)(ui16);
  10.262 +			*((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
  10.263 +															(char)(ui16 >> 8);
  10.264 +		}
  10.265 +	}
  10.266 +
  10.267 +	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
  10.268 +}
  10.269 +
  10.270 +static void flac_metadata_music_cb(
  10.271 +					const FLAC__StreamDecoder *decoder,
  10.272 +					const FLAC__StreamMetadata *metadata,
  10.273 +					void *client_data) {
  10.274 +	FLAC_music *data = (FLAC_music *)client_data;
  10.275 +
  10.276 +	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
  10.277 +		data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
  10.278 +		data->flac_data.channels = metadata->data.stream_info.channels;
  10.279 +		data->flac_data.total_samples =
  10.280 +							metadata->data.stream_info.total_samples;
  10.281 +		data->flac_data.bits_per_sample =
  10.282 +							metadata->data.stream_info.bits_per_sample;
  10.283 +		data->flac_data.sample_size = data->flac_data.channels *
  10.284 +										((data->flac_data.bits_per_sample) / 8);
  10.285 +	}
  10.286 +}
  10.287 +
  10.288 +static void flac_error_music_cb(
  10.289 +				const FLAC__StreamDecoder *decoder,
  10.290 +				FLAC__StreamDecoderErrorStatus status,
  10.291 +				void *client_data) {
  10.292 +	// print an SDL error based on the error status
  10.293 +	switch (status) {
  10.294 +		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
  10.295 +			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
  10.296 +		break;
  10.297 +		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
  10.298 +			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
  10.299 +		break;
  10.300 +		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
  10.301 +			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
  10.302 +		break;
  10.303 +		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
  10.304 +			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
  10.305 +		break;
  10.306 +		default:
  10.307 +			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
  10.308 +		break;
  10.309 +	}
  10.310 +}
  10.311 +
  10.312 +/* Load an FLAC stream from an SDL_RWops object */
  10.313 +FLAC_music *FLAC_new_RW(SDL_RWops *rw) {
  10.314 +	FLAC_music *music;
  10.315 +	int init_stage = 0;
  10.316 +	int was_error = 1;
  10.317 +
  10.318 +	music = (FLAC_music *)malloc ( sizeof (*music));
  10.319 +	if (music) {
  10.320 +		/* Initialize the music structure */
  10.321 +		memset (music, 0, (sizeof (*music)));
  10.322 +		FLAC_stop (music);
  10.323 +		FLAC_setvolume (music, MIX_MAX_VOLUME);
  10.324 +		music->section = -1;
  10.325 +		music->rwops = rw;
  10.326 +		music->flac_data.max_to_read = 0;
  10.327 +		music->flac_data.overflow = NULL;
  10.328 +		music->flac_data.overflow_len = 0;
  10.329 +		music->flac_data.overflow_read = 0;
  10.330 +		music->flac_data.data = NULL;
  10.331 +		music->flac_data.data_len = 0;
  10.332 +		music->flac_data.data_read = 0;
  10.333 +
  10.334 +		if (Mix_InitFLAC () >= 0) {
  10.335 +			init_stage++; // stage 1!
  10.336 +
  10.337 +			music->flac_decoder = flac.FLAC__stream_decoder_new ();
  10.338 +
  10.339 +			if (music->flac_decoder != NULL) {
  10.340 +				init_stage++; // stage 2!
  10.341 +
  10.342 +				if (flac.FLAC__stream_decoder_init_stream(
  10.343 +							music->flac_decoder,
  10.344 +							flac_read_music_cb, flac_seek_music_cb,
  10.345 +							flac_tell_music_cb, flac_length_music_cb,
  10.346 +							flac_eof_music_cb, flac_write_music_cb,
  10.347 +							flac_metadata_music_cb, flac_error_music_cb,
  10.348 +							music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
  10.349 +					init_stage++; // stage 3!
  10.350 +
  10.351 +					if (flac.FLAC__stream_decoder_process_until_end_of_metadata
  10.352 +											(music->flac_decoder)) {
  10.353 +						was_error = 0;
  10.354 +					}
  10.355 +				}
  10.356 +			}
  10.357 +		}
  10.358 +
  10.359 +		if (was_error) {
  10.360 +			switch (init_stage) {
  10.361 +				case 3:
  10.362 +					flac.FLAC__stream_decoder_finish( music->flac_decoder );
  10.363 +				case 2:
  10.364 +					flac.FLAC__stream_decoder_delete( music->flac_decoder );
  10.365 +				case 1:
  10.366 +					Mix_QuitFLAC();
  10.367 +				case 0:
  10.368 +					free(music);
  10.369 +					SDL_RWclose(rw);
  10.370 +					break;
  10.371 +			}
  10.372 +
  10.373 +			SDL_SetError ("There was an error in stage [%d] of FLAC init.",
  10.374 +							init_stage);
  10.375 +
  10.376 +			return NULL;
  10.377 +		}
  10.378 +	}
  10.379 +	else {
  10.380 +		SDL_OutOfMemory();
  10.381 +	}
  10.382 +
  10.383 +	return music;
  10.384 +}
  10.385 +
  10.386 +/* Start playback of a given FLAC stream */
  10.387 +void FLAC_play(FLAC_music *music) {
  10.388 +	music->playing = 1;
  10.389 +}
  10.390 +
  10.391 +/* Return non-zero if a stream is currently playing */
  10.392 +int FLAC_playing(FLAC_music *music) {
  10.393 +	return(music->playing);
  10.394 +}
  10.395 +
  10.396 +/* Read some FLAC stream data and convert it for output */
  10.397 +static void FLAC_getsome(FLAC_music *music) {
  10.398 +	int section;
  10.399 +	SDL_AudioCVT *cvt;
  10.400 +
  10.401 +	/* GET AUDIO wAVE DATA */
  10.402 +	// set the max number of characters to read
  10.403 +	music->flac_data.max_to_read = 8192;
  10.404 +
  10.405 +	// clear out the data buffer if it exists
  10.406 +	if (music->flac_data.data) {
  10.407 +		free (music->flac_data.data);
  10.408 +	}
  10.409 +
  10.410 +	music->flac_data.data_len = music->flac_data.max_to_read;
  10.411 +	music->flac_data.data_read = 0;
  10.412 +	music->flac_data.data = (char *)malloc (music->flac_data.data_len);
  10.413 +
  10.414 +	// we have data to read
  10.415 +	while(music->flac_data.max_to_read > 0) {
  10.416 +		// first check if there is data in the overflow from before
  10.417 +		if (music->flac_data.overflow) {
  10.418 +			size_t overflow_len = music->flac_data.overflow_read;
  10.419 +
  10.420 +			if (overflow_len > music->flac_data.max_to_read) {
  10.421 +				size_t overflow_extra_len = overflow_len -
  10.422 +												music->flac_data.max_to_read;
  10.423 +
  10.424 +				char* new_overflow = (char *)malloc (overflow_extra_len);
  10.425 +				memcpy (music->flac_data.data+music->flac_data.data_read,
  10.426 +					music->flac_data.overflow, music->flac_data.max_to_read);
  10.427 +				music->flac_data.data_read += music->flac_data.max_to_read;
  10.428 +				memcpy (new_overflow,
  10.429 +					music->flac_data.overflow + music->flac_data.max_to_read,
  10.430 +					overflow_extra_len);
  10.431 +				free (music->flac_data.overflow);
  10.432 +				music->flac_data.overflow = new_overflow;
  10.433 +				music->flac_data.overflow_len = overflow_extra_len;
  10.434 +				music->flac_data.overflow_read = 0;
  10.435 +				music->flac_data.max_to_read = 0;
  10.436 +			}
  10.437 +			else {
  10.438 +				memcpy (music->flac_data.data+music->flac_data.data_read,
  10.439 +					music->flac_data.overflow, overflow_len);
  10.440 +				music->flac_data.data_read += overflow_len;
  10.441 +				free (music->flac_data.overflow);
  10.442 +				music->flac_data.overflow = NULL;
  10.443 +				music->flac_data.overflow_len = 0;
  10.444 +				music->flac_data.overflow_read = 0;
  10.445 +				music->flac_data.max_to_read -= overflow_len;
  10.446 +			}
  10.447 +		}
  10.448 +		else {
  10.449 +			if (!flac.FLAC__stream_decoder_process_single (
  10.450 +														music->flac_decoder)) {
  10.451 +				music->flac_data.max_to_read = 0;
  10.452 +			}
  10.453 +
  10.454 +			if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
  10.455 +									== FLAC__STREAM_DECODER_END_OF_STREAM) {
  10.456 +				music->flac_data.max_to_read = 0;
  10.457 +			}
  10.458 +		}
  10.459 +	}
  10.460 +
  10.461 +	if (music->flac_data.data_read <= 0) {
  10.462 +		if (music->flac_data.data_read == 0) {
  10.463 +			music->playing = 0;
  10.464 +		}
  10.465 +		return;
  10.466 +	}
  10.467 +	cvt = &music->cvt;
  10.468 +	if (section != music->section) {
  10.469 +
  10.470 +		SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
  10.471 +						(int)music->flac_data.sample_rate, mixer.format,
  10.472 +		                mixer.channels, mixer.freq);
  10.473 +		if (cvt->buf) {
  10.474 +			free (cvt->buf);
  10.475 +		}
  10.476 +		cvt->buf = (Uint8 *)malloc (music->flac_data.data_len * cvt->len_mult);
  10.477 +		music->section = section;
  10.478 +	}
  10.479 +	if (cvt->buf) {
  10.480 +		memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
  10.481 +		if (cvt->needed) {
  10.482 +			cvt->len = music->flac_data.data_read;
  10.483 +			SDL_ConvertAudio (cvt);
  10.484 +		}
  10.485 +		else {
  10.486 +			cvt->len_cvt = music->flac_data.data_read;
  10.487 +		}
  10.488 +		music->len_available = music->cvt.len_cvt;
  10.489 +		music->snd_available = music->cvt.buf;
  10.490 +	}
  10.491 +	else {
  10.492 +		SDL_SetError ("Out of memory");
  10.493 +		music->playing = 0;
  10.494 +	}
  10.495 +}
  10.496 +
  10.497 +/* Play some of a stream previously started with FLAC_play() */
  10.498 +int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len) {
  10.499 +	int mixable;
  10.500 +
  10.501 +	while ((len > 0) && music->playing) {
  10.502 +		if (!music->len_available) {
  10.503 +			FLAC_getsome (music);
  10.504 +		}
  10.505 +		mixable = len;
  10.506 +		if (mixable > music->len_available) {
  10.507 +			mixable = music->len_available;
  10.508 +		}
  10.509 +		if (music->volume == MIX_MAX_VOLUME) {
  10.510 +			memcpy (snd, music->snd_available, mixable);
  10.511 +		}
  10.512 +		else {
  10.513 +			SDL_MixAudio (snd, music->snd_available, mixable, music->volume);
  10.514 +		}
  10.515 +		music->len_available -= mixable;
  10.516 +		music->snd_available += mixable;
  10.517 +		len -= mixable;
  10.518 +		snd += mixable;
  10.519 +	}
  10.520 +
  10.521 +	return len;
  10.522 +}
  10.523 +
  10.524 +/* Stop playback of a stream previously started with FLAC_play() */
  10.525 +void FLAC_stop(FLAC_music *music) {
  10.526 +	music->playing = 0;
  10.527 +}
  10.528 +
  10.529 +/* Close the given FLAC_music object */
  10.530 +void FLAC_delete(FLAC_music *music) {
  10.531 +	if (music) {
  10.532 +		if (music->flac_decoder) {
  10.533 +			flac.FLAC__stream_decoder_finish (music->flac_decoder);
  10.534 +			flac.FLAC__stream_decoder_delete (music->flac_decoder);
  10.535 +		}
  10.536 +
  10.537 +		if (music->flac_data.data) {
  10.538 +			free (music->flac_data.data);
  10.539 +		}
  10.540 +
  10.541 +		if (music->flac_data.overflow) {
  10.542 +			free (music->flac_data.overflow);
  10.543 +		}
  10.544 +
  10.545 +		if (music->cvt.buf) {
  10.546 +			free (music->cvt.buf);
  10.547 +		}
  10.548 +
  10.549 +		free (music);
  10.550 +
  10.551 +		Mix_QuitFLAC ();
  10.552 +	}
  10.553 +}
  10.554 +
  10.555 +/* Jump (seek) to a given position (time is in seconds) */
  10.556 +void FLAC_jump_to_time(FLAC_music *music, double time) {
  10.557 +	if (music) {
  10.558 +		if (music->flac_decoder) {
  10.559 +			double seek_sample = music->flac_data.sample_rate * time;
  10.560 +
  10.561 +			// clear data if it has data
  10.562 +			if (music->flac_data.data) {
  10.563 +				free (music->flac_data.data);
  10.564 +				music->flac_data.data = NULL;
  10.565 +			}
  10.566 +
  10.567 +			// clear overflow if it has data
  10.568 +			if (music->flac_data.overflow) {
  10.569 +				free (music->flac_data.overflow);
  10.570 +				music->flac_data.overflow = NULL;
  10.571 +			}
  10.572 +
  10.573 +			if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
  10.574 +												(FLAC__uint64)seek_sample)) {
  10.575 +				if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
  10.576 +										== FLAC__STREAM_DECODER_SEEK_ERROR) {
  10.577 +					flac.FLAC__stream_decoder_flush (music->flac_decoder);
  10.578 +				}
  10.579 +
  10.580 +				SDL_SetError
  10.581 +					("Seeking of FLAC stream failed: libFLAC seek failed.");
  10.582 +			}
  10.583 +		}
  10.584 +		else {
  10.585 +			SDL_SetError
  10.586 +				("Seeking of FLAC stream failed: FLAC decoder was NULL.");
  10.587 +		}
  10.588 +	}
  10.589 +	else {
  10.590 +		SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
  10.591 +	}
  10.592 +}
  10.593 +
  10.594 +#endif /* FLAC_MUSIC */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/music_flac.h	Wed Feb 27 07:31:03 2008 +0000
    11.3 @@ -0,0 +1,93 @@
    11.4 +/*
    11.5 +    SDL_mixer:  An audio mixer library based on the SDL library
    11.6 +    Copyright (C) 1997-2004 Sam Lantinga
    11.7 +
    11.8 +    This library is free software; you can redistribute it and/or
    11.9 +    modify it under the terms of the GNU Library General Public
   11.10 +    License as published by the Free Software Foundation; either
   11.11 +    version 2 of the License, or (at your option) any later version.
   11.12 +
   11.13 +    This library is distributed in the hope that it will be useful,
   11.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.16 +    Library General Public License for more details.
   11.17 +
   11.18 +    You should have received a copy of the GNU Library General Public
   11.19 +    License along with this library; if not, write to the Free
   11.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   11.21 +
   11.22 +    Sam Lantinga
   11.23 +    slouken@libsdl.org
   11.24 +
   11.25 +    Header to handle loading FLAC music files in SDL.
   11.26 +	    									~ Austen Dicken (admin@cvpcs.org)
   11.27 +*/
   11.28 +
   11.29 +/* $Id:  $ */
   11.30 +
   11.31 +#ifdef FLAC_MUSIC
   11.32 +
   11.33 +#include <FLAC/stream_decoder.h>
   11.34 +
   11.35 +typedef struct {
   11.36 +	FLAC__uint64 sample_size;
   11.37 +	unsigned sample_rate;
   11.38 +	unsigned channels;
   11.39 +	unsigned bits_per_sample;
   11.40 +	FLAC__uint64 total_samples;
   11.41 +
   11.42 +	// the following are used to handle the callback nature of the writer
   11.43 +	int max_to_read;
   11.44 +	char *data;				// pointer to beginning of data array
   11.45 +	int data_len;			// size of data array
   11.46 +	int data_read;			// amount of data array used
   11.47 +	char *overflow;			// pointer to beginning of overflow array
   11.48 +	int overflow_len;		// size of overflow array
   11.49 +	int overflow_read;		// amount of overflow array used
   11.50 +} FLAC_Data;
   11.51 +
   11.52 +typedef struct {
   11.53 +	int playing;
   11.54 +	int volume;
   11.55 +	int section;
   11.56 +	FLAC__StreamDecoder *flac_decoder;
   11.57 +	FLAC_Data flac_data;
   11.58 +	SDL_RWops *rwops;
   11.59 +	SDL_AudioCVT cvt;
   11.60 +	int len_available;
   11.61 +	Uint8 *snd_available;
   11.62 +} FLAC_music;
   11.63 +
   11.64 +/* Initialize the FLAC player, with the given mixer settings
   11.65 +   This function returns 0, or -1 if there was an error.
   11.66 + */
   11.67 +extern int FLAC_init(SDL_AudioSpec *mixer);
   11.68 +
   11.69 +/* Set the volume for a FLAC stream */
   11.70 +extern void FLAC_setvolume(FLAC_music *music, int volume);
   11.71 +
   11.72 +/* Load a FLAC stream from the given file */
   11.73 +extern FLAC_music *FLAC_new(const char *file);
   11.74 +
   11.75 +/* Load an FLAC stream from an SDL_RWops object */
   11.76 +extern FLAC_music *FLAC_new_RW(SDL_RWops *rw);
   11.77 +
   11.78 +/* Start playback of a given FLAC stream */
   11.79 +extern void FLAC_play(FLAC_music *music);
   11.80 +
   11.81 +/* Return non-zero if a stream is currently playing */
   11.82 +extern int FLAC_playing(FLAC_music *music);
   11.83 +
   11.84 +/* Play some of a stream previously started with FLAC_play() */
   11.85 +extern int FLAC_playAudio(FLAC_music *music, Uint8 *stream, int len);
   11.86 +
   11.87 +/* Stop playback of a stream previously started with FLAC_play() */
   11.88 +extern void FLAC_stop(FLAC_music *music);
   11.89 +
   11.90 +/* Close the given FLAC stream */
   11.91 +extern void FLAC_delete(FLAC_music *music);
   11.92 +
   11.93 +/* Jump (seek) to a given position (time is in seconds) */
   11.94 +extern void FLAC_jump_to_time(FLAC_music *music, double time);
   11.95 +
   11.96 +#endif /* FLAC_MUSIC */