music_flac.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 12 Nov 2018 16:54:24 -0800
changeset 925 5945988b4a41
parent 848 3907db698eb5
child 926 d6c9518fb5ee
permissions -rw-r--r--
Fixed bug 4371 - tvOS Simulator devices not listed

Caleb Cornett

In the Xcode-iOS project, when selecting the libSDL_mixer-tvOS target, no tvOS simulators appear in the available device dropdown.

This is easily fixed with the attached patch.
slouken@382
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@848
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@382
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@382
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@382
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@382
    20
slouken@518
    21
  This file is used to support SDL_LoadMUS playback of FLAC files.
slouken@617
    22
    ~ Austen Dicken (admin@cvpcs.org)
slouken@382
    23
*/
slouken@382
    24
slouken@777
    25
#ifdef MUSIC_FLAC
slouken@382
    26
slouken@797
    27
#include "SDL_assert.h"
slouken@777
    28
#include "SDL_loadso.h"
slouken@382
    29
slouken@382
    30
#include "music_flac.h"
slouken@382
    31
slouken@777
    32
#include <FLAC/stream_decoder.h>
slouken@382
    33
slouken@777
    34
slouken@777
    35
typedef struct {
slouken@777
    36
    int loaded;
slouken@777
    37
    void *handle;
slouken@788
    38
    FLAC__StreamDecoder *(*FLAC__stream_decoder_new)(void);
slouken@777
    39
    void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder);
slouken@777
    40
    FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)(
slouken@777
    41
                        FLAC__StreamDecoder *decoder,
slouken@777
    42
                        FLAC__StreamDecoderReadCallback read_callback,
slouken@777
    43
                        FLAC__StreamDecoderSeekCallback seek_callback,
slouken@777
    44
                        FLAC__StreamDecoderTellCallback tell_callback,
slouken@777
    45
                        FLAC__StreamDecoderLengthCallback length_callback,
slouken@777
    46
                        FLAC__StreamDecoderEofCallback eof_callback,
slouken@777
    47
                        FLAC__StreamDecoderWriteCallback write_callback,
slouken@777
    48
                        FLAC__StreamDecoderMetadataCallback metadata_callback,
slouken@777
    49
                        FLAC__StreamDecoderErrorCallback error_callback,
slouken@777
    50
                        void *client_data);
slouken@777
    51
    FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder);
slouken@777
    52
    FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder);
slouken@777
    53
    FLAC__bool (*FLAC__stream_decoder_process_single)(
slouken@777
    54
                        FLAC__StreamDecoder *decoder);
slouken@777
    55
    FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(
slouken@777
    56
                        FLAC__StreamDecoder *decoder);
slouken@777
    57
    FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(
slouken@777
    58
                        FLAC__StreamDecoder *decoder);
slouken@777
    59
    FLAC__bool (*FLAC__stream_decoder_seek_absolute)(
slouken@777
    60
                        FLAC__StreamDecoder *decoder,
slouken@777
    61
                        FLAC__uint64 sample);
slouken@777
    62
    FLAC__StreamDecoderState (*FLAC__stream_decoder_get_state)(
slouken@777
    63
                        const FLAC__StreamDecoder *decoder);
slouken@777
    64
} flac_loader;
slouken@777
    65
slouken@777
    66
static flac_loader flac = {
slouken@777
    67
    0, NULL
slouken@777
    68
};
slouken@777
    69
slouken@777
    70
#ifdef FLAC_DYNAMIC
slouken@798
    71
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    72
    flac.FUNC = (SIG) SDL_LoadFunction(flac.handle, #FUNC); \
slouken@798
    73
    if (flac.FUNC == NULL) { SDL_UnloadObject(flac.handle); return -1; }
slouken@798
    74
#else
slouken@798
    75
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    76
    flac.FUNC = FUNC;
slouken@798
    77
#endif
slouken@777
    78
slouken@785
    79
static int FLAC_Load(void)
slouken@409
    80
{
slouken@777
    81
    if (flac.loaded == 0) {
slouken@798
    82
#ifdef FLAC_DYNAMIC
slouken@777
    83
        flac.handle = SDL_LoadObject(FLAC_DYNAMIC);
slouken@777
    84
        if (flac.handle == NULL) {
slouken@777
    85
            return -1;
slouken@777
    86
        }
slouken@798
    87
#elif defined(__MACOSX__)
slouken@798
    88
        extern FLAC__StreamDecoder *FLAC__stream_decoder_new(void) __attribute__((weak_import));
slouken@798
    89
        if (FLAC__stream_decoder_new == NULL)
slouken@798
    90
        {
slouken@798
    91
            /* Missing weakly linked framework */
slouken@798
    92
            Mix_SetError("Missing FLAC.framework");
slouken@777
    93
            return -1;
slouken@777
    94
        }
slouken@798
    95
#endif
slouken@798
    96
slouken@798
    97
        FUNCTION_LOADER(FLAC__stream_decoder_new, FLAC__StreamDecoder *(*)(void))
slouken@798
    98
        FUNCTION_LOADER(FLAC__stream_decoder_delete, void (*)(FLAC__StreamDecoder *))
slouken@798
    99
        FUNCTION_LOADER(FLAC__stream_decoder_init_stream, FLAC__StreamDecoderInitStatus (*)(
slouken@777
   100
                        FLAC__StreamDecoder *,
slouken@777
   101
                        FLAC__StreamDecoderReadCallback,
slouken@777
   102
                        FLAC__StreamDecoderSeekCallback,
slouken@777
   103
                        FLAC__StreamDecoderTellCallback,
slouken@777
   104
                        FLAC__StreamDecoderLengthCallback,
slouken@777
   105
                        FLAC__StreamDecoderEofCallback,
slouken@777
   106
                        FLAC__StreamDecoderWriteCallback,
slouken@777
   107
                        FLAC__StreamDecoderMetadataCallback,
slouken@777
   108
                        FLAC__StreamDecoderErrorCallback,
slouken@777
   109
                        void *))
slouken@798
   110
        FUNCTION_LOADER(FLAC__stream_decoder_finish, FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@798
   111
        FUNCTION_LOADER(FLAC__stream_decoder_flush, FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@798
   112
        FUNCTION_LOADER(FLAC__stream_decoder_process_single, FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@798
   113
        FUNCTION_LOADER(FLAC__stream_decoder_process_until_end_of_metadata, FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@798
   114
        FUNCTION_LOADER(FLAC__stream_decoder_process_until_end_of_stream, FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@798
   115
        FUNCTION_LOADER(FLAC__stream_decoder_seek_absolute, FLAC__bool (*)(FLAC__StreamDecoder *, FLAC__uint64))
slouken@798
   116
        FUNCTION_LOADER(FLAC__stream_decoder_get_state, FLAC__StreamDecoderState (*)(const FLAC__StreamDecoder *decoder))
slouken@777
   117
    }
slouken@777
   118
    ++flac.loaded;
slouken@777
   119
slouken@777
   120
    return 0;
slouken@382
   121
}
slouken@382
   122
slouken@777
   123
static void FLAC_Unload(void)
slouken@409
   124
{
slouken@777
   125
    if (flac.loaded == 0) {
slouken@777
   126
        return;
slouken@777
   127
    }
slouken@777
   128
    if (flac.loaded == 1) {
slouken@798
   129
#ifdef FLAC_DYNAMIC
slouken@777
   130
        SDL_UnloadObject(flac.handle);
slouken@798
   131
#endif
slouken@777
   132
    }
slouken@777
   133
    --flac.loaded;
slouken@382
   134
}
slouken@382
   135
slouken@777
   136
slouken@777
   137
typedef struct {
slouken@797
   138
    int volume;
slouken@797
   139
    int play_count;
slouken@797
   140
    FLAC__StreamDecoder *flac_decoder;
slouken@777
   141
    unsigned sample_rate;
slouken@777
   142
    unsigned channels;
slouken@777
   143
    unsigned bits_per_sample;
slouken@777
   144
    SDL_RWops *src;
slouken@777
   145
    int freesrc;
slouken@797
   146
    SDL_AudioStream *stream;
slouken@797
   147
} FLAC_Music;
slouken@777
   148
slouken@777
   149
slouken@797
   150
static int FLAC_Seek(void *context, double position);
slouken@797
   151
slouken@382
   152
static FLAC__StreamDecoderReadStatus flac_read_music_cb(
slouken@617
   153
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   154
                                    FLAC__byte buffer[],
slouken@617
   155
                                    size_t *bytes,
slouken@617
   156
                                    void *client_data)
slouken@409
   157
{
slouken@797
   158
    FLAC_Music *data = (FLAC_Music*)client_data;
slouken@382
   159
slouken@797
   160
    /* make sure there is something to be reading */
slouken@617
   161
    if (*bytes > 0) {
slouken@625
   162
        *bytes = SDL_RWread (data->src, buffer, sizeof (FLAC__byte), *bytes);
slouken@382
   163
slouken@797
   164
        if (*bytes == 0) { /* error or no data was read (EOF) */
slouken@617
   165
            return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
slouken@797
   166
        } else { /* data was read, continue */
slouken@617
   167
            return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
slouken@617
   168
        }
slouken@621
   169
    } else {
slouken@617
   170
        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
slouken@617
   171
    }
slouken@382
   172
}
slouken@382
   173
slouken@382
   174
static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
slouken@617
   175
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   176
                                    FLAC__uint64 absolute_byte_offset,
slouken@617
   177
                                    void *client_data)
slouken@409
   178
{
slouken@797
   179
    FLAC_Music *data = (FLAC_Music*)client_data;
slouken@382
   180
slouken@797
   181
    if (SDL_RWseek(data->src, absolute_byte_offset, RW_SEEK_SET) < 0) {
slouken@617
   182
        return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
slouken@621
   183
    } else {
slouken@617
   184
        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
slouken@617
   185
    }
slouken@382
   186
}
slouken@382
   187
slouken@382
   188
static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
slouken@617
   189
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   190
                                    FLAC__uint64 *absolute_byte_offset,
slouken@777
   191
                                    void *client_data)
slouken@409
   192
{
slouken@797
   193
    FLAC_Music *data = (FLAC_Music*)client_data;
slouken@382
   194
slouken@797
   195
    Sint64 pos = SDL_RWtell(data->src);
slouken@382
   196
slouken@617
   197
    if (pos < 0) {
slouken@617
   198
        return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
slouken@621
   199
    } else {
slouken@617
   200
        *absolute_byte_offset = (FLAC__uint64)pos;
slouken@617
   201
        return FLAC__STREAM_DECODER_TELL_STATUS_OK;
slouken@617
   202
    }
slouken@382
   203
}
slouken@382
   204
slouken@797
   205
static FLAC__StreamDecoderLengthStatus flac_length_music_cb(
slouken@617
   206
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   207
                                    FLAC__uint64 *stream_length,
slouken@617
   208
                                    void *client_data)
slouken@409
   209
{
slouken@797
   210
    FLAC_Music *data = (FLAC_Music*)client_data;
slouken@382
   211
slouken@797
   212
    Sint64 pos = SDL_RWtell(data->src);
slouken@797
   213
    Sint64 length = SDL_RWseek(data->src, 0, RW_SEEK_END);
slouken@382
   214
slouken@797
   215
    if (SDL_RWseek(data->src, pos, RW_SEEK_SET) != pos || length < 0) {
slouken@617
   216
        /* there was an error attempting to return the stream to the original
slouken@617
   217
         * position, or the length was invalid. */
slouken@617
   218
        return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
slouken@621
   219
    } else {
slouken@617
   220
        *stream_length = (FLAC__uint64)length;
slouken@617
   221
        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
slouken@617
   222
    }
slouken@382
   223
}
slouken@382
   224
slouken@382
   225
static FLAC__bool flac_eof_music_cb(
slouken@617
   226
                                const FLAC__StreamDecoder *decoder,
slouken@777
   227
                                void *client_data)
slouken@409
   228
{
slouken@797
   229
    FLAC_Music *data = (FLAC_Music*)client_data;
slouken@382
   230
slouken@797
   231
    Sint64 pos = SDL_RWtell(data->src);
slouken@797
   232
    Sint64 end = SDL_RWseek(data->src, 0, RW_SEEK_END);
slouken@382
   233
slouken@797
   234
    /* was the original position equal to the end (a.k.a. the seek didn't move)? */
slouken@617
   235
    if (pos == end) {
slouken@797
   236
        /* must be EOF */
slouken@617
   237
        return true;
slouken@621
   238
    } else {
slouken@797
   239
        /* not EOF, return to the original position */
slouken@797
   240
        SDL_RWseek(data->src, pos, RW_SEEK_SET);
slouken@617
   241
        return false;
slouken@617
   242
    }
slouken@382
   243
}
slouken@382
   244
slouken@382
   245
static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
slouken@617
   246
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   247
                                    const FLAC__Frame *frame,
slouken@617
   248
                                    const FLAC__int32 *const buffer[],
slouken@617
   249
                                    void *client_data)
slouken@409
   250
{
slouken@797
   251
    FLAC_Music *music = (FLAC_Music *)client_data;
slouken@797
   252
    Sint16 *data;
slouken@800
   253
    unsigned int i, j, channels;
slouken@797
   254
    int shift_amount = 0;
slouken@382
   255
slouken@797
   256
    if (!music->stream) {
slouken@617
   257
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   258
    }
slouken@382
   259
slouken@797
   260
    switch (music->bits_per_sample) {
slouken@797
   261
    case 16:
slouken@797
   262
        shift_amount = 0;
slouken@797
   263
        break;
slouken@797
   264
    case 20:
slouken@797
   265
        shift_amount = 4;
slouken@797
   266
        break;
slouken@797
   267
    case 24:
slouken@797
   268
        shift_amount = 8;
slouken@797
   269
        break;
slouken@797
   270
    default:
slouken@797
   271
        SDL_SetError("FLAC decoder doesn't support %d bits_per_sample", music->bits_per_sample);
slouken@617
   272
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   273
    }
slouken@382
   274
slouken@797
   275
    if (music->channels == 3) {
slouken@797
   276
        /* We'll just drop the center channel for now */
slouken@797
   277
        channels = 2;
slouken@797
   278
    } else {
slouken@797
   279
        channels = music->channels;
slouken@797
   280
    }
slouken@436
   281
slouken@797
   282
    data = SDL_stack_alloc(Sint16, (frame->header.blocksize * channels));
slouken@797
   283
    if (!data) {
slouken@797
   284
        SDL_SetError("Couldn't allocate %d bytes stack memory", (int)(frame->header.blocksize * channels * sizeof(*data)));
slouken@797
   285
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@797
   286
    }
slouken@797
   287
    if (music->channels == 3) {
slouken@797
   288
        Sint16 *dst = data;
slouken@797
   289
        for (i = 0; i < frame->header.blocksize; ++i) {
slouken@797
   290
            Sint16 FL = (buffer[0][i] >> shift_amount);
slouken@797
   291
            Sint16 FR = (buffer[1][i] >> shift_amount);
slouken@797
   292
            Sint16 FCmix = (Sint16)((buffer[2][i] >> shift_amount) * 0.5f);
slouken@797
   293
            int sample;
slouken@382
   294
slouken@797
   295
            sample = (FL + FCmix);
slouken@797
   296
            if (sample > SDL_MAX_SINT16) {
slouken@797
   297
                *dst = SDL_MAX_SINT16;
slouken@797
   298
            } else if (sample < SDL_MIN_SINT16) {
slouken@797
   299
                *dst = SDL_MIN_SINT16;
slouken@797
   300
            } else {
slouken@797
   301
                *dst = sample;
slouken@797
   302
            }
slouken@797
   303
            ++dst;
slouken@382
   304
slouken@797
   305
            sample = (FR + FCmix);
slouken@797
   306
            if (sample > SDL_MAX_SINT16) {
slouken@797
   307
                *dst = SDL_MAX_SINT16;
slouken@797
   308
            } else if (sample < SDL_MIN_SINT16) {
slouken@797
   309
                *dst = SDL_MIN_SINT16;
slouken@797
   310
            } else {
slouken@797
   311
                *dst = sample;
slouken@617
   312
            }
slouken@797
   313
            ++dst;
slouken@797
   314
        }
slouken@797
   315
    } else {
slouken@797
   316
        for (i = 0; i < channels; ++i) {
slouken@797
   317
            Sint16 *dst = data + i;
slouken@797
   318
            for (j = 0; j < frame->header.blocksize; ++j) {
slouken@797
   319
                *dst = (buffer[i][j] >> shift_amount);
slouken@797
   320
                dst += channels;
slouken@617
   321
            }
slouken@617
   322
        }
slouken@617
   323
    }
slouken@797
   324
    SDL_AudioStreamPut(music->stream, data, (frame->header.blocksize * channels * sizeof(*data)));
slouken@797
   325
    SDL_stack_free(data);
slouken@382
   326
slouken@617
   327
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
slouken@382
   328
}
slouken@382
   329
slouken@382
   330
static void flac_metadata_music_cb(
slouken@617
   331
                    const FLAC__StreamDecoder *decoder,
slouken@617
   332
                    const FLAC__StreamMetadata *metadata,
slouken@617
   333
                    void *client_data)
slouken@409
   334
{
slouken@797
   335
    FLAC_Music *music = (FLAC_Music *)client_data;
slouken@797
   336
    int channels;
slouken@382
   337
slouken@797
   338
    if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) {
slouken@797
   339
        return;
slouken@617
   340
    }
slouken@797
   341
slouken@797
   342
    music->sample_rate = metadata->data.stream_info.sample_rate;
slouken@797
   343
    music->channels = metadata->data.stream_info.channels;
slouken@797
   344
    music->bits_per_sample = metadata->data.stream_info.bits_per_sample;
slouken@797
   345
/*printf("FLAC: Sample rate = %d, channels = %d, bits_per_sample = %d\n", music->sample_rate, music->channels, music->bits_per_sample);*/
slouken@797
   346
slouken@797
   347
    /* SDL's channel mapping and FLAC channel mapping are the same,
slouken@797
   348
       except for 3 channels: SDL is FL FR LFE and FLAC is FL FR FC
slouken@797
   349
     */
slouken@797
   350
    if (music->channels == 3) {
slouken@797
   351
        channels = 2;
slouken@797
   352
    } else {
slouken@797
   353
        channels = music->channels;
slouken@797
   354
    }
slouken@797
   355
    /* We check for NULL stream later when we get data */
slouken@797
   356
    SDL_assert(!music->stream);
slouken@797
   357
    music->stream = SDL_NewAudioStream(AUDIO_S16SYS, channels, music->sample_rate,
slouken@797
   358
                                      music_spec.format, music_spec.channels, music_spec.freq);
slouken@382
   359
}
slouken@382
   360
slouken@382
   361
static void flac_error_music_cb(
slouken@617
   362
                const FLAC__StreamDecoder *decoder,
slouken@617
   363
                FLAC__StreamDecoderErrorStatus status,
slouken@617
   364
                void *client_data)
slouken@409
   365
{
slouken@797
   366
    /* print an SDL error based on the error status */
slouken@617
   367
    switch (status) {
slouken@797
   368
    case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
slouken@797
   369
        SDL_SetError("Error processing the FLAC file [LOST_SYNC].");
slouken@617
   370
        break;
slouken@797
   371
    case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
slouken@797
   372
        SDL_SetError("Error processing the FLAC file [BAD_HEADER].");
slouken@617
   373
        break;
slouken@797
   374
    case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
slouken@797
   375
        SDL_SetError("Error processing the FLAC file [CRC_MISMATCH].");
slouken@617
   376
        break;
slouken@797
   377
    case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
slouken@797
   378
        SDL_SetError("Error processing the FLAC file [UNPARSEABLE].");
slouken@617
   379
        break;
slouken@797
   380
    default:
slouken@797
   381
        SDL_SetError("Error processing the FLAC file [UNKNOWN].");
slouken@617
   382
        break;
slouken@617
   383
    }
slouken@382
   384
}
slouken@382
   385
slouken@382
   386
/* Load an FLAC stream from an SDL_RWops object */
slouken@777
   387
static void *FLAC_CreateFromRW(SDL_RWops *src, int freesrc)
slouken@409
   388
{
slouken@797
   389
    FLAC_Music *music;
slouken@617
   390
    int init_stage = 0;
slouken@617
   391
    int was_error = 1;
slouken@382
   392
slouken@797
   393
    music = (FLAC_Music *)SDL_calloc(1, sizeof(*music));
slouken@797
   394
    if (!music) {
slouken@797
   395
        SDL_OutOfMemory();
slouken@797
   396
        return NULL;
slouken@797
   397
    }
slouken@797
   398
    music->src = src;
slouken@797
   399
    music->volume = MIX_MAX_VOLUME;
slouken@797
   400
slouken@797
   401
    music->flac_decoder = flac.FLAC__stream_decoder_new();
slouken@797
   402
    if (music->flac_decoder) {
slouken@797
   403
        init_stage++; /* stage 1! */
slouken@797
   404
slouken@797
   405
        if (flac.FLAC__stream_decoder_init_stream(
slouken@797
   406
                    music->flac_decoder,
slouken@797
   407
                    flac_read_music_cb, flac_seek_music_cb,
slouken@797
   408
                    flac_tell_music_cb, flac_length_music_cb,
slouken@797
   409
                    flac_eof_music_cb, flac_write_music_cb,
slouken@797
   410
                    flac_metadata_music_cb, flac_error_music_cb,
slouken@797
   411
                    music) == FLAC__STREAM_DECODER_INIT_STATUS_OK) {
slouken@797
   412
            init_stage++; /* stage 2! */
slouken@797
   413
slouken@797
   414
            if (flac.FLAC__stream_decoder_process_until_end_of_metadata(music->flac_decoder)) {
slouken@797
   415
                was_error = 0;
slouken@797
   416
            } else {
slouken@797
   417
                SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
slouken@797
   418
            }
slouken@797
   419
        } else {
slouken@797
   420
            SDL_SetError("FLAC__stream_decoder_init_stream() failed");
slouken@797
   421
        }
slouken@797
   422
    } else {
slouken@797
   423
        SDL_SetError("FLAC__stream_decoder_new() failed");
slouken@797
   424
    }
slouken@797
   425
slouken@797
   426
    if (was_error) {
slouken@797
   427
        switch (init_stage) {
slouken@797
   428
            case 2:
slouken@797
   429
                flac.FLAC__stream_decoder_finish(music->flac_decoder);
slouken@797
   430
            case 1:
slouken@797
   431
                flac.FLAC__stream_decoder_delete(music->flac_decoder);
slouken@797
   432
            case 0:
slouken@797
   433
                SDL_free(music);
slouken@797
   434
                break;
slouken@797
   435
        }
slouken@617
   436
        return NULL;
slouken@617
   437
    }
slouken@545
   438
slouken@797
   439
    music->freesrc = freesrc;
slouken@617
   440
    return music;
slouken@382
   441
}
slouken@382
   442
slouken@777
   443
/* Set the volume for an FLAC stream */
slouken@777
   444
static void FLAC_SetVolume(void *context, int volume)
slouken@777
   445
{
slouken@797
   446
    FLAC_Music *music = (FLAC_Music *)context;
slouken@777
   447
    music->volume = volume;
slouken@777
   448
}
slouken@777
   449
slouken@382
   450
/* Start playback of a given FLAC stream */
slouken@797
   451
static int FLAC_Play(void *context, int play_count)
slouken@409
   452
{
slouken@797
   453
    FLAC_Music *music = (FLAC_Music *)context;
slouken@797
   454
    music->play_count = play_count;
slouken@797
   455
    return FLAC_Seek(music, 0.0);
slouken@382
   456
}
slouken@382
   457
slouken@382
   458
/* Read some FLAC stream data and convert it for output */
slouken@797
   459
static int FLAC_GetSome(void *context, void *data, int bytes, SDL_bool *done)
slouken@409
   460
{
slouken@797
   461
    FLAC_Music *music = (FLAC_Music *)context;
slouken@797
   462
    int filled;
slouken@382
   463
slouken@797
   464
    filled = SDL_AudioStreamGet(music->stream, data, bytes);
slouken@797
   465
    if (filled != 0) {
slouken@797
   466
        return filled;
slouken@617
   467
    }
slouken@382
   468
slouken@797
   469
    if (!music->play_count) {
slouken@797
   470
        /* All done */
slouken@797
   471
        *done = SDL_TRUE;
slouken@797
   472
        return 0;
slouken@797
   473
    }
slouken@382
   474
slouken@797
   475
    if (!flac.FLAC__stream_decoder_process_single(music->flac_decoder)) {
slouken@797
   476
        SDL_SetError("FLAC__stream_decoder_process_single() failed");
slouken@797
   477
        return -1;
slouken@797
   478
    }
slouken@382
   479
slouken@797
   480
    if (flac.FLAC__stream_decoder_get_state(music->flac_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) {
slouken@797
   481
        if (music->play_count == 1) {
slouken@797
   482
            music->play_count = 0;
slouken@797
   483
            SDL_AudioStreamFlush(music->stream);
slouken@797
   484
        } else {
slouken@797
   485
            int play_count = -1;
slouken@797
   486
            if (music->play_count > 0) {
slouken@797
   487
                play_count = (music->play_count - 1);
slouken@617
   488
            }
slouken@797
   489
            if (FLAC_Play(music, play_count) < 0) {
slouken@797
   490
                return -1;
slouken@617
   491
            }
slouken@617
   492
        }
slouken@617
   493
    }
slouken@797
   494
    return 0;
slouken@382
   495
}
slouken@382
   496
slouken@382
   497
/* Play some of a stream previously started with FLAC_play() */
slouken@777
   498
static int FLAC_GetAudio(void *context, void *data, int bytes)
slouken@409
   499
{
slouken@797
   500
    FLAC_Music *music = (FLAC_Music *)context;
slouken@797
   501
    return music_pcm_getaudio(context, data, bytes, music->volume, FLAC_GetSome);
slouken@382
   502
}
slouken@382
   503
slouken@777
   504
/* Jump (seek) to a given position (position is in seconds) */
slouken@777
   505
static int FLAC_Seek(void *context, double position)
slouken@777
   506
{
slouken@797
   507
    FLAC_Music *music = (FLAC_Music *)context;
slouken@797
   508
    double seek_sample = music->sample_rate * position;
slouken@777
   509
slouken@797
   510
    if (!flac.FLAC__stream_decoder_seek_absolute(music->flac_decoder, (FLAC__uint64)seek_sample)) {
slouken@797
   511
        if (flac.FLAC__stream_decoder_get_state(music->flac_decoder) == FLAC__STREAM_DECODER_SEEK_ERROR) {
slouken@797
   512
            flac.FLAC__stream_decoder_flush(music->flac_decoder);
slouken@777
   513
        }
slouken@777
   514
slouken@777
   515
        SDL_SetError("Seeking of FLAC stream failed: libFLAC seek failed.");
slouken@777
   516
        return -1;
slouken@777
   517
    }
slouken@777
   518
    return 0;
slouken@777
   519
}
slouken@777
   520
slouken@797
   521
/* Close the given FLAC_Music object */
slouken@777
   522
static void FLAC_Delete(void *context)
slouken@409
   523
{
slouken@797
   524
    FLAC_Music *music = (FLAC_Music *)context;
slouken@617
   525
    if (music) {
slouken@617
   526
        if (music->flac_decoder) {
slouken@797
   527
            flac.FLAC__stream_decoder_finish(music->flac_decoder);
slouken@797
   528
            flac.FLAC__stream_decoder_delete(music->flac_decoder);
slouken@617
   529
        }
slouken@797
   530
        if (music->stream) {
slouken@797
   531
            SDL_FreeAudioStream(music->stream);
slouken@617
   532
        }
slouken@625
   533
        if (music->freesrc) {
slouken@625
   534
            SDL_RWclose(music->src);
slouken@617
   535
        }
slouken@797
   536
        SDL_free(music);
slouken@617
   537
    }
slouken@382
   538
}
slouken@382
   539
slouken@777
   540
Mix_MusicInterface Mix_MusicInterface_FLAC =
slouken@409
   541
{
slouken@777
   542
    "FLAC",
slouken@777
   543
    MIX_MUSIC_FLAC,
slouken@777
   544
    MUS_FLAC,
slouken@777
   545
    SDL_FALSE,
slouken@777
   546
    SDL_FALSE,
slouken@382
   547
slouken@777
   548
    FLAC_Load,
slouken@777
   549
    NULL,   /* Open */
slouken@777
   550
    FLAC_CreateFromRW,
slouken@777
   551
    NULL,   /* CreateFromFile */
slouken@777
   552
    FLAC_SetVolume,
slouken@777
   553
    FLAC_Play,
slouken@797
   554
    NULL,   /* IsPlaying */
slouken@777
   555
    FLAC_GetAudio,
slouken@777
   556
    FLAC_Seek,
slouken@777
   557
    NULL,   /* Pause */
slouken@777
   558
    NULL,   /* Resume */
slouken@797
   559
    NULL,   /* Stop */
slouken@777
   560
    FLAC_Delete,
slouken@777
   561
    NULL,   /* Close */
slouken@777
   562
    FLAC_Unload,
slouken@777
   563
};
slouken@382
   564
slouken@777
   565
#endif /* MUSIC_FLAC */
slouken@382
   566
slouken@777
   567
/* vi: set ts=4 sw=4 expandtab: */