load_flac.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Jan 2016 22:12:31 -0800
changeset 712 7e59d684b070
parent 711 f40c5ac95b12
child 725 bdf7b8d20566
permissions -rw-r--r--
Updated to version 2.0.1
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2016 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         } else { // data was read, continue
    67             return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
    68         }
    69     } else {
    70         return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
    71     }
    72 }
    73 
    74 static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
    75                                     const FLAC__StreamDecoder *decoder,
    76                                     FLAC__uint64 absolute_byte_offset,
    77                                     void *client_data)
    78 {
    79     FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    80 
    81     if (SDL_RWseek (data->sdl_src, absolute_byte_offset, RW_SEEK_SET) < 0) {
    82         return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
    83     } else {
    84         return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
    85     }
    86 }
    87 
    88 static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
    89                                     const FLAC__StreamDecoder *decoder,
    90                                     FLAC__uint64 *absolute_byte_offset,
    91                                     void *client_data)
    92 {
    93     FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
    94 
    95     Sint64 pos = SDL_RWtell (data->sdl_src);
    96 
    97     if (pos < 0) {
    98         return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
    99     } else {
   100         *absolute_byte_offset = (FLAC__uint64)pos;
   101         return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   102     }
   103 }
   104 
   105 static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
   106                                     const FLAC__StreamDecoder *decoder,
   107                                     FLAC__uint64 *stream_length,
   108                                     void *client_data)
   109 {
   110     FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   111 
   112     Sint64 pos = SDL_RWtell (data->sdl_src);
   113     Sint64 length = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   114 
   115     if (SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET) != pos || length < 0) {
   116         /* there was an error attempting to return the stream to the original
   117          * position, or the length was invalid. */
   118         return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   119     } else {
   120         *stream_length = (FLAC__uint64)length;
   121         return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   122     }
   123 }
   124 
   125 static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
   126                                     void *client_data)
   127 {
   128     FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   129 
   130     Sint64 pos = SDL_RWtell (data->sdl_src);
   131     Sint64 end = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
   132 
   133     // was the original position equal to the end (a.k.a. the seek didn't move)?
   134     if (pos == end) {
   135         // must be EOF
   136         return true;
   137     } else {
   138         // not EOF, return to the original position
   139         SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET);
   140         return false;
   141     }
   142 }
   143 
   144 static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
   145                                     const FLAC__StreamDecoder *decoder,
   146                                     const FLAC__Frame *frame,
   147                                     const FLAC__int32 *const buffer[],
   148                                     void *client_data)
   149 {
   150     FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
   151     size_t i;
   152     Uint8 *buf;
   153 
   154     if (data->flac_total_samples == 0) {
   155         SDL_SetError ("Given FLAC file does not specify its sample count.");
   156         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   157     }
   158 
   159     if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
   160         SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
   161         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   162     }
   163 
   164     // check if it is the first audio frame so we can initialize the output
   165     // buffer
   166     if (frame->header.number.sample_number == 0) {
   167         *(data->sdl_audio_len) = data->sdl_spec->size;
   168         data->sdl_audio_read = 0;
   169         *(data->sdl_audio_buf) = SDL_malloc (*(data->sdl_audio_len));
   170 
   171         if (*(data->sdl_audio_buf) == NULL) {
   172             SDL_SetError
   173                     ("Unable to allocate memory to store the FLAC stream.");
   174             return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   175         }
   176     }
   177 
   178     buf = *(data->sdl_audio_buf);
   179 
   180     for (i = 0; i < frame->header.blocksize; i++) {
   181         FLAC__int16 i16;
   182         FLAC__uint16 ui16;
   183 
   184         i16 = (FLAC__int16)buffer[0][i];
   185         ui16 = (FLAC__uint16)i16;
   186 
   187         *(buf + (data->sdl_audio_read++)) = (char)(ui16);
   188         *(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   189 
   190         i16 = (FLAC__int16)buffer[1][i];
   191         ui16 = (FLAC__uint16)i16;
   192 
   193         *(buf + (data->sdl_audio_read++)) = (char)(ui16);
   194         *(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
   195     }
   196 
   197     return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   198 }
   199 
   200 static void flac_metadata_load_cb(
   201                     const FLAC__StreamDecoder *decoder,
   202                     const FLAC__StreamMetadata *metadata,
   203                     void *client_data)
   204 {
   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 = (Uint32)(total_samples * data->sdl_spec->channels * (bps / 8));
   224         data->flac_total_samples = total_samples;
   225         data->flac_bps = bps;
   226     }
   227 }
   228 
   229 static void flac_error_load_cb(
   230                 const FLAC__StreamDecoder *decoder,
   231                 FLAC__StreamDecoderErrorStatus status,
   232                 void *client_data)
   233 {
   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 {
   258     FLAC__StreamDecoder *decoder = 0;
   259     FLAC__StreamDecoderInitStatus init_status;
   260     int was_error = 1;
   261     int was_init = 0;
   262     Uint32 samplesize;
   263 
   264     // create the client data passing information
   265     FLAC_SDL_Data* client_data;
   266     client_data = (FLAC_SDL_Data *)SDL_malloc (sizeof (FLAC_SDL_Data));
   267 
   268     if ((!src) || (!audio_buf) || (!audio_len))   /* sanity checks. */
   269         goto done;
   270 
   271     if (!Mix_Init(MIX_INIT_FLAC))
   272         goto done;
   273 
   274     if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
   275         SDL_SetError ("Unable to allocate FLAC decoder.");
   276         goto done;
   277     }
   278 
   279     init_status = flac.FLAC__stream_decoder_init_stream (decoder,
   280                                 flac_read_load_cb, flac_seek_load_cb,
   281                                 flac_tell_load_cb, flac_length_load_cb,
   282                                 flac_eof_load_cb, flac_write_load_cb,
   283                                 flac_metadata_load_cb, flac_error_load_cb,
   284                                 client_data);
   285 
   286     if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   287         SDL_SetError ("Unable to initialize FLAC stream decoder.");
   288         goto done;
   289     }
   290 
   291     was_init = 1;
   292 
   293     client_data->sdl_src = src;
   294     client_data->sdl_spec = spec;
   295     client_data->sdl_audio_buf = audio_buf;
   296     client_data->sdl_audio_len = audio_len;
   297 
   298     if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
   299         SDL_SetError ("Unable to process FLAC file.");
   300         goto done;
   301     }
   302 
   303     was_error = 0;
   304 
   305     /* Don't return a buffer that isn't a multiple of samplesize */
   306     samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
   307     *audio_len &= ~(samplesize - 1);
   308 
   309 done:
   310     if (was_init && decoder) {
   311         flac.FLAC__stream_decoder_finish (decoder);
   312     }
   313 
   314     if (decoder) {
   315         flac.FLAC__stream_decoder_delete (decoder);
   316     }
   317 
   318     if (freesrc && src) {
   319         SDL_RWclose (src);
   320     }
   321 
   322     if (was_error) {
   323         spec = NULL;
   324     }
   325 
   326     return spec;
   327 }
   328 
   329 #endif // FLAC_MUSIC