src/codecs/music_flac.c
author Ozkan Sezer
Wed, 18 Dec 2019 15:51:40 +0300
changeset 1093 6f0bea2ab267
parent 1090 543b77a3c0eb
child 1099 a3c637d1a698
permissions -rw-r--r--
load_voc.c, music_flac.c: fix implicit-fallthrough warnings.
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2019 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 file is used to support SDL_LoadMUS playback of FLAC files.
    22     ~ Austen Dicken (admin@cvpcs.org)
    23 */
    24 
    25 #ifdef MUSIC_FLAC
    26 
    27 #include "SDL_assert.h"
    28 #include "SDL_loadso.h"
    29 
    30 #include "music_flac.h"
    31 
    32 #include <FLAC/stream_decoder.h>
    33 
    34 
    35 typedef struct {
    36     int loaded;
    37     void *handle;
    38     FLAC__StreamDecoder *(*FLAC__stream_decoder_new)(void);
    39     void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder);
    40     FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)(
    41                         FLAC__StreamDecoder *decoder,
    42                         FLAC__StreamDecoderReadCallback read_callback,
    43                         FLAC__StreamDecoderSeekCallback seek_callback,
    44                         FLAC__StreamDecoderTellCallback tell_callback,
    45                         FLAC__StreamDecoderLengthCallback length_callback,
    46                         FLAC__StreamDecoderEofCallback eof_callback,
    47                         FLAC__StreamDecoderWriteCallback write_callback,
    48                         FLAC__StreamDecoderMetadataCallback metadata_callback,
    49                         FLAC__StreamDecoderErrorCallback error_callback,
    50                         void *client_data);
    51     FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder);
    52     FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder);
    53     FLAC__bool (*FLAC__stream_decoder_process_single)(
    54                         FLAC__StreamDecoder *decoder);
    55     FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(
    56                         FLAC__StreamDecoder *decoder);
    57     FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(
    58                         FLAC__StreamDecoder *decoder);
    59     FLAC__bool (*FLAC__stream_decoder_seek_absolute)(
    60                         FLAC__StreamDecoder *decoder,
    61                         FLAC__uint64 sample);
    62     FLAC__StreamDecoderState (*FLAC__stream_decoder_get_state)(
    63                         const FLAC__StreamDecoder *decoder);
    64     FLAC__uint64 (*FLAC__stream_decoder_get_total_samples)(
    65                         const FLAC__StreamDecoder *decoder);
    66     FLAC__bool (*FLAC__stream_decoder_set_metadata_respond)(
    67                         FLAC__StreamDecoder *decoder,
    68                         FLAC__MetadataType type);
    69 } flac_loader;
    70 
    71 static flac_loader flac = {
    72     0, NULL
    73 };
    74 
    75 #ifdef FLAC_DYNAMIC
    76 #define FUNCTION_LOADER(FUNC, SIG) \
    77     flac.FUNC = (SIG) SDL_LoadFunction(flac.handle, #FUNC); \
    78     if (flac.FUNC == NULL) { SDL_UnloadObject(flac.handle); return -1; }
    79 #else
    80 #define FUNCTION_LOADER(FUNC, SIG) \
    81     flac.FUNC = FUNC;
    82 #endif
    83 
    84 static int FLAC_Load(void)
    85 {
    86     if (flac.loaded == 0) {
    87 #ifdef FLAC_DYNAMIC
    88         flac.handle = SDL_LoadObject(FLAC_DYNAMIC);
    89         if (flac.handle == NULL) {
    90             return -1;
    91         }
    92 #elif defined(__MACOSX__)
    93         extern FLAC__StreamDecoder *FLAC__stream_decoder_new(void) __attribute__((weak_import));
    94         if (FLAC__stream_decoder_new == NULL)
    95         {
    96             /* Missing weakly linked framework */
    97             Mix_SetError("Missing FLAC.framework");
    98             return -1;
    99         }
   100 #endif
   101 
   102         FUNCTION_LOADER(FLAC__stream_decoder_new, FLAC__StreamDecoder *(*)(void))
   103         FUNCTION_LOADER(FLAC__stream_decoder_delete, void (*)(FLAC__StreamDecoder *))
   104         FUNCTION_LOADER(FLAC__stream_decoder_init_stream, FLAC__StreamDecoderInitStatus (*)(
   105                         FLAC__StreamDecoder *,
   106                         FLAC__StreamDecoderReadCallback,
   107                         FLAC__StreamDecoderSeekCallback,
   108                         FLAC__StreamDecoderTellCallback,
   109                         FLAC__StreamDecoderLengthCallback,
   110                         FLAC__StreamDecoderEofCallback,
   111                         FLAC__StreamDecoderWriteCallback,
   112                         FLAC__StreamDecoderMetadataCallback,
   113                         FLAC__StreamDecoderErrorCallback,
   114                         void *))
   115         FUNCTION_LOADER(FLAC__stream_decoder_finish, FLAC__bool (*)(FLAC__StreamDecoder *))
   116         FUNCTION_LOADER(FLAC__stream_decoder_flush, FLAC__bool (*)(FLAC__StreamDecoder *))
   117         FUNCTION_LOADER(FLAC__stream_decoder_process_single, FLAC__bool (*)(FLAC__StreamDecoder *))
   118         FUNCTION_LOADER(FLAC__stream_decoder_process_until_end_of_metadata, FLAC__bool (*)(FLAC__StreamDecoder *))
   119         FUNCTION_LOADER(FLAC__stream_decoder_process_until_end_of_stream, FLAC__bool (*)(FLAC__StreamDecoder *))
   120         FUNCTION_LOADER(FLAC__stream_decoder_seek_absolute, FLAC__bool (*)(FLAC__StreamDecoder *, FLAC__uint64))
   121         FUNCTION_LOADER(FLAC__stream_decoder_get_state, FLAC__StreamDecoderState (*)(const FLAC__StreamDecoder *decoder))
   122         FUNCTION_LOADER(FLAC__stream_decoder_get_total_samples,
   123                         FLAC__uint64 (*)(const FLAC__StreamDecoder *))
   124         FUNCTION_LOADER(FLAC__stream_decoder_set_metadata_respond,
   125                         FLAC__bool (*)(FLAC__StreamDecoder *,
   126                                        FLAC__MetadataType))
   127     }
   128     ++flac.loaded;
   129 
   130     return 0;
   131 }
   132 
   133 static void FLAC_Unload(void)
   134 {
   135     if (flac.loaded == 0) {
   136         return;
   137     }
   138     if (flac.loaded == 1) {
   139 #ifdef FLAC_DYNAMIC
   140         SDL_UnloadObject(flac.handle);
   141 #endif
   142     }
   143     --flac.loaded;
   144 }
   145 
   146 
   147 typedef struct {
   148     int volume;
   149     int play_count;
   150     FLAC__StreamDecoder *flac_decoder;
   151     unsigned sample_rate;
   152     unsigned channels;
   153     unsigned bits_per_sample;
   154     SDL_RWops *src;
   155     int freesrc;
   156     SDL_AudioStream *stream;
   157     int loop;
   158     FLAC__uint64 pcm_pos;
   159     FLAC__uint64 full_length;
   160     SDL_bool loop_flag;
   161     FLAC__uint64 loop_start;
   162     FLAC__uint64 loop_end;
   163     FLAC__uint64 loop_len;
   164 } FLAC_Music;
   165 
   166 
   167 static int FLAC_Seek(void *context, double position);
   168 
   169 static FLAC__StreamDecoderReadStatus flac_read_music_cb(
   170                                     const FLAC__StreamDecoder *decoder,
   171                                     FLAC__byte buffer[],
   172                                     size_t *bytes,
   173                                     void *client_data)
   174 {
   175     FLAC_Music *data = (FLAC_Music*)client_data;
   176 
   177     (void)decoder;
   178 
   179     /* make sure there is something to be reading */
   180     if (*bytes > 0) {
   181         *bytes = SDL_RWread (data->src, buffer, sizeof (FLAC__byte), *bytes);
   182 
   183         if (*bytes == 0) { /* error or no data was read (EOF) */
   184             return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
   185         } else { /* data was read, continue */
   186             return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
   187         }
   188     } else {
   189         return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
   190     }
   191 }
   192 
   193 static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
   194                                     const FLAC__StreamDecoder *decoder,
   195                                     FLAC__uint64 absolute_byte_offset,
   196                                     void *client_data)
   197 {
   198     FLAC_Music *data = (FLAC_Music*)client_data;
   199 
   200     (void)decoder;
   201 
   202     if (SDL_RWseek(data->src, (Sint64)absolute_byte_offset, RW_SEEK_SET) < 0) {
   203         return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
   204     } else {
   205         return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
   206     }
   207 }
   208 
   209 static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
   210                                     const FLAC__StreamDecoder *decoder,
   211                                     FLAC__uint64 *absolute_byte_offset,
   212                                     void *client_data)
   213 {
   214     FLAC_Music *data = (FLAC_Music*)client_data;
   215 
   216     Sint64 pos = SDL_RWtell(data->src);
   217 
   218     (void)decoder;
   219 
   220     if (pos < 0) {
   221         return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
   222     } else {
   223         *absolute_byte_offset = (FLAC__uint64)pos;
   224         return FLAC__STREAM_DECODER_TELL_STATUS_OK;
   225     }
   226 }
   227 
   228 static FLAC__StreamDecoderLengthStatus flac_length_music_cb(
   229                                     const FLAC__StreamDecoder *decoder,
   230                                     FLAC__uint64 *stream_length,
   231                                     void *client_data)
   232 {
   233     FLAC_Music *data = (FLAC_Music*)client_data;
   234 
   235     Sint64 pos = SDL_RWtell(data->src);
   236     Sint64 length = SDL_RWseek(data->src, 0, RW_SEEK_END);
   237 
   238     (void)decoder;
   239 
   240     if (SDL_RWseek(data->src, pos, RW_SEEK_SET) != pos || length < 0) {
   241         /* there was an error attempting to return the stream to the original
   242          * position, or the length was invalid. */
   243         return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
   244     } else {
   245         *stream_length = (FLAC__uint64)length;
   246         return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
   247     }
   248 }
   249 
   250 static FLAC__bool flac_eof_music_cb(
   251                                 const FLAC__StreamDecoder *decoder,
   252                                 void *client_data)
   253 {
   254     FLAC_Music *data = (FLAC_Music*)client_data;
   255 
   256     Sint64 pos = SDL_RWtell(data->src);
   257     Sint64 end = SDL_RWseek(data->src, 0, RW_SEEK_END);
   258 
   259     (void)decoder;
   260 
   261     /* was the original position equal to the end (a.k.a. the seek didn't move)? */
   262     if (pos == end) {
   263         /* must be EOF */
   264         return true;
   265     } else {
   266         /* not EOF, return to the original position */
   267         SDL_RWseek(data->src, pos, RW_SEEK_SET);
   268         return false;
   269     }
   270 }
   271 
   272 static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
   273                                     const FLAC__StreamDecoder *decoder,
   274                                     const FLAC__Frame *frame,
   275                                     const FLAC__int32 *const buffer[],
   276                                     void *client_data)
   277 {
   278     FLAC_Music *music = (FLAC_Music *)client_data;
   279     Sint16 *data;
   280     unsigned int i, j, channels;
   281     int shift_amount = 0, amount;
   282 
   283     (void)decoder;
   284 
   285     if (!music->stream) {
   286         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   287     }
   288 
   289     switch (music->bits_per_sample) {
   290     case 16:
   291         shift_amount = 0;
   292         break;
   293     case 20:
   294         shift_amount = 4;
   295         break;
   296     case 24:
   297         shift_amount = 8;
   298         break;
   299     default:
   300         SDL_SetError("FLAC decoder doesn't support %d bits_per_sample", music->bits_per_sample);
   301         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   302     }
   303 
   304     if (music->channels == 3) {
   305         /* We'll just drop the center channel for now */
   306         channels = 2;
   307     } else {
   308         channels = music->channels;
   309     }
   310 
   311     data = SDL_stack_alloc(Sint16, (frame->header.blocksize * channels));
   312     if (!data) {
   313         SDL_SetError("Couldn't allocate %d bytes stack memory", (int)(frame->header.blocksize * channels * sizeof(*data)));
   314         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   315     }
   316     if (music->channels == 3) {
   317         Sint16 *dst = data;
   318         for (i = 0; i < frame->header.blocksize; ++i) {
   319             Sint16 FL = (Sint16)(buffer[0][i] >> shift_amount);
   320             Sint16 FR = (Sint16)(buffer[1][i] >> shift_amount);
   321             Sint16 FCmix = (Sint16)((buffer[2][i] >> shift_amount) * 0.5f);
   322             int sample;
   323 
   324             sample = (FL + FCmix);
   325             if (sample > SDL_MAX_SINT16) {
   326                 *dst = SDL_MAX_SINT16;
   327             } else if (sample < SDL_MIN_SINT16) {
   328                 *dst = SDL_MIN_SINT16;
   329             } else {
   330                 *dst = (Sint16)sample;
   331             }
   332             ++dst;
   333 
   334             sample = (FR + FCmix);
   335             if (sample > SDL_MAX_SINT16) {
   336                 *dst = SDL_MAX_SINT16;
   337             } else if (sample < SDL_MIN_SINT16) {
   338                 *dst = SDL_MIN_SINT16;
   339             } else {
   340                 *dst = (Sint16)sample;
   341             }
   342             ++dst;
   343         }
   344     } else {
   345         for (i = 0; i < channels; ++i) {
   346             Sint16 *dst = data + i;
   347             for (j = 0; j < frame->header.blocksize; ++j) {
   348                 *dst = (Sint16)(buffer[i][j] >> shift_amount);
   349                 dst += channels;
   350             }
   351         }
   352     }
   353     amount = (int)(frame->header.blocksize * channels * sizeof(*data));
   354     music->pcm_pos += (FLAC__uint64) frame->header.blocksize;
   355     if ((music->loop == 1) && (music->play_count != 1) &&
   356         (music->pcm_pos >= music->loop_end)) {
   357         amount -= (music->pcm_pos - music->loop_end) * channels * sizeof(*data);
   358         music->loop_flag = SDL_TRUE;
   359     }
   360 
   361     SDL_AudioStreamPut(music->stream, data, amount);
   362     SDL_stack_free(data);
   363 
   364     return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
   365 }
   366 
   367 /* Parse time string of the form HH:MM:SS.mmm and return equivalent sample
   368  * position */
   369 static FLAC__uint64 parse_time(char *time, unsigned samplerate_hz)
   370 {
   371     char *num_start, *p;
   372     FLAC__uint64 result = 0;
   373     char c;
   374 
   375     /* Time is directly expressed as a sample position */
   376     if (SDL_strchr(time, ':') == NULL) {
   377         return SDL_strtoull(time, NULL, 10);
   378     }
   379 
   380     result = 0;
   381     num_start = time;
   382 
   383     for (p = time; *p != '\0'; ++p) {
   384         if (*p == '.' || *p == ':') {
   385             c = *p; *p = '\0';
   386             result = result * 60 + SDL_atoi(num_start);
   387             num_start = p + 1;
   388             *p = c;
   389         }
   390 
   391         if (*p == '.') {
   392             return result * samplerate_hz
   393                 + (FLAC__uint64) (SDL_atof(p) * samplerate_hz);
   394         }
   395     }
   396 
   397     return (result * 60 + SDL_atoi(num_start)) * samplerate_hz;
   398 }
   399 
   400 static void flac_metadata_music_cb(
   401                     const FLAC__StreamDecoder *decoder,
   402                     const FLAC__StreamMetadata *metadata,
   403                     void *client_data)
   404 {
   405     FLAC_Music *music = (FLAC_Music *)client_data;
   406     const FLAC__StreamMetadata_VorbisComment *vc;
   407     int channels;
   408     unsigned rate;
   409     char *param, *argument, *value;
   410     SDL_bool is_loop_length = SDL_FALSE;
   411 
   412     (void)decoder;
   413 
   414     if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
   415         music->sample_rate = metadata->data.stream_info.sample_rate;
   416         music->channels = metadata->data.stream_info.channels;
   417         music->bits_per_sample = metadata->data.stream_info.bits_per_sample;
   418       /*printf("FLAC: Sample rate = %d, channels = %d, bits_per_sample = %d\n", music->sample_rate, music->channels, music->bits_per_sample);*/
   419 
   420         /* SDL's channel mapping and FLAC channel mapping are the same,
   421            except for 3 channels: SDL is FL FR LFE and FLAC is FL FR FC
   422          */
   423         if (music->channels == 3) {
   424             channels = 2;
   425         } else {
   426             channels = (int)music->channels;
   427         }
   428 
   429         /* We check for NULL stream later when we get data */
   430         SDL_assert(!music->stream);
   431         music->stream = SDL_NewAudioStream(AUDIO_S16SYS, (Uint8)channels, (int)music->sample_rate,
   432                                           music_spec.format, music_spec.channels, music_spec.freq);
   433     } else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
   434         FLAC__uint32 i;
   435 
   436         vc  = &metadata->data.vorbis_comment;
   437         rate = music->sample_rate;
   438 
   439         for (i = 0; i < vc->num_comments; ++i) {
   440             param = SDL_strdup((const char *) vc->comments[i].entry);
   441             argument = param;
   442             value = SDL_strchr(param, '=');
   443 
   444             if (value == NULL) {
   445                 value = param + SDL_strlen(param);
   446             } else {
   447                 *(value++) = '\0';
   448             }
   449 
   450             /* Want to match LOOP-START, LOOP_START, etc. Remove - or _ from
   451              * string if it is present at position 4. */
   452 
   453             if ((argument[4] == '_') || (argument[4] == '-')) {
   454                 SDL_memmove(argument + 4, argument + 5,
   455                            SDL_strlen(argument) - 4);
   456             }
   457 
   458             if (SDL_strcasecmp(argument, "LOOPSTART") == 0)
   459                 music->loop_start = parse_time(value, rate);
   460             else if (SDL_strcasecmp(argument, "LOOPLENGTH") == 0) {
   461                 music->loop_len = SDL_strtoull(value, NULL, 10);
   462                 is_loop_length = SDL_TRUE;
   463             } else if (SDL_strcasecmp(argument, "LOOPEND") == 0) {
   464                 music->loop_end = parse_time(value, rate);
   465                 is_loop_length = SDL_FALSE;
   466             }
   467             SDL_free(param);
   468         }
   469 
   470         if (is_loop_length) {
   471             music->loop_end = music->loop_start + music->loop_len;
   472         } else {
   473             music->loop_len = music->loop_end - music->loop_start;
   474         }
   475     }
   476 }
   477 
   478 static void flac_error_music_cb(
   479                 const FLAC__StreamDecoder *decoder,
   480                 FLAC__StreamDecoderErrorStatus status,
   481                 void *client_data)
   482 {
   483     (void)decoder;
   484     (void)client_data;
   485 
   486     /* print an SDL error based on the error status */
   487     switch (status) {
   488     case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
   489         SDL_SetError("Error processing the FLAC file [LOST_SYNC].");
   490         break;
   491     case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
   492         SDL_SetError("Error processing the FLAC file [BAD_HEADER].");
   493         break;
   494     case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
   495         SDL_SetError("Error processing the FLAC file [CRC_MISMATCH].");
   496         break;
   497     case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
   498         SDL_SetError("Error processing the FLAC file [UNPARSEABLE].");
   499         break;
   500     default:
   501         SDL_SetError("Error processing the FLAC file [UNKNOWN].");
   502         break;
   503     }
   504 }
   505 
   506 /* Load an FLAC stream from an SDL_RWops object */
   507 static void *FLAC_CreateFromRW(SDL_RWops *src, int freesrc)
   508 {
   509     FLAC_Music *music;
   510     int init_stage = 0;
   511     int was_error = 1;
   512     FLAC__uint64 full_length;
   513 
   514     music = (FLAC_Music *)SDL_calloc(1, sizeof(*music));
   515     if (!music) {
   516         SDL_OutOfMemory();
   517         return NULL;
   518     }
   519     music->src = src;
   520     music->volume = MIX_MAX_VOLUME;
   521     music->loop = -1;
   522     music->loop_start = -1;
   523     music->loop_end = 0;
   524     music->loop_len = 0;
   525     music->loop_flag = SDL_FALSE;
   526     music->pcm_pos = 0;
   527 
   528     music->flac_decoder = flac.FLAC__stream_decoder_new();
   529     if (music->flac_decoder) {
   530         init_stage++; /* stage 1! */
   531         flac.FLAC__stream_decoder_set_metadata_respond(music->flac_decoder,
   532                     FLAC__METADATA_TYPE_VORBIS_COMMENT);
   533 
   534         if (flac.FLAC__stream_decoder_init_stream(
   535                     music->flac_decoder,
   536                     flac_read_music_cb, flac_seek_music_cb,
   537                     flac_tell_music_cb, flac_length_music_cb,
   538                     flac_eof_music_cb, flac_write_music_cb,
   539                     flac_metadata_music_cb, flac_error_music_cb,
   540                     music) == FLAC__STREAM_DECODER_INIT_STATUS_OK) {
   541             init_stage++; /* stage 2! */
   542 
   543             if (flac.FLAC__stream_decoder_process_until_end_of_metadata(music->flac_decoder)) {
   544                 was_error = 0;
   545             } else {
   546                 SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
   547             }
   548         } else {
   549             SDL_SetError("FLAC__stream_decoder_init_stream() failed");
   550         }
   551     } else {
   552         SDL_SetError("FLAC__stream_decoder_new() failed");
   553     }
   554 
   555     if (was_error) {
   556         switch (init_stage) {
   557             case 2:
   558                 flac.FLAC__stream_decoder_finish(music->flac_decoder); /* fallthrough */
   559             case 1:
   560                 flac.FLAC__stream_decoder_delete(music->flac_decoder); /* fallthrough */
   561             case 0:
   562                 SDL_free(music);
   563                 break;
   564         }
   565         return NULL;
   566     }
   567 
   568     /* loop_start, loop_end and loop_len get set by metadata callback if tags
   569      * are present in metadata.
   570      */
   571     full_length = flac.FLAC__stream_decoder_get_total_samples(music->flac_decoder);
   572     if (((music->loop_start >= 0) || (music->loop_end > 0)) &&
   573         ((music->loop_start < music->loop_end) || (music->loop_end > 0)) &&
   574          (music->loop_start < full_length) &&
   575          (music->loop_end <= full_length)) {
   576         if (music->loop_start < 0) music->loop_start = 0;
   577         if (music->loop_end == 0) music->loop_end = full_length;
   578         music->loop = 1;
   579     }
   580 
   581     music->full_length = full_length;
   582     music->freesrc = freesrc;
   583     return music;
   584 }
   585 
   586 /* Set the volume for an FLAC stream */
   587 static void FLAC_SetVolume(void *context, int volume)
   588 {
   589     FLAC_Music *music = (FLAC_Music *)context;
   590     music->volume = volume;
   591 }
   592 
   593 /* Start playback of a given FLAC stream */
   594 static int FLAC_Play(void *context, int play_count)
   595 {
   596     FLAC_Music *music = (FLAC_Music *)context;
   597     music->play_count = play_count;
   598     return FLAC_Seek(music, 0.0);
   599 }
   600 
   601 /* Read some FLAC stream data and convert it for output */
   602 static int FLAC_GetSome(void *context, void *data, int bytes, SDL_bool *done)
   603 {
   604     FLAC_Music *music = (FLAC_Music *)context;
   605     int filled;
   606 
   607     filled = SDL_AudioStreamGet(music->stream, data, bytes);
   608     if (filled != 0) {
   609         return filled;
   610     }
   611 
   612     if (!music->play_count) {
   613         /* All done */
   614         *done = SDL_TRUE;
   615         return 0;
   616     }
   617 
   618     if (!flac.FLAC__stream_decoder_process_single(music->flac_decoder)) {
   619         SDL_SetError("FLAC__stream_decoder_process_single() failed");
   620         return -1;
   621     }
   622 
   623     if (music->loop_flag) {
   624         music->pcm_pos = music->loop_start;
   625         if (flac.FLAC__stream_decoder_seek_absolute(music->flac_decoder, music->loop_start) ==
   626                 FLAC__STREAM_DECODER_SEEK_ERROR) {
   627             SDL_SetError("FLAC__stream_decoder_seek_absolute() failed");
   628             flac.FLAC__stream_decoder_flush(music->flac_decoder);
   629             return -1;
   630         } else {
   631             int play_count = -1;
   632             if (music->play_count > 0) {
   633                 play_count = (music->play_count - 1);
   634             }
   635             music->play_count = play_count;
   636             music->loop_flag = SDL_FALSE;
   637         }
   638     }
   639 
   640     if (flac.FLAC__stream_decoder_get_state(music->flac_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) {
   641         if (music->play_count == 1) {
   642             music->play_count = 0;
   643             SDL_AudioStreamFlush(music->stream);
   644         } else {
   645             int play_count = -1;
   646             if (music->play_count > 0) {
   647                 play_count = (music->play_count - 1);
   648             }
   649             if (FLAC_Play(music, play_count) < 0) {
   650                 return -1;
   651             }
   652         }
   653     }
   654     return 0;
   655 }
   656 
   657 /* Play some of a stream previously started with FLAC_play() */
   658 static int FLAC_GetAudio(void *context, void *data, int bytes)
   659 {
   660     FLAC_Music *music = (FLAC_Music *)context;
   661     return music_pcm_getaudio(context, data, bytes, music->volume, FLAC_GetSome);
   662 }
   663 
   664 /* Jump (seek) to a given position (position is in seconds) */
   665 static int FLAC_Seek(void *context, double position)
   666 {
   667     FLAC_Music *music = (FLAC_Music *)context;
   668     FLAC__uint64 seek_sample = (FLAC__uint64) (music->sample_rate * position);
   669 
   670     SDL_AudioStreamClear(music->stream);
   671     music->pcm_pos = seek_sample;
   672     if (!flac.FLAC__stream_decoder_seek_absolute(music->flac_decoder, seek_sample)) {
   673         if (flac.FLAC__stream_decoder_get_state(music->flac_decoder) == FLAC__STREAM_DECODER_SEEK_ERROR) {
   674             flac.FLAC__stream_decoder_flush(music->flac_decoder);
   675         }
   676 
   677         SDL_SetError("Seeking of FLAC stream failed: libFLAC seek failed.");
   678         return -1;
   679     }
   680     return 0;
   681 }
   682 
   683 /* Return music duration in seconds */
   684 static double FLAC_Duration(void *context)
   685 {
   686     FLAC_Music *music = (FLAC_Music *)context;
   687     return (double)music->full_length / music->sample_rate;
   688 }
   689 
   690 /* Close the given FLAC_Music object */
   691 static void FLAC_Delete(void *context)
   692 {
   693     FLAC_Music *music = (FLAC_Music *)context;
   694     if (music) {
   695         if (music->flac_decoder) {
   696             flac.FLAC__stream_decoder_finish(music->flac_decoder);
   697             flac.FLAC__stream_decoder_delete(music->flac_decoder);
   698         }
   699         if (music->stream) {
   700             SDL_FreeAudioStream(music->stream);
   701         }
   702         if (music->freesrc) {
   703             SDL_RWclose(music->src);
   704         }
   705         SDL_free(music);
   706     }
   707 }
   708 
   709 Mix_MusicInterface Mix_MusicInterface_FLAC =
   710 {
   711     "FLAC",
   712     MIX_MUSIC_FLAC,
   713     MUS_FLAC,
   714     SDL_FALSE,
   715     SDL_FALSE,
   716 
   717     FLAC_Load,
   718     NULL,   /* Open */
   719     FLAC_CreateFromRW,
   720     NULL,   /* CreateFromFile */
   721     FLAC_SetVolume,
   722     FLAC_Play,
   723     NULL,   /* IsPlaying */
   724     FLAC_GetAudio,
   725     FLAC_Seek,
   726     FLAC_Duration,
   727     NULL,   /* Pause */
   728     NULL,   /* Resume */
   729     NULL,   /* Stop */
   730     FLAC_Delete,
   731     NULL,   /* Close */
   732     FLAC_Unload
   733 };
   734 
   735 #endif /* MUSIC_FLAC */
   736 
   737 /* vi: set ts=4 sw=4 expandtab: */