load_flac.c
changeset 382 50501e45c57b
child 386 695494546b3c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/load_flac.c	Wed Feb 27 07:31:03 2008 +0000
     1.3 @@ -0,0 +1,332 @@
     1.4 +/*
     1.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     1.6 +    Copyright (C) 1997-2004 Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    This is the source needed to decode a FLAC into a waveform.
    1.23 +    										~ Austen Dicken (admin@cvpcs.org).
    1.24 +*/
    1.25 +
    1.26 +#ifdef FLAC_MUSIC
    1.27 +
    1.28 +#include <stdio.h>
    1.29 +#include <stdlib.h>
    1.30 +#include <string.h>
    1.31 +
    1.32 +#include "SDL_mutex.h"
    1.33 +#include "SDL_endian.h"
    1.34 +#include "SDL_timer.h"
    1.35 +
    1.36 +#include "SDL_mixer.h"
    1.37 +#include "dynamic_flac.h"
    1.38 +#include "load_flac.h"
    1.39 +
    1.40 +#include <FLAC/stream_decoder.h>
    1.41 +
    1.42 +typedef struct {
    1.43 +	SDL_RWops* sdl_src;
    1.44 +	SDL_AudioSpec* sdl_spec;
    1.45 +	Uint8** sdl_audio_buf;
    1.46 +	Uint32* sdl_audio_len;
    1.47 +	int sdl_audio_read;
    1.48 +	FLAC__uint64 flac_total_samples;
    1.49 +	unsigned flac_bps;
    1.50 +} FLAC_SDL_Data;
    1.51 +
    1.52 +static FLAC__StreamDecoderReadStatus flac_read_load_cb(
    1.53 +									const FLAC__StreamDecoder *decoder,
    1.54 +									FLAC__byte buffer[],
    1.55 +									size_t *bytes,
    1.56 +									void *client_data) {
    1.57 +	// make sure there is something to be reading
    1.58 +	if (*bytes > 0) {
    1.59 +		FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    1.60 +
    1.61 +		*bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
    1.62 +								*bytes);
    1.63 +
    1.64 +		if(*bytes < 0) { // error in read
    1.65 +			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    1.66 +		}
    1.67 +		else if(*bytes == 0) { // no data was read (EOF)
    1.68 +			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    1.69 +		}
    1.70 +		else { // data was read, continue
    1.71 +			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    1.72 +		}
    1.73 +	}
    1.74 +	else {
    1.75 +		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    1.76 +	}
    1.77 +}
    1.78 +
    1.79 +static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
    1.80 +									const FLAC__StreamDecoder *decoder,
    1.81 +									FLAC__uint64 absolute_byte_offset,
    1.82 +									void *client_data) {
    1.83 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    1.84 +
    1.85 +	if (SDL_RWseek (data->sdl_src, absolute_byte_offset, SEEK_SET) < 0) {
    1.86 +		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    1.87 +	}
    1.88 +	else {
    1.89 +		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    1.90 +	}
    1.91 +}
    1.92 +
    1.93 +static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    1.94 +									const FLAC__StreamDecoder *decoder,
    1.95 +									FLAC__uint64 *absolute_byte_offset,
    1.96 +									void *client_data) {
    1.97 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    1.98 +
    1.99 +	int pos = SDL_RWtell (data->sdl_src);
   1.100 +
   1.101 +	if (pos < 0) {
   1.102 +		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   1.103 +	}
   1.104 +	else {
   1.105 +		*absolute_byte_offset = (FLAC__uint64)pos;
   1.106 +		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   1.107 +	}
   1.108 +}
   1.109 +
   1.110 +static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   1.111 +									const FLAC__StreamDecoder *decoder,
   1.112 +									FLAC__uint64 *stream_length,
   1.113 +									void *client_data) {
   1.114 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   1.115 +
   1.116 +	int pos = SDL_RWtell (data->sdl_src);
   1.117 +	int length = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   1.118 +
   1.119 +	if (SDL_RWseek (data->sdl_src, pos, SEEK_SET) != pos || length < 0) {
   1.120 +		/* there was an error attempting to return the stream to the original
   1.121 +		 * position, or the length was invalid. */
   1.122 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   1.123 +	}
   1.124 +	else {
   1.125 +		*stream_length = (FLAC__uint64)length;
   1.126 +		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   1.127 +	}
   1.128 +}
   1.129 +
   1.130 +static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   1.131 +									void *client_data) {
   1.132 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   1.133 +
   1.134 +	int pos = SDL_RWtell (data->sdl_src);
   1.135 +	int end = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   1.136 +
   1.137 +	// was the original position equal to the end (a.k.a. the seek didn't move)?
   1.138 +	if (pos == end) {
   1.139 +		// must be EOF
   1.140 +		return true;
   1.141 +	}
   1.142 +	else {
   1.143 +		// not EOF, return to the original position
   1.144 +		SDL_RWseek (data->sdl_src, pos, SEEK_SET);
   1.145 +
   1.146 +		return false;
   1.147 +	}
   1.148 +}
   1.149 +
   1.150 +static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   1.151 +									const FLAC__StreamDecoder *decoder,
   1.152 +									const FLAC__Frame *frame,
   1.153 +									const FLAC__int32 *const buffer[],
   1.154 +									void *client_data) {
   1.155 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   1.156 +	size_t i;
   1.157 +
   1.158 +	if (data->flac_total_samples == 0) {
   1.159 +		SDL_SetError ("Given FLAC file does not specify its sample count.");
   1.160 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   1.161 +	}
   1.162 +
   1.163 +	if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   1.164 +		SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   1.165 +		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   1.166 +	}
   1.167 +
   1.168 +	// check if it is the first audio frame so we can initialize the output
   1.169 +	// buffer
   1.170 +	if (frame->header.number.sample_number == 0) {
   1.171 +		*(data->sdl_audio_len) = data->sdl_spec->size;
   1.172 +		data->sdl_audio_read = 0;
   1.173 +    	*(data->sdl_audio_buf) = malloc (*(data->sdl_audio_len));
   1.174 +
   1.175 +    	if (*(data->sdl_audio_buf) == NULL) {
   1.176 +    		SDL_SetError
   1.177 +					("Unable to allocate memory to store the FLAC stream.");
   1.178 +    		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   1.179 +    	}
   1.180 +	}
   1.181 +
   1.182 +	Uint8 *buf = *(data->sdl_audio_buf);
   1.183 +
   1.184 +	for (i = 0; i < frame->header.blocksize; i++) {
   1.185 +		FLAC__int16 i16;
   1.186 +		FLAC__uint16 ui16;
   1.187 +
   1.188 +		i16 = (FLAC__int16)buffer[0][i];
   1.189 +		ui16 = (FLAC__uint16)i16;
   1.190 +
   1.191 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   1.192 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   1.193 +
   1.194 +		i16 = (FLAC__int16)buffer[1][i];
   1.195 +		ui16 = (FLAC__uint16)i16;
   1.196 +
   1.197 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   1.198 +		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   1.199 +	}
   1.200 +
   1.201 +	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   1.202 +}
   1.203 +
   1.204 +static void flac_metadata_load_cb(
   1.205 +					const FLAC__StreamDecoder *decoder,
   1.206 +					const FLAC__StreamMetadata *metadata,
   1.207 +					void *client_data) {
   1.208 +	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   1.209 +	FLAC__uint64 total_samples;
   1.210 +	unsigned bps;
   1.211 +
   1.212 +	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   1.213 +		// save the metadata right now for use later on
   1.214 +		*(data->sdl_audio_buf) = NULL;
   1.215 +		*(data->sdl_audio_len) = 0;
   1.216 +		memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
   1.217 +
   1.218 +		data->sdl_spec->format = AUDIO_S16;
   1.219 +		data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
   1.220 +		data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
   1.221 +		data->sdl_spec->samples = 8192; /* buffer size */
   1.222 +
   1.223 +		total_samples = metadata->data.stream_info.total_samples;
   1.224 +		bps = metadata->data.stream_info.bits_per_sample;
   1.225 +
   1.226 +		data->sdl_spec->size = total_samples * data->sdl_spec->channels *
   1.227 +								(bps / 8);
   1.228 +		data->flac_total_samples = total_samples;
   1.229 +		data->flac_bps = bps;
   1.230 +	}
   1.231 +}
   1.232 +
   1.233 +static void flac_error_load_cb(
   1.234 +				const FLAC__StreamDecoder *decoder,
   1.235 +				FLAC__StreamDecoderErrorStatus status,
   1.236 +				void *client_data) {
   1.237 +	// print an SDL error based on the error status
   1.238 +	switch (status) {
   1.239 +		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   1.240 +			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
   1.241 +		break;
   1.242 +		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   1.243 +			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
   1.244 +		break;
   1.245 +		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   1.246 +			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
   1.247 +		break;
   1.248 +		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   1.249 +			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
   1.250 +		break;
   1.251 +		default:
   1.252 +			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
   1.253 +		break;
   1.254 +	}
   1.255 +}
   1.256 +
   1.257 +/* don't call this directly; use Mix_LoadWAV_RW() for now. */
   1.258 +SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
   1.259 +        SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) {
   1.260 +	FLAC__StreamDecoder *decoder = 0;
   1.261 +	FLAC__StreamDecoderInitStatus init_status;
   1.262 +	int was_error = 1;
   1.263 +	int was_init = 0;
   1.264 +	Uint32 samplesize;
   1.265 +
   1.266 +	// create the client data passing information
   1.267 +	FLAC_SDL_Data* client_data;
   1.268 +	client_data = (FLAC_SDL_Data *)malloc (sizeof (FLAC_SDL_Data));
   1.269 +
   1.270 +    if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   1.271 +        goto done;
   1.272 +
   1.273 +    if (Mix_InitFLAC() < 0)
   1.274 +        goto done;
   1.275 +
   1.276 +	if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   1.277 +		SDL_SetError ("Unable to allocate FLAC decoder.");
   1.278 +		goto done;
   1.279 +	}
   1.280 +
   1.281 +	init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   1.282 +								flac_read_load_cb, flac_seek_load_cb,
   1.283 +								flac_tell_load_cb, flac_length_load_cb,
   1.284 +								flac_eof_load_cb, flac_write_load_cb,
   1.285 +								flac_metadata_load_cb, flac_error_load_cb,
   1.286 +								client_data);
   1.287 +
   1.288 +	if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   1.289 +		SDL_SetError ("Unable to initialize FLAC stream decoder.");
   1.290 +		goto done;
   1.291 +	}
   1.292 +
   1.293 +	was_init = 1;
   1.294 +
   1.295 +	client_data->sdl_src = src;
   1.296 +	client_data->sdl_spec = spec;
   1.297 +	client_data->sdl_audio_buf = audio_buf;
   1.298 +	client_data->sdl_audio_len = audio_len;
   1.299 +
   1.300 +	if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   1.301 +		SDL_SetError ("Unable to process FLAC file.");
   1.302 +		goto done;
   1.303 +	}
   1.304 +
   1.305 +	was_error = 0;
   1.306 +
   1.307 +    /* Don't return a buffer that isn't a multiple of samplesize */
   1.308 +    samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   1.309 +    *audio_len &= ~(samplesize - 1);
   1.310 +
   1.311 +done:
   1.312 +	if(was_init && decoder) {
   1.313 +		flac.FLAC__stream_decoder_finish (decoder);
   1.314 +	}
   1.315 +
   1.316 +	if(decoder) {
   1.317 +		flac.FLAC__stream_decoder_delete (decoder);
   1.318 +	}
   1.319 +
   1.320 +    if (src) {
   1.321 +        if (freesrc)
   1.322 +            SDL_RWclose (src);
   1.323 +        else
   1.324 +            SDL_RWseek (src, 0, SEEK_SET);
   1.325 +    }
   1.326 +
   1.327 +    if (was_error)
   1.328 +        spec = NULL;
   1.329 +
   1.330 +    Mix_QuitFLAC ();
   1.331 +
   1.332 +    return spec;
   1.333 +}
   1.334 +
   1.335 +#endif // FLAC_MUSIC