load_flac.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 08 Dec 2008 00:27:32 +0000
changeset 386 695494546b3c
parent 382 50501e45c57b
child 436 8ec227cabdd4
permissions -rw-r--r--
Updated copyright date
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     This is the source needed to decode a FLAC into a waveform.
    20     										~ Austen Dicken (admin@cvpcs.org).
    21 */
    22 
    23 #ifdef FLAC_MUSIC
    24 
    25 #include <stdio.h>
    26 #include <stdlib.h>
    27 #include <string.h>
    28 
    29 #include "SDL_mutex.h"
    30 #include "SDL_endian.h"
    31 #include "SDL_timer.h"
    32 
    33 #include "SDL_mixer.h"
    34 #include "dynamic_flac.h"
    35 #include "load_flac.h"
    36 
    37 #include <FLAC/stream_decoder.h>
    38 
    39 typedef struct {
    40 	SDL_RWops* sdl_src;
    41 	SDL_AudioSpec* sdl_spec;
    42 	Uint8** sdl_audio_buf;
    43 	Uint32* sdl_audio_len;
    44 	int sdl_audio_read;
    45 	FLAC__uint64 flac_total_samples;
    46 	unsigned flac_bps;
    47 } FLAC_SDL_Data;
    48 
    49 static FLAC__StreamDecoderReadStatus flac_read_load_cb(
    50 									const FLAC__StreamDecoder *decoder,
    51 									FLAC__byte buffer[],
    52 									size_t *bytes,
    53 									void *client_data) {
    54 	// make sure there is something to be reading
    55 	if (*bytes > 0) {
    56 		FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    57 
    58 		*bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
    59 								*bytes);
    60 
    61 		if(*bytes < 0) { // error in read
    62 			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    63 		}
    64 		else if(*bytes == 0) { // no data was read (EOF)
    65 			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    66 		}
    67 		else { // data was read, continue
    68 			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    69 		}
    70 	}
    71 	else {
    72 		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    73 	}
    74 }
    75 
    76 static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
    77 									const FLAC__StreamDecoder *decoder,
    78 									FLAC__uint64 absolute_byte_offset,
    79 									void *client_data) {
    80 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    81 
    82 	if (SDL_RWseek (data->sdl_src, absolute_byte_offset, SEEK_SET) < 0) {
    83 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    84 	}
    85 	else {
    86 		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    87 	}
    88 }
    89 
    90 static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    91 									const FLAC__StreamDecoder *decoder,
    92 									FLAC__uint64 *absolute_byte_offset,
    93 									void *client_data) {
    94 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    95 
    96 	int pos = SDL_RWtell (data->sdl_src);
    97 
    98 	if (pos < 0) {
    99 		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   100 	}
   101 	else {
   102 		*absolute_byte_offset = (FLAC__uint64)pos;
   103 		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   104 	}
   105 }
   106 
   107 static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   108 									const FLAC__StreamDecoder *decoder,
   109 									FLAC__uint64 *stream_length,
   110 									void *client_data) {
   111 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   112 
   113 	int pos = SDL_RWtell (data->sdl_src);
   114 	int length = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   115 
   116 	if (SDL_RWseek (data->sdl_src, pos, SEEK_SET) != pos || length < 0) {
   117 		/* there was an error attempting to return the stream to the original
   118 		 * position, or the length was invalid. */
   119 		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   120 	}
   121 	else {
   122 		*stream_length = (FLAC__uint64)length;
   123 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   124 	}
   125 }
   126 
   127 static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   128 									void *client_data) {
   129 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   130 
   131 	int pos = SDL_RWtell (data->sdl_src);
   132 	int end = SDL_RWseek (data->sdl_src, 0, SEEK_END);
   133 
   134 	// was the original position equal to the end (a.k.a. the seek didn't move)?
   135 	if (pos == end) {
   136 		// must be EOF
   137 		return true;
   138 	}
   139 	else {
   140 		// not EOF, return to the original position
   141 		SDL_RWseek (data->sdl_src, pos, SEEK_SET);
   142 
   143 		return false;
   144 	}
   145 }
   146 
   147 static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   148 									const FLAC__StreamDecoder *decoder,
   149 									const FLAC__Frame *frame,
   150 									const FLAC__int32 *const buffer[],
   151 									void *client_data) {
   152 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   153 	size_t i;
   154 
   155 	if (data->flac_total_samples == 0) {
   156 		SDL_SetError ("Given FLAC file does not specify its sample count.");
   157 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   158 	}
   159 
   160 	if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   161 		SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   162 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   163 	}
   164 
   165 	// check if it is the first audio frame so we can initialize the output
   166 	// buffer
   167 	if (frame->header.number.sample_number == 0) {
   168 		*(data->sdl_audio_len) = data->sdl_spec->size;
   169 		data->sdl_audio_read = 0;
   170     	*(data->sdl_audio_buf) = malloc (*(data->sdl_audio_len));
   171 
   172     	if (*(data->sdl_audio_buf) == NULL) {
   173     		SDL_SetError
   174 					("Unable to allocate memory to store the FLAC stream.");
   175     		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   176     	}
   177 	}
   178 
   179 	Uint8 *buf = *(data->sdl_audio_buf);
   180 
   181 	for (i = 0; i < frame->header.blocksize; i++) {
   182 		FLAC__int16 i16;
   183 		FLAC__uint16 ui16;
   184 
   185 		i16 = (FLAC__int16)buffer[0][i];
   186 		ui16 = (FLAC__uint16)i16;
   187 
   188 		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   189 		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   190 
   191 		i16 = (FLAC__int16)buffer[1][i];
   192 		ui16 = (FLAC__uint16)i16;
   193 
   194 		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   195 		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   196 	}
   197 
   198 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   199 }
   200 
   201 static void flac_metadata_load_cb(
   202 					const FLAC__StreamDecoder *decoder,
   203 					const FLAC__StreamMetadata *metadata,
   204 					void *client_data) {
   205 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   206 	FLAC__uint64 total_samples;
   207 	unsigned bps;
   208 
   209 	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   210 		// save the metadata right now for use later on
   211 		*(data->sdl_audio_buf) = NULL;
   212 		*(data->sdl_audio_len) = 0;
   213 		memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
   214 
   215 		data->sdl_spec->format = AUDIO_S16;
   216 		data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
   217 		data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
   218 		data->sdl_spec->samples = 8192; /* buffer size */
   219 
   220 		total_samples = metadata->data.stream_info.total_samples;
   221 		bps = metadata->data.stream_info.bits_per_sample;
   222 
   223 		data->sdl_spec->size = total_samples * data->sdl_spec->channels *
   224 								(bps / 8);
   225 		data->flac_total_samples = total_samples;
   226 		data->flac_bps = bps;
   227 	}
   228 }
   229 
   230 static void flac_error_load_cb(
   231 				const FLAC__StreamDecoder *decoder,
   232 				FLAC__StreamDecoderErrorStatus status,
   233 				void *client_data) {
   234 	// print an SDL error based on the error status
   235 	switch (status) {
   236 		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   237 			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
   238 		break;
   239 		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   240 			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
   241 		break;
   242 		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   243 			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
   244 		break;
   245 		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   246 			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
   247 		break;
   248 		default:
   249 			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
   250 		break;
   251 	}
   252 }
   253 
   254 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
   255 SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
   256         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) {
   257 	FLAC__StreamDecoder *decoder = 0;
   258 	FLAC__StreamDecoderInitStatus init_status;
   259 	int was_error = 1;
   260 	int was_init = 0;
   261 	Uint32 samplesize;
   262 
   263 	// create the client data passing information
   264 	FLAC_SDL_Data* client_data;
   265 	client_data = (FLAC_SDL_Data *)malloc (sizeof (FLAC_SDL_Data));
   266 
   267     if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   268         goto done;
   269 
   270     if (Mix_InitFLAC() < 0)
   271         goto done;
   272 
   273 	if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   274 		SDL_SetError ("Unable to allocate FLAC decoder.");
   275 		goto done;
   276 	}
   277 
   278 	init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   279 								flac_read_load_cb, flac_seek_load_cb,
   280 								flac_tell_load_cb, flac_length_load_cb,
   281 								flac_eof_load_cb, flac_write_load_cb,
   282 								flac_metadata_load_cb, flac_error_load_cb,
   283 								client_data);
   284 
   285 	if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   286 		SDL_SetError ("Unable to initialize FLAC stream decoder.");
   287 		goto done;
   288 	}
   289 
   290 	was_init = 1;
   291 
   292 	client_data->sdl_src = src;
   293 	client_data->sdl_spec = spec;
   294 	client_data->sdl_audio_buf = audio_buf;
   295 	client_data->sdl_audio_len = audio_len;
   296 
   297 	if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   298 		SDL_SetError ("Unable to process FLAC file.");
   299 		goto done;
   300 	}
   301 
   302 	was_error = 0;
   303 
   304     /* Don't return a buffer that isn't a multiple of samplesize */
   305     samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   306     *audio_len &= ~(samplesize - 1);
   307 
   308 done:
   309 	if(was_init && decoder) {
   310 		flac.FLAC__stream_decoder_finish (decoder);
   311 	}
   312 
   313 	if(decoder) {
   314 		flac.FLAC__stream_decoder_delete (decoder);
   315 	}
   316 
   317     if (src) {
   318         if (freesrc)
   319             SDL_RWclose (src);
   320         else
   321             SDL_RWseek (src, 0, SEEK_SET);
   322     }
   323 
   324     if (was_error)
   325         spec = NULL;
   326 
   327     Mix_QuitFLAC ();
   328 
   329     return spec;
   330 }
   331 
   332 #endif // FLAC_MUSIC