load_flac.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Nov 2009 18:40:07 +0000
changeset 474 a2c238c0c4b2
parent 473 60b7e1c4f6b2
child 518 8bc9b5fd2aae
permissions -rw-r--r--
Don't break binary compatibility!
     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 {
    55 	// make sure there is something to be reading
    56 	if (*bytes > 0) {
    57 		FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    58 
    59 		*bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
    60 								*bytes);
    61 
    62 		if(*bytes < 0) { // error in read
    63 			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    64 		}
    65 		else if(*bytes == 0) { // no data was read (EOF)
    66 			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
    67 		}
    68 		else { // data was read, continue
    69 			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    70 		}
    71 	}
    72 	else {
    73 		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    74 	}
    75 }
    76 
    77 static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
    78 									const FLAC__StreamDecoder *decoder,
    79 									FLAC__uint64 absolute_byte_offset,
    80 									void *client_data)
    81 {
    82 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    83 
    84 	if (SDL_RWseek (data->sdl_src, absolute_byte_offset, RW_SEEK_SET) < 0) {
    85 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    86 	}
    87 	else {
    88 		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    89 	}
    90 }
    91 
    92 static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    93 									const FLAC__StreamDecoder *decoder,
    94 									FLAC__uint64 *absolute_byte_offset,
    95 									void *client_data)
    96 {
    97 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    98 
    99 	int pos = SDL_RWtell (data->sdl_src);
   100 
   101 	if (pos < 0) {
   102 		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   103 	}
   104 	else {
   105 		*absolute_byte_offset = (FLAC__uint64)pos;
   106 		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   107 	}
   108 }
   109 
   110 static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   111 									const FLAC__StreamDecoder *decoder,
   112 									FLAC__uint64 *stream_length,
   113 									void *client_data)
   114 {
   115 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   116 
   117 	int pos = SDL_RWtell (data->sdl_src);
   118 	int length = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   119 
   120 	if (SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET) != pos || length < 0) {
   121 		/* there was an error attempting to return the stream to the original
   122 		 * position, or the length was invalid. */
   123 		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   124 	}
   125 	else {
   126 		*stream_length = (FLAC__uint64)length;
   127 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   128 	}
   129 }
   130 
   131 static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   132 									void *client_data)
   133 {
   134 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   135 
   136 	int pos = SDL_RWtell (data->sdl_src);
   137 	int end = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   138 
   139 	// was the original position equal to the end (a.k.a. the seek didn't move)?
   140 	if (pos == end) {
   141 		// must be EOF
   142 		return true;
   143 	}
   144 	else {
   145 		// not EOF, return to the original position
   146 		SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET);
   147 
   148 		return false;
   149 	}
   150 }
   151 
   152 static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   153 									const FLAC__StreamDecoder *decoder,
   154 									const FLAC__Frame *frame,
   155 									const FLAC__int32 *const buffer[],
   156 									void *client_data)
   157 {
   158 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   159 	size_t i;
   160 	Uint8 *buf;
   161 
   162 	if (data->flac_total_samples == 0) {
   163 		SDL_SetError ("Given FLAC file does not specify its sample count.");
   164 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   165 	}
   166 
   167 	if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   168 		SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   169 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   170 	}
   171 
   172 	// check if it is the first audio frame so we can initialize the output
   173 	// buffer
   174 	if (frame->header.number.sample_number == 0) {
   175 		*(data->sdl_audio_len) = data->sdl_spec->size;
   176 		data->sdl_audio_read = 0;
   177     	*(data->sdl_audio_buf) = malloc (*(data->sdl_audio_len));
   178 
   179     	if (*(data->sdl_audio_buf) == NULL) {
   180     		SDL_SetError
   181 					("Unable to allocate memory to store the FLAC stream.");
   182     		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   183     	}
   184 	}
   185 
   186 	buf = *(data->sdl_audio_buf);
   187 
   188 	for (i = 0; i < frame->header.blocksize; i++) {
   189 		FLAC__int16 i16;
   190 		FLAC__uint16 ui16;
   191 
   192 		i16 = (FLAC__int16)buffer[0][i];
   193 		ui16 = (FLAC__uint16)i16;
   194 
   195 		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   196 		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   197 
   198 		i16 = (FLAC__int16)buffer[1][i];
   199 		ui16 = (FLAC__uint16)i16;
   200 
   201 		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   202 		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   203 	}
   204 
   205 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   206 }
   207 
   208 static void flac_metadata_load_cb(
   209 					const FLAC__StreamDecoder *decoder,
   210 					const FLAC__StreamMetadata *metadata,
   211 					void *client_data)
   212 {
   213 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   214 	FLAC__uint64 total_samples;
   215 	unsigned bps;
   216 
   217 	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   218 		// save the metadata right now for use later on
   219 		*(data->sdl_audio_buf) = NULL;
   220 		*(data->sdl_audio_len) = 0;
   221 		memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
   222 
   223 		data->sdl_spec->format = AUDIO_S16;
   224 		data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
   225 		data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
   226 		data->sdl_spec->samples = 8192; /* buffer size */
   227 
   228 		total_samples = metadata->data.stream_info.total_samples;
   229 		bps = metadata->data.stream_info.bits_per_sample;
   230 
   231 		data->sdl_spec->size = total_samples * data->sdl_spec->channels *
   232 								(bps / 8);
   233 		data->flac_total_samples = total_samples;
   234 		data->flac_bps = bps;
   235 	}
   236 }
   237 
   238 static void flac_error_load_cb(
   239 				const FLAC__StreamDecoder *decoder,
   240 				FLAC__StreamDecoderErrorStatus status,
   241 				void *client_data)
   242 {
   243 	// print an SDL error based on the error status
   244 	switch (status) {
   245 		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   246 			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
   247 		break;
   248 		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   249 			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
   250 		break;
   251 		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   252 			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
   253 		break;
   254 		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   255 			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
   256 		break;
   257 		default:
   258 			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
   259 		break;
   260 	}
   261 }
   262 
   263 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
   264 SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
   265         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
   266 {
   267 	FLAC__StreamDecoder *decoder = 0;
   268 	FLAC__StreamDecoderInitStatus init_status;
   269 	int was_error = 1;
   270 	int was_init = 0;
   271 	Uint32 samplesize;
   272 
   273 	// create the client data passing information
   274 	FLAC_SDL_Data* client_data;
   275 	client_data = (FLAC_SDL_Data *)malloc (sizeof (FLAC_SDL_Data));
   276 
   277 	if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   278 		goto done;
   279 
   280 	if (!Mix_Init(MIX_INIT_FLAC))
   281 		goto done;
   282 
   283 	if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   284 		SDL_SetError ("Unable to allocate FLAC decoder.");
   285 		goto done;
   286 	}
   287 
   288 	init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   289 								flac_read_load_cb, flac_seek_load_cb,
   290 								flac_tell_load_cb, flac_length_load_cb,
   291 								flac_eof_load_cb, flac_write_load_cb,
   292 								flac_metadata_load_cb, flac_error_load_cb,
   293 								client_data);
   294 
   295 	if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   296 		SDL_SetError ("Unable to initialize FLAC stream decoder.");
   297 		goto done;
   298 	}
   299 
   300 	was_init = 1;
   301 
   302 	client_data->sdl_src = src;
   303 	client_data->sdl_spec = spec;
   304 	client_data->sdl_audio_buf = audio_buf;
   305 	client_data->sdl_audio_len = audio_len;
   306 
   307 	if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   308 		SDL_SetError ("Unable to process FLAC file.");
   309 		goto done;
   310 	}
   311 
   312 	was_error = 0;
   313 
   314     /* Don't return a buffer that isn't a multiple of samplesize */
   315     samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   316     *audio_len &= ~(samplesize - 1);
   317 
   318 done:
   319 	if (was_init && decoder) {
   320 		flac.FLAC__stream_decoder_finish (decoder);
   321 	}
   322 
   323 	if (decoder) {
   324 		flac.FLAC__stream_decoder_delete (decoder);
   325 	}
   326 
   327 	if (src) {
   328 		if (freesrc)
   329 			SDL_RWclose (src);
   330 		else
   331 			SDL_RWseek (src, 0, RW_SEEK_SET);
   332 	}
   333 
   334 	if (was_error)
   335 		spec = NULL;
   336 
   337     return spec;
   338 }
   339 
   340 #endif // FLAC_MUSIC