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