load_flac.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 May 2013 02:56:20 -0700
changeset 613 6fa075aa693e
parent 601 05123263dab3
child 617 87116a42526e
permissions -rw-r--r--
Fixed Xcode warnings
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 
    21   This is the source needed to decode a FLAC into a waveform.
    22   	~ Austen Dicken (admin@cvpcs.org).
    23 */
    24 
    25 #ifdef FLAC_MUSIC
    26 
    27 #include <stdio.h>
    28 #include <stdlib.h>
    29 #include <string.h>
    30 
    31 #include "SDL_mutex.h"
    32 #include "SDL_endian.h"
    33 #include "SDL_timer.h"
    34 
    35 #include "SDL_mixer.h"
    36 #include "dynamic_flac.h"
    37 #include "load_flac.h"
    38 
    39 #include <FLAC/stream_decoder.h>
    40 
    41 typedef struct {
    42 	SDL_RWops* sdl_src;
    43 	SDL_AudioSpec* sdl_spec;
    44 	Uint8** sdl_audio_buf;
    45 	Uint32* sdl_audio_len;
    46 	int sdl_audio_read;
    47 	FLAC__uint64 flac_total_samples;
    48 	unsigned flac_bps;
    49 } FLAC_SDL_Data;
    50 
    51 static FLAC__StreamDecoderReadStatus flac_read_load_cb(
    52 									const FLAC__StreamDecoder *decoder,
    53 									FLAC__byte buffer[],
    54 									size_t *bytes,
    55 									void *client_data)
    56 {
    57 	// make sure there is something to be reading
    58 	if (*bytes > 0) {
    59 		FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    60 
    61 		*bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
    62 								*bytes);
    63 
    64 		if (*bytes == 0) { // error or 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 {
    81 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    82 
    83 	if (SDL_RWseek (data->sdl_src, absolute_byte_offset, RW_SEEK_SET) < 0) {
    84 		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    85 	}
    86 	else {
    87 		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    88 	}
    89 }
    90 
    91 static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    92 									const FLAC__StreamDecoder *decoder,
    93 									FLAC__uint64 *absolute_byte_offset,
    94 									void *client_data)
    95 {
    96 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    97 
    98 	int pos = SDL_RWtell (data->sdl_src);
    99 
   100 	if (pos < 0) {
   101 		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   102 	}
   103 	else {
   104 		*absolute_byte_offset = (FLAC__uint64)pos;
   105 		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   106 	}
   107 }
   108 
   109 static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   110 									const FLAC__StreamDecoder *decoder,
   111 									FLAC__uint64 *stream_length,
   112 									void *client_data)
   113 {
   114 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   115 
   116 	int pos = SDL_RWtell (data->sdl_src);
   117 	int length = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   118 
   119 	if (SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET) != pos || length < 0) {
   120 		/* there was an error attempting to return the stream to the original
   121 		 * position, or the length was invalid. */
   122 		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   123 	}
   124 	else {
   125 		*stream_length = (FLAC__uint64)length;
   126 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   127 	}
   128 }
   129 
   130 static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   131 									void *client_data)
   132 {
   133 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   134 
   135 	int pos = SDL_RWtell (data->sdl_src);
   136 	int end = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   137 
   138 	// was the original position equal to the end (a.k.a. the seek didn't move)?
   139 	if (pos == end) {
   140 		// must be EOF
   141 		return true;
   142 	}
   143 	else {
   144 		// not EOF, return to the original position
   145 		SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET);
   146 
   147 		return false;
   148 	}
   149 }
   150 
   151 static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   152 									const FLAC__StreamDecoder *decoder,
   153 									const FLAC__Frame *frame,
   154 									const FLAC__int32 *const buffer[],
   155 									void *client_data)
   156 {
   157 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   158 	size_t i;
   159 	Uint8 *buf;
   160 
   161 	if (data->flac_total_samples == 0) {
   162 		SDL_SetError ("Given FLAC file does not specify its sample count.");
   163 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   164 	}
   165 
   166 	if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   167 		SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   168 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   169 	}
   170 
   171 	// check if it is the first audio frame so we can initialize the output
   172 	// buffer
   173 	if (frame->header.number.sample_number == 0) {
   174 		*(data->sdl_audio_len) = data->sdl_spec->size;
   175 		data->sdl_audio_read = 0;
   176     	*(data->sdl_audio_buf) = SDL_malloc (*(data->sdl_audio_len));
   177 
   178     	if (*(data->sdl_audio_buf) == NULL) {
   179     		SDL_SetError
   180 					("Unable to allocate memory to store the FLAC stream.");
   181     		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   182     	}
   183 	}
   184 
   185 	buf = *(data->sdl_audio_buf);
   186 
   187 	for (i = 0; i < frame->header.blocksize; i++) {
   188 		FLAC__int16 i16;
   189 		FLAC__uint16 ui16;
   190 
   191 		i16 = (FLAC__int16)buffer[0][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 		i16 = (FLAC__int16)buffer[1][i];
   198 		ui16 = (FLAC__uint16)i16;
   199 
   200 		*(buf + (data->sdl_audio_read++)) = (char)(ui16);
   201 		*(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   202 	}
   203 
   204 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   205 }
   206 
   207 static void flac_metadata_load_cb(
   208 					const FLAC__StreamDecoder *decoder,
   209 					const FLAC__StreamMetadata *metadata,
   210 					void *client_data)
   211 {
   212 	FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   213 	FLAC__uint64 total_samples;
   214 	unsigned bps;
   215 
   216 	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   217 		// save the metadata right now for use later on
   218 		*(data->sdl_audio_buf) = NULL;
   219 		*(data->sdl_audio_len) = 0;
   220 		memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
   221 
   222 		data->sdl_spec->format = AUDIO_S16;
   223 		data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
   224 		data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
   225 		data->sdl_spec->samples = 8192; /* buffer size */
   226 
   227 		total_samples = metadata->data.stream_info.total_samples;
   228 		bps = metadata->data.stream_info.bits_per_sample;
   229 
   230 		data->sdl_spec->size = total_samples * data->sdl_spec->channels *
   231 								(bps / 8);
   232 		data->flac_total_samples = total_samples;
   233 		data->flac_bps = bps;
   234 	}
   235 }
   236 
   237 static void flac_error_load_cb(
   238 				const FLAC__StreamDecoder *decoder,
   239 				FLAC__StreamDecoderErrorStatus status,
   240 				void *client_data)
   241 {
   242 	// print an SDL error based on the error status
   243 	switch (status) {
   244 		case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   245 			SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
   246 		break;
   247 		case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   248 			SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
   249 		break;
   250 		case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   251 			SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
   252 		break;
   253 		case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   254 			SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
   255 		break;
   256 		default:
   257 			SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
   258 		break;
   259 	}
   260 }
   261 
   262 /* don't call this directly; use Mix_LoadWAV_RW() for now. */
   263 SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
   264         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
   265 {
   266 	FLAC__StreamDecoder *decoder = 0;
   267 	FLAC__StreamDecoderInitStatus init_status;
   268 	int was_error = 1;
   269 	int was_init = 0;
   270 	Uint32 samplesize;
   271 
   272 	// create the client data passing information
   273 	FLAC_SDL_Data* client_data;
   274 	client_data = (FLAC_SDL_Data *)SDL_malloc (sizeof (FLAC_SDL_Data));
   275 
   276 	if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   277 		goto done;
   278 
   279 	if (!Mix_Init(MIX_INIT_FLAC))
   280 		goto done;
   281 
   282 	if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   283 		SDL_SetError ("Unable to allocate FLAC decoder.");
   284 		goto done;
   285 	}
   286 
   287 	init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   288 								flac_read_load_cb, flac_seek_load_cb,
   289 								flac_tell_load_cb, flac_length_load_cb,
   290 								flac_eof_load_cb, flac_write_load_cb,
   291 								flac_metadata_load_cb, flac_error_load_cb,
   292 								client_data);
   293 
   294 	if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   295 		SDL_SetError ("Unable to initialize FLAC stream decoder.");
   296 		goto done;
   297 	}
   298 
   299 	was_init = 1;
   300 
   301 	client_data->sdl_src = src;
   302 	client_data->sdl_spec = spec;
   303 	client_data->sdl_audio_buf = audio_buf;
   304 	client_data->sdl_audio_len = audio_len;
   305 
   306 	if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   307 		SDL_SetError ("Unable to process FLAC file.");
   308 		goto done;
   309 	}
   310 
   311 	was_error = 0;
   312 
   313 	/* Don't return a buffer that isn't a multiple of samplesize */
   314 	samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   315 	*audio_len &= ~(samplesize - 1);
   316 
   317 done:
   318 	if (was_init && decoder) {
   319 		flac.FLAC__stream_decoder_finish (decoder);
   320 	}
   321 
   322 	if (decoder) {
   323 		flac.FLAC__stream_decoder_delete (decoder);
   324 	}
   325 
   326 	if (src) {
   327 		if (freesrc)
   328 			SDL_RWclose (src);
   329 		else
   330 			SDL_RWseek (src, 0, RW_SEEK_SET);
   331 	}
   332 
   333 	if (was_error)
   334 		spec = NULL;
   335 
   336     return spec;
   337 }
   338 
   339 #endif // FLAC_MUSIC