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