music_flac.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 20 Jan 2017 02:23:51 -0500
changeset 726 298d69a81cc9
parent 725 bdf7b8d20566
child 755 7c9cfb3bf040
permissions -rw-r--r--
Fixed music fading for Ogg Vorbis, libmad, and FLAC.
slouken@382
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@725
     3
  Copyright (C) 1997-2017 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@382
    25
#ifdef FLAC_MUSIC
slouken@382
    26
slouken@382
    27
#include <stdio.h>
slouken@382
    28
#include <stdlib.h>
slouken@382
    29
#include <string.h>
slouken@382
    30
slouken@382
    31
#include "SDL_mixer.h"
slouken@382
    32
#include "dynamic_flac.h"
slouken@382
    33
#include "music_flac.h"
slouken@382
    34
slouken@382
    35
/* This is the format of the audio mixer data */
slouken@382
    36
static SDL_AudioSpec mixer;
slouken@382
    37
slouken@382
    38
/* Initialize the FLAC player, with the given mixer settings
slouken@382
    39
   This function returns 0, or -1 if there was an error.
slouken@382
    40
 */
slouken@409
    41
int FLAC_init(SDL_AudioSpec *mixerfmt)
slouken@409
    42
{
slouken@617
    43
    mixer = *mixerfmt;
slouken@617
    44
    return(0);
slouken@382
    45
}
slouken@382
    46
slouken@382
    47
/* Set the volume for an FLAC stream */
slouken@409
    48
void FLAC_setvolume(FLAC_music *music, int volume)
slouken@409
    49
{
slouken@617
    50
    music->volume = volume;
slouken@382
    51
}
slouken@382
    52
slouken@382
    53
static FLAC__StreamDecoderReadStatus flac_read_music_cb(
slouken@617
    54
                                    const FLAC__StreamDecoder *decoder,
slouken@617
    55
                                    FLAC__byte buffer[],
slouken@617
    56
                                    size_t *bytes,
slouken@617
    57
                                    void *client_data)
slouken@409
    58
{
slouken@617
    59
    FLAC_music *data = (FLAC_music*)client_data;
slouken@382
    60
slouken@617
    61
    // make sure there is something to be reading
slouken@617
    62
    if (*bytes > 0) {
slouken@625
    63
        *bytes = SDL_RWread (data->src, buffer, sizeof (FLAC__byte), *bytes);
slouken@382
    64
slouken@617
    65
        if (*bytes == 0 ) { // error or no data was read (EOF)
slouken@617
    66
            return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
slouken@621
    67
        } else { // data was read, continue
slouken@617
    68
            return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
slouken@617
    69
        }
slouken@621
    70
    } else {
slouken@617
    71
        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
slouken@617
    72
    }
slouken@382
    73
}
slouken@382
    74
slouken@382
    75
static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
slouken@617
    76
                                    const FLAC__StreamDecoder *decoder,
slouken@617
    77
                                    FLAC__uint64 absolute_byte_offset,
slouken@617
    78
                                    void *client_data)
slouken@409
    79
{
slouken@617
    80
    FLAC_music *data = (FLAC_music*)client_data;
slouken@382
    81
slouken@625
    82
    if (SDL_RWseek (data->src, absolute_byte_offset, RW_SEEK_SET) < 0) {
slouken@617
    83
        return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
slouken@621
    84
    } else {
slouken@617
    85
        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
slouken@617
    86
    }
slouken@382
    87
}
slouken@382
    88
slouken@382
    89
static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
slouken@617
    90
                                    const FLAC__StreamDecoder *decoder,
slouken@617
    91
                                    FLAC__uint64 *absolute_byte_offset,
slouken@617
    92
                                    void *client_data )
slouken@409
    93
{
slouken@617
    94
    FLAC_music *data = (FLAC_music*)client_data;
slouken@382
    95
slouken@625
    96
    Sint64 pos = SDL_RWtell (data->src);
slouken@382
    97
slouken@617
    98
    if (pos < 0) {
slouken@617
    99
        return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
slouken@621
   100
    } else {
slouken@617
   101
        *absolute_byte_offset = (FLAC__uint64)pos;
slouken@617
   102
        return FLAC__STREAM_DECODER_TELL_STATUS_OK;
slouken@617
   103
    }
slouken@382
   104
}
slouken@382
   105
slouken@382
   106
static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
slouken@617
   107
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   108
                                    FLAC__uint64 *stream_length,
slouken@617
   109
                                    void *client_data)
slouken@409
   110
{
slouken@617
   111
    FLAC_music *data = (FLAC_music*)client_data;
slouken@382
   112
slouken@625
   113
    Sint64 pos = SDL_RWtell (data->src);
slouken@625
   114
    Sint64 length = SDL_RWseek (data->src, 0, RW_SEEK_END);
slouken@382
   115
slouken@625
   116
    if (SDL_RWseek (data->src, pos, RW_SEEK_SET) != pos || length < 0) {
slouken@617
   117
        /* there was an error attempting to return the stream to the original
slouken@617
   118
         * position, or the length was invalid. */
slouken@617
   119
        return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
slouken@621
   120
    } else {
slouken@617
   121
        *stream_length = (FLAC__uint64)length;
slouken@617
   122
        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
slouken@617
   123
    }
slouken@382
   124
}
slouken@382
   125
slouken@382
   126
static FLAC__bool flac_eof_music_cb(
slouken@617
   127
                                const FLAC__StreamDecoder *decoder,
slouken@617
   128
                                void *client_data )
slouken@409
   129
{
slouken@617
   130
    FLAC_music *data = (FLAC_music*)client_data;
slouken@382
   131
slouken@625
   132
    Sint64 pos = SDL_RWtell (data->src);
slouken@625
   133
    Sint64 end = SDL_RWseek (data->src, 0, RW_SEEK_END);
slouken@382
   134
slouken@617
   135
    // was the original position equal to the end (a.k.a. the seek didn't move)?
slouken@617
   136
    if (pos == end) {
slouken@617
   137
        // must be EOF
slouken@617
   138
        return true;
slouken@621
   139
    } else {
slouken@617
   140
        // not EOF, return to the original position
slouken@625
   141
        SDL_RWseek (data->src, pos, RW_SEEK_SET);
slouken@617
   142
        return false;
slouken@617
   143
    }
slouken@382
   144
}
slouken@382
   145
slouken@382
   146
static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
slouken@617
   147
                                    const FLAC__StreamDecoder *decoder,
slouken@617
   148
                                    const FLAC__Frame *frame,
slouken@617
   149
                                    const FLAC__int32 *const buffer[],
slouken@617
   150
                                    void *client_data)
slouken@409
   151
{
slouken@617
   152
    FLAC_music *data = (FLAC_music *)client_data;
slouken@617
   153
    size_t i;
slouken@382
   154
slouken@617
   155
    if (data->flac_data.total_samples == 0) {
slouken@617
   156
        SDL_SetError ("Given FLAC file does not specify its sample count.");
slouken@617
   157
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   158
    }
slouken@382
   159
slouken@617
   160
    if (data->flac_data.channels != 2 ||
slouken@617
   161
        data->flac_data.bits_per_sample != 16) {
slouken@617
   162
        SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
slouken@617
   163
        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   164
    }
slouken@382
   165
slouken@617
   166
    for (i = 0; i < frame->header.blocksize; i++) {
slouken@617
   167
        FLAC__int16 i16;
slouken@617
   168
        FLAC__uint16 ui16;
slouken@436
   169
slouken@617
   170
        // make sure we still have at least two bytes that can be read (one for
slouken@617
   171
        // each channel)
slouken@617
   172
        if (data->flac_data.max_to_read >= 4) {
slouken@617
   173
            // does the data block exist?
slouken@617
   174
            if (!data->flac_data.data) {
slouken@617
   175
                data->flac_data.data_len = data->flac_data.max_to_read;
slouken@617
   176
                data->flac_data.data_read = 0;
slouken@382
   177
slouken@617
   178
                // create it
slouken@617
   179
                data->flac_data.data =
slouken@617
   180
                    (char *)SDL_malloc (data->flac_data.data_len);
slouken@382
   181
slouken@617
   182
                if (!data->flac_data.data) {
slouken@617
   183
                    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   184
                }
slouken@617
   185
            }
slouken@382
   186
slouken@617
   187
            i16 = (FLAC__int16)buffer[0][i];
slouken@617
   188
            ui16 = (FLAC__uint16)i16;
slouken@382
   189
slouken@617
   190
            *((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@617
   191
                                                            (char)(ui16);
slouken@617
   192
            *((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@617
   193
                                                            (char)(ui16 >> 8);
slouken@382
   194
slouken@617
   195
            i16 = (FLAC__int16)buffer[1][i];
slouken@617
   196
            ui16 = (FLAC__uint16)i16;
slouken@382
   197
slouken@617
   198
            *((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@617
   199
                                                            (char)(ui16);
slouken@617
   200
            *((data->flac_data.data) + (data->flac_data.data_read++)) =
slouken@617
   201
                                                            (char)(ui16 >> 8);
slouken@382
   202
slouken@617
   203
            data->flac_data.max_to_read -= 4;
slouken@382
   204
slouken@617
   205
            if (data->flac_data.max_to_read < 4) {
slouken@617
   206
                // we need to set this so that the read halts from the
slouken@617
   207
                // FLAC_getsome function.
slouken@617
   208
                data->flac_data.max_to_read = 0;
slouken@617
   209
            }
slouken@617
   210
        }
slouken@617
   211
        else {
slouken@617
   212
            // we need to write to the overflow
slouken@617
   213
            if (!data->flac_data.overflow) {
slouken@617
   214
                data->flac_data.overflow_len =
slouken@617
   215
                                            4 * (frame->header.blocksize - i);
slouken@617
   216
                data->flac_data.overflow_read = 0;
slouken@382
   217
slouken@617
   218
                // make it big enough for the rest of the block
slouken@617
   219
                data->flac_data.overflow =
slouken@617
   220
                    (char *)SDL_malloc (data->flac_data.overflow_len);
slouken@382
   221
slouken@617
   222
                if (!data->flac_data.overflow) {
slouken@617
   223
                    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
slouken@617
   224
                }
slouken@617
   225
            }
slouken@382
   226
slouken@617
   227
            i16 = (FLAC__int16)buffer[0][i];
slouken@617
   228
            ui16 = (FLAC__uint16)i16;
slouken@382
   229
slouken@617
   230
            *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@617
   231
                                                            (char)(ui16);
slouken@617
   232
            *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@617
   233
                                                            (char)(ui16 >> 8);
slouken@382
   234
slouken@617
   235
            i16 = (FLAC__int16)buffer[1][i];
slouken@617
   236
            ui16 = (FLAC__uint16)i16;
slouken@382
   237
slouken@617
   238
            *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@617
   239
                                                            (char)(ui16);
slouken@617
   240
            *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
slouken@617
   241
                                                            (char)(ui16 >> 8);
slouken@617
   242
        }
slouken@617
   243
    }
slouken@382
   244
slouken@617
   245
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
slouken@382
   246
}
slouken@382
   247
slouken@382
   248
static void flac_metadata_music_cb(
slouken@617
   249
                    const FLAC__StreamDecoder *decoder,
slouken@617
   250
                    const FLAC__StreamMetadata *metadata,
slouken@617
   251
                    void *client_data)
slouken@409
   252
{
slouken@617
   253
    FLAC_music *data = (FLAC_music *)client_data;
slouken@382
   254
slouken@617
   255
    if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
slouken@617
   256
        data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
slouken@617
   257
        data->flac_data.channels = metadata->data.stream_info.channels;
slouken@617
   258
        data->flac_data.total_samples =
slouken@617
   259
                            metadata->data.stream_info.total_samples;
slouken@617
   260
        data->flac_data.bits_per_sample =
slouken@617
   261
                            metadata->data.stream_info.bits_per_sample;
slouken@617
   262
        data->flac_data.sample_size = data->flac_data.channels *
slouken@617
   263
                                        ((data->flac_data.bits_per_sample) / 8);
slouken@617
   264
    }
slouken@382
   265
}
slouken@382
   266
slouken@382
   267
static void flac_error_music_cb(
slouken@617
   268
                const FLAC__StreamDecoder *decoder,
slouken@617
   269
                FLAC__StreamDecoderErrorStatus status,
slouken@617
   270
                void *client_data)
slouken@409
   271
{
slouken@617
   272
    // print an SDL error based on the error status
slouken@617
   273
    switch (status) {
slouken@617
   274
        case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
slouken@617
   275
            SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
slouken@617
   276
        break;
slouken@617
   277
        case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
slouken@617
   278
            SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
slouken@617
   279
        break;
slouken@617
   280
        case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
slouken@617
   281
            SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
slouken@617
   282
        break;
slouken@617
   283
        case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
slouken@617
   284
            SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
slouken@617
   285
        break;
slouken@617
   286
        default:
slouken@617
   287
            SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
slouken@617
   288
        break;
slouken@617
   289
    }
slouken@382
   290
}
slouken@382
   291
slouken@382
   292
/* Load an FLAC stream from an SDL_RWops object */
slouken@625
   293
FLAC_music *FLAC_new_RW(SDL_RWops *src, int freesrc)
slouken@409
   294
{
slouken@617
   295
    FLAC_music *music;
slouken@617
   296
    int init_stage = 0;
slouken@617
   297
    int was_error = 1;
slouken@382
   298
slouken@617
   299
    if (!Mix_Init(MIX_INIT_FLAC)) {
slouken@617
   300
        return NULL;
slouken@617
   301
    }
slouken@545
   302
slouken@617
   303
    music = (FLAC_music *)SDL_malloc ( sizeof (*music));
slouken@617
   304
    if (music) {
slouken@617
   305
        /* Initialize the music structure */
slouken@617
   306
        memset (music, 0, (sizeof (*music)));
slouken@617
   307
        FLAC_stop (music);
slouken@617
   308
        FLAC_setvolume (music, MIX_MAX_VOLUME);
slouken@617
   309
        music->section = -1;
slouken@625
   310
        music->src = src;
slouken@625
   311
        music->freesrc = freesrc;
slouken@617
   312
        music->flac_data.max_to_read = 0;
slouken@617
   313
        music->flac_data.overflow = NULL;
slouken@617
   314
        music->flac_data.overflow_len = 0;
slouken@617
   315
        music->flac_data.overflow_read = 0;
slouken@617
   316
        music->flac_data.data = NULL;
slouken@617
   317
        music->flac_data.data_len = 0;
slouken@617
   318
        music->flac_data.data_read = 0;
slouken@382
   319
slouken@617
   320
        init_stage++; // stage 1!
slouken@382
   321
slouken@617
   322
        music->flac_decoder = flac.FLAC__stream_decoder_new ();
slouken@382
   323
slouken@617
   324
        if (music->flac_decoder != NULL) {
slouken@617
   325
            init_stage++; // stage 2!
slouken@382
   326
slouken@617
   327
            if (flac.FLAC__stream_decoder_init_stream(
slouken@617
   328
                        music->flac_decoder,
slouken@617
   329
                        flac_read_music_cb, flac_seek_music_cb,
slouken@617
   330
                        flac_tell_music_cb, flac_length_music_cb,
slouken@617
   331
                        flac_eof_music_cb, flac_write_music_cb,
slouken@617
   332
                        flac_metadata_music_cb, flac_error_music_cb,
slouken@617
   333
                        music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
slouken@617
   334
                init_stage++; // stage 3!
slouken@382
   335
slouken@617
   336
                if (flac.FLAC__stream_decoder_process_until_end_of_metadata
slouken@617
   337
                                        (music->flac_decoder)) {
slouken@617
   338
                    was_error = 0;
slouken@617
   339
                } else {
slouken@617
   340
                    SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
slouken@617
   341
                }
slouken@617
   342
            } else {
slouken@617
   343
                SDL_SetError("FLAC__stream_decoder_init_stream() failed");
slouken@617
   344
            }
slouken@617
   345
        } else {
slouken@617
   346
            SDL_SetError("FLAC__stream_decoder_new() failed");
slouken@617
   347
        }
slouken@382
   348
slouken@617
   349
        if (was_error) {
slouken@617
   350
            switch (init_stage) {
slouken@617
   351
                case 3:
slouken@617
   352
                    flac.FLAC__stream_decoder_finish( music->flac_decoder );
slouken@617
   353
                case 2:
slouken@617
   354
                    flac.FLAC__stream_decoder_delete( music->flac_decoder );
slouken@617
   355
                case 1:
slouken@617
   356
                case 0:
slouken@617
   357
                    SDL_free(music);
slouken@617
   358
                    break;
slouken@617
   359
            }
slouken@617
   360
            return NULL;
slouken@617
   361
        }
slouken@617
   362
    } else {
slouken@617
   363
        SDL_OutOfMemory();
slouken@617
   364
        return NULL;
slouken@617
   365
    }
slouken@382
   366
slouken@617
   367
    return music;
slouken@382
   368
}
slouken@382
   369
slouken@382
   370
/* Start playback of a given FLAC stream */
slouken@409
   371
void FLAC_play(FLAC_music *music)
slouken@409
   372
{
slouken@617
   373
    music->playing = 1;
slouken@382
   374
}
slouken@382
   375
slouken@382
   376
/* Return non-zero if a stream is currently playing */
slouken@409
   377
int FLAC_playing(FLAC_music *music)
slouken@409
   378
{
slouken@617
   379
    return(music->playing);
slouken@382
   380
}
slouken@382
   381
slouken@382
   382
/* Read some FLAC stream data and convert it for output */
slouken@409
   383
static void FLAC_getsome(FLAC_music *music)
slouken@409
   384
{
slouken@617
   385
    SDL_AudioCVT *cvt;
slouken@382
   386
slouken@617
   387
    /* GET AUDIO WAVE DATA */
slouken@617
   388
    // set the max number of characters to read
slouken@617
   389
    music->flac_data.max_to_read = 8192;
slouken@617
   390
    music->flac_data.data_len = music->flac_data.max_to_read;
slouken@617
   391
    music->flac_data.data_read = 0;
slouken@617
   392
    if (!music->flac_data.data) {
slouken@617
   393
        music->flac_data.data = (char *)SDL_malloc (music->flac_data.data_len);
slouken@617
   394
    }
slouken@382
   395
slouken@617
   396
    // we have data to read
slouken@617
   397
    while(music->flac_data.max_to_read > 0) {
slouken@617
   398
        // first check if there is data in the overflow from before
slouken@617
   399
        if (music->flac_data.overflow) {
slouken@617
   400
            size_t overflow_len = music->flac_data.overflow_read;
slouken@382
   401
aschiffler@642
   402
            if (overflow_len > (size_t)music->flac_data.max_to_read) {
slouken@617
   403
                size_t overflow_extra_len = overflow_len -
slouken@617
   404
                                                music->flac_data.max_to_read;
slouken@382
   405
slouken@621
   406
                SDL_memcpy (music->flac_data.data+music->flac_data.data_read,
slouken@617
   407
                    music->flac_data.overflow, music->flac_data.max_to_read);
slouken@617
   408
                music->flac_data.data_read += music->flac_data.max_to_read;
slouken@621
   409
                SDL_memcpy (music->flac_data.overflow,
slouken@617
   410
                    music->flac_data.overflow + music->flac_data.max_to_read,
slouken@617
   411
                    overflow_extra_len);
slouken@617
   412
                music->flac_data.overflow_len = overflow_extra_len;
slouken@617
   413
                music->flac_data.overflow_read = overflow_extra_len;
slouken@617
   414
                music->flac_data.max_to_read = 0;
slouken@621
   415
            } else {
slouken@621
   416
                SDL_memcpy (music->flac_data.data+music->flac_data.data_read,
slouken@617
   417
                    music->flac_data.overflow, overflow_len);
slouken@617
   418
                music->flac_data.data_read += overflow_len;
slouken@621
   419
                SDL_free (music->flac_data.overflow);
slouken@617
   420
                music->flac_data.overflow = NULL;
slouken@617
   421
                music->flac_data.overflow_len = 0;
slouken@617
   422
                music->flac_data.overflow_read = 0;
slouken@617
   423
                music->flac_data.max_to_read -= overflow_len;
slouken@617
   424
            }
slouken@617
   425
        }
slouken@617
   426
        else {
slouken@617
   427
            if (!flac.FLAC__stream_decoder_process_single (
slouken@617
   428
                                                        music->flac_decoder)) {
slouken@617
   429
                music->flac_data.max_to_read = 0;
slouken@617
   430
            }
slouken@382
   431
slouken@617
   432
            if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
slouken@617
   433
                                    == FLAC__STREAM_DECODER_END_OF_STREAM) {
slouken@617
   434
                music->flac_data.max_to_read = 0;
slouken@617
   435
            }
slouken@617
   436
        }
slouken@617
   437
    }
slouken@382
   438
slouken@617
   439
    if (music->flac_data.data_read <= 0) {
slouken@617
   440
        if (music->flac_data.data_read == 0) {
slouken@617
   441
            music->playing = 0;
slouken@617
   442
        }
slouken@617
   443
        return;
slouken@617
   444
    }
slouken@617
   445
    cvt = &music->cvt;
slouken@617
   446
    if (music->section < 0) {
slouken@617
   447
        SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
slouken@617
   448
                        (int)music->flac_data.sample_rate, mixer.format,
slouken@617
   449
                        mixer.channels, mixer.freq);
slouken@617
   450
        if (cvt->buf) {
slouken@621
   451
            SDL_free (cvt->buf);
slouken@617
   452
        }
slouken@617
   453
        cvt->buf = (Uint8 *)SDL_malloc (music->flac_data.data_len * cvt->len_mult);
slouken@617
   454
        music->section = 0;
slouken@617
   455
    }
slouken@617
   456
    if (cvt->buf) {
slouken@621
   457
        SDL_memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
slouken@617
   458
        if (cvt->needed) {
slouken@617
   459
            cvt->len = music->flac_data.data_read;
slouken@617
   460
            SDL_ConvertAudio (cvt);
slouken@617
   461
        }
slouken@617
   462
        else {
slouken@617
   463
            cvt->len_cvt = music->flac_data.data_read;
slouken@617
   464
        }
slouken@617
   465
        music->len_available = music->cvt.len_cvt;
slouken@617
   466
        music->snd_available = music->cvt.buf;
slouken@617
   467
    }
slouken@617
   468
    else {
slouken@617
   469
        SDL_SetError ("Out of memory");
slouken@617
   470
        music->playing = 0;
slouken@617
   471
    }
slouken@382
   472
}
slouken@382
   473
slouken@382
   474
/* Play some of a stream previously started with FLAC_play() */
slouken@409
   475
int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len)
slouken@409
   476
{
slouken@617
   477
    int mixable;
slouken@382
   478
slouken@617
   479
    while ((len > 0) && music->playing) {
slouken@617
   480
        if (!music->len_available) {
slouken@617
   481
            FLAC_getsome (music);
slouken@617
   482
        }
slouken@617
   483
        mixable = len;
slouken@617
   484
        if (mixable > music->len_available) {
slouken@617
   485
            mixable = music->len_available;
slouken@617
   486
        }
slouken@617
   487
        if (music->volume == MIX_MAX_VOLUME) {
slouken@621
   488
            SDL_memcpy (snd, music->snd_available, mixable);
slouken@617
   489
        }
slouken@617
   490
        else {
icculus@726
   491
            SDL_MixAudioFormat(snd, music->snd_available, mixer.format, mixable, music->volume);
slouken@617
   492
        }
slouken@617
   493
        music->len_available -= mixable;
slouken@617
   494
        music->snd_available += mixable;
slouken@617
   495
        len -= mixable;
slouken@617
   496
        snd += mixable;
slouken@617
   497
    }
slouken@382
   498
slouken@617
   499
    return len;
slouken@382
   500
}
slouken@382
   501
slouken@382
   502
/* Stop playback of a stream previously started with FLAC_play() */
slouken@409
   503
void FLAC_stop(FLAC_music *music)
slouken@409
   504
{
slouken@617
   505
    music->playing = 0;
slouken@382
   506
}
slouken@382
   507
slouken@382
   508
/* Close the given FLAC_music object */
slouken@409
   509
void FLAC_delete(FLAC_music *music)
slouken@409
   510
{
slouken@617
   511
    if (music) {
slouken@617
   512
        if (music->flac_decoder) {
slouken@617
   513
            flac.FLAC__stream_decoder_finish (music->flac_decoder);
slouken@617
   514
            flac.FLAC__stream_decoder_delete (music->flac_decoder);
slouken@617
   515
        }
slouken@382
   516
slouken@617
   517
        if (music->flac_data.data) {
slouken@621
   518
            SDL_free (music->flac_data.data);
slouken@617
   519
        }
slouken@382
   520
slouken@617
   521
        if (music->flac_data.overflow) {
slouken@621
   522
            SDL_free (music->flac_data.overflow);
slouken@617
   523
        }
slouken@382
   524
slouken@617
   525
        if (music->cvt.buf) {
slouken@621
   526
            SDL_free (music->cvt.buf);
slouken@617
   527
        }
slouken@382
   528
slouken@625
   529
        if (music->freesrc) {
slouken@625
   530
            SDL_RWclose(music->src);
slouken@617
   531
        }
slouken@621
   532
        SDL_free (music);
slouken@617
   533
    }
slouken@382
   534
}
slouken@382
   535
slouken@382
   536
/* Jump (seek) to a given position (time is in seconds) */
slouken@409
   537
void FLAC_jump_to_time(FLAC_music *music, double time)
slouken@409
   538
{
slouken@617
   539
    if (music) {
slouken@617
   540
        if (music->flac_decoder) {
slouken@617
   541
            double seek_sample = music->flac_data.sample_rate * time;
slouken@382
   542
slouken@617
   543
            // clear data if it has data
slouken@617
   544
            if (music->flac_data.data) {
slouken@621
   545
                SDL_free (music->flac_data.data);
slouken@617
   546
                music->flac_data.data = NULL;
slouken@617
   547
            }
slouken@382
   548
slouken@617
   549
            // clear overflow if it has data
slouken@617
   550
            if (music->flac_data.overflow) {
slouken@621
   551
                SDL_free (music->flac_data.overflow);
slouken@617
   552
                music->flac_data.overflow = NULL;
slouken@617
   553
            }
slouken@382
   554
slouken@617
   555
            if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
slouken@617
   556
                                                (FLAC__uint64)seek_sample)) {
slouken@617
   557
                if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
slouken@617
   558
                                        == FLAC__STREAM_DECODER_SEEK_ERROR) {
slouken@617
   559
                    flac.FLAC__stream_decoder_flush (music->flac_decoder);
slouken@617
   560
                }
slouken@382
   561
slouken@617
   562
                SDL_SetError
slouken@617
   563
                    ("Seeking of FLAC stream failed: libFLAC seek failed.");
slouken@617
   564
            }
slouken@617
   565
        }
slouken@617
   566
        else {
slouken@617
   567
            SDL_SetError
slouken@617
   568
                ("Seeking of FLAC stream failed: FLAC decoder was NULL.");
slouken@617
   569
        }
slouken@617
   570
    }
slouken@617
   571
    else {
slouken@617
   572
        SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
slouken@617
   573
    }
slouken@382
   574
}
slouken@382
   575
slouken@382
   576
#endif /* FLAC_MUSIC */