1 /*
2 * Allegro FLAC reader
3 * author: Ryan Dickie, (c) 2008
4 * streaming support by Elias Pschernig
5 */
6
7
8 #include "allegro5/allegro.h"
9 #include "allegro5/allegro_acodec.h"
10 #include "allegro5/allegro_audio.h"
11 #include "allegro5/internal/aintern.h"
12 #include "allegro5/internal/aintern_audio.h"
13 #include "allegro5/internal/aintern_exitfunc.h"
14 #include "allegro5/internal/aintern_system.h"
15 #include "acodec.h"
16 #include "helper.h"
17
18 #ifndef ALLEGRO_CFG_ACODEC_FLAC
19 #error configuration problem, ALLEGRO_CFG_ACODEC_FLAC not set
20 #endif
21
22 #include <FLAC/stream_decoder.h>
23 #include <stdio.h>
24
25 ALLEGRO_DEBUG_CHANNEL("acodec")
26
27
28 typedef struct FLACFILE {
29 FLAC__StreamDecoder *decoder;
30 double sample_rate;
31 int sample_size;
32 int channels;
33
34 /* The file buffer. */
35 uint64_t buffer_pos, buffer_size;
36 char *buffer;
37
38 /* Number of samples in the complete FLAC. */
39 uint64_t total_samples;
40
41 /* Sample position one past last decoded sample. */
42 uint64_t decoded_samples;
43
44 /* Sample position one past last streamed sample. */
45 uint64_t streamed_samples;
46
47 ALLEGRO_FILE *fh;
48 uint64_t loop_start, loop_end; /* in samples */
49 } FLACFILE;
50
51
52 /* dynamic loading support (Windows only currently) */
53 #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL
54 static void *flac_dll = NULL;
55 static bool flac_virgin = true;
56 #endif
57
58 static struct
59 {
60 FLAC__StreamDecoder *(*FLAC__stream_decoder_new)(void);
61 void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder);
62 FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)(
63 FLAC__StreamDecoder *decoder,
64 FLAC__StreamDecoderReadCallback read_callback,
65 FLAC__StreamDecoderSeekCallback seek_callback,
66 FLAC__StreamDecoderTellCallback tell_callback,
67 FLAC__StreamDecoderLengthCallback length_callback,
68 FLAC__StreamDecoderEofCallback eof_callback,
69 FLAC__StreamDecoderWriteCallback write_callback,
70 FLAC__StreamDecoderMetadataCallback metadata_callback,
71 FLAC__StreamDecoderErrorCallback error_callback,
72 void *client_data);
73 FLAC__bool (*FLAC__stream_decoder_process_single)(FLAC__StreamDecoder *decoder);
74 FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(FLAC__StreamDecoder *decoder);
75 FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(FLAC__StreamDecoder *decoder);
76 FLAC__bool (*FLAC__stream_decoder_seek_absolute)(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
77 FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder);
78 FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder);
79 } lib;
80
81
82 #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL
shutdown_dynlib(void)83 static void shutdown_dynlib(void)
84 {
85 if (flac_dll) {
86 _al_close_library(flac_dll);
87 flac_dll = NULL;
88 flac_virgin = true;
89 }
90 }
91 #endif
92
93
init_dynlib(void)94 static bool init_dynlib(void)
95 {
96 #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL
97 if (flac_dll) {
98 return true;
99 }
100
101 if (!flac_virgin) {
102 return false;
103 }
104
105 flac_virgin = false;
106
107 flac_dll = _al_open_library(ALLEGRO_CFG_ACODEC_FLAC_DLL);
108 if (!flac_dll) {
109 ALLEGRO_ERROR("Could not load " ALLEGRO_CFG_ACODEC_FLAC_DLL "\n");
110 return false;
111 }
112
113 _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib");
114
115 #define INITSYM(x) \
116 do \
117 { \
118 lib.x = _al_import_symbol(flac_dll, #x); \
119 if (lib.x == 0) { \
120 ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \
121 return false; \
122 } \
123 } while(0)
124 #else
125 #define INITSYM(x) (lib.x = (x))
126 #endif
127
128 memset(&lib, 0, sizeof(lib));
129
130 INITSYM(FLAC__stream_decoder_new);
131 INITSYM(FLAC__stream_decoder_delete);
132 INITSYM(FLAC__stream_decoder_init_stream);
133 INITSYM(FLAC__stream_decoder_process_single);
134 INITSYM(FLAC__stream_decoder_process_until_end_of_metadata);
135 INITSYM(FLAC__stream_decoder_process_until_end_of_stream);
136 INITSYM(FLAC__stream_decoder_seek_absolute);
137 INITSYM(FLAC__stream_decoder_flush);
138 INITSYM(FLAC__stream_decoder_finish);
139
140 return true;
141
142 #undef INITSYM
143 }
144
145
read_callback(const FLAC__StreamDecoder * decoder,FLAC__byte buffer[],size_t * bytes,void * dptr)146 static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder,
147 FLAC__byte buffer[], size_t *bytes, void *dptr)
148 {
149 FLACFILE *ff = (FLACFILE *)dptr;
150 ALLEGRO_FILE *fh = ff->fh;
151 (void)decoder;
152 if (*bytes > 0) {
153 *bytes = al_fread(fh, buffer, *bytes);
154 if (al_ferror(fh))
155 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
156 else if (*bytes == 0)
157 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
158 else
159 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
160 }
161 else
162 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
163 }
164
165
seek_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 absolute_byte_offset,void * dptr)166 static FLAC__StreamDecoderSeekStatus seek_callback(
167 const FLAC__StreamDecoder *decoder,
168 FLAC__uint64 absolute_byte_offset, void *dptr)
169 {
170 FLACFILE *ff = (FLACFILE *)dptr;
171 ALLEGRO_FILE *fh = ff->fh;
172 (void)decoder;
173
174 if (!al_fseek(fh, absolute_byte_offset, ALLEGRO_SEEK_SET))
175 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
176 else
177 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
178 }
179
180
tell_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 * absolute_byte_offset,void * dptr)181 static FLAC__StreamDecoderTellStatus tell_callback(
182 const FLAC__StreamDecoder *decoder,
183 FLAC__uint64 *absolute_byte_offset, void *dptr)
184 {
185 FLACFILE *ff = (FLACFILE *)dptr;
186 ALLEGRO_FILE *fh = ff->fh;
187 int64_t pos = 0;
188 (void)decoder;
189
190 pos = al_ftell(fh);
191 if (pos == -1)
192 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
193
194 *absolute_byte_offset = (FLAC__uint64)pos;
195 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
196 }
197
198
length_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 * stream_length,void * dptr)199 static FLAC__StreamDecoderLengthStatus length_callback(
200 const FLAC__StreamDecoder *decoder,
201 FLAC__uint64 *stream_length, void *dptr)
202 {
203 FLACFILE *ff = (FLACFILE *)dptr;
204 ALLEGRO_FILE *fh = ff->fh;
205 (void)decoder;
206
207 /* XXX check error */
208 *stream_length = (FLAC__uint64)al_fsize(fh);
209
210 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
211 }
212
213
eof_callback(const FLAC__StreamDecoder * decoder,void * dptr)214 static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *dptr)
215 {
216 FLACFILE *ff = (FLACFILE *)dptr;
217 ALLEGRO_FILE *fh = ff->fh;
218 (void)decoder;
219
220 if (al_feof(fh))
221 return true;
222
223 return false;
224 }
225
226
metadata_callback(const FLAC__StreamDecoder * decoder,const FLAC__StreamMetadata * metadata,void * client_data)227 static void metadata_callback(const FLAC__StreamDecoder *decoder,
228 const FLAC__StreamMetadata *metadata, void *client_data)
229 {
230 FLACFILE *out = (FLACFILE *)client_data;
231
232 (void)decoder;
233
234 if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
235 out->total_samples = metadata->data.stream_info.total_samples;
236 out->sample_rate = metadata->data.stream_info.sample_rate;
237 out->channels = metadata->data.stream_info.channels;
238 out->sample_size = metadata->data.stream_info.bits_per_sample / 8;
239 }
240 }
241
242
error_callback(const FLAC__StreamDecoder * decoder,FLAC__StreamDecoderErrorStatus status,void * client_data)243 static void error_callback(const FLAC__StreamDecoder *decoder,
244 FLAC__StreamDecoderErrorStatus status, void *client_data)
245 {
246 (void)decoder;
247 (void)client_data;
248
249 #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL
250 (void)status;
251 ALLEGRO_ERROR("Got FLAC error callback\n"); /* lazy */
252 #else
253 ALLEGRO_ERROR("Got FLAC error callback: %s\n",
254 FLAC__StreamDecoderErrorStatusString[status]);
255 #endif
256 }
257
258
write_callback(const FLAC__StreamDecoder * decoder,const FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)259 static FLAC__StreamDecoderWriteStatus write_callback(
260 const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
261 const FLAC__int32 * const buffer[], void *client_data)
262 {
263 FLACFILE *ff = (FLACFILE *) client_data;
264 long len = frame->header.blocksize;
265 long bytes = len * ff->channels * ff->sample_size;
266 FLAC__uint8 *buf8;
267 FLAC__int16 *buf16;
268 float *buf32;
269 int sample_index;
270 int channel_index;
271 int out_index;
272
273 if (ff->buffer_pos + bytes > ff->buffer_size) {
274 ff->buffer = al_realloc(ff->buffer, ff->buffer_pos + bytes);
275 ff->buffer_size = ff->buffer_pos + bytes;
276 }
277
278 /* FLAC returns FLAC__int32 and I need to convert it to my own format. */
279 buf8 = (FLAC__uint8 *) (ff->buffer + ff->buffer_pos);
280 buf16 = (FLAC__int16 *) buf8;
281 buf32 = (float *) buf8;
282
283 (void)decoder;
284 (void)client_data;
285
286 /* Flatten the array */
287 /* TODO: test this array flattening process on 5.1 and higher flac files */
288 out_index = 0;
289 switch (ff->sample_size) {
290 case 1:
291 for (sample_index = 0; sample_index < len; sample_index++) {
292 for (channel_index = 0;
293 channel_index < ff->channels;
294 channel_index++) {
295 buf8[out_index++] =
296 (FLAC__uint8) buffer[channel_index][sample_index];
297 }
298 }
299 break;
300
301 case 2:
302 for (sample_index = 0; sample_index < len; sample_index++) {
303 for (channel_index = 0; channel_index < ff->channels;
304 channel_index++) {
305 buf16[out_index++] =
306 (FLAC__int16) buffer[channel_index][sample_index];
307 }
308 }
309 break;
310
311 case 3:
312 for (sample_index = 0; sample_index < len; sample_index++) {
313 for (channel_index = 0; channel_index < ff->channels;
314 channel_index++)
315 {
316 /* Little endian */
317 /* FIXME: does this work? I only have 16-bit sound card mixer
318 * garbages for other 24-bit codecs too.
319 */
320 buf8[out_index++] = (FLAC__uint8) (buffer[channel_index][sample_index] & 0xFF);
321 buf8[out_index++] = (FLAC__uint8) ((buffer[channel_index][sample_index] & 0xFF00) >> 8);
322 buf8[out_index++] = (FLAC__uint8) ((buffer[channel_index][sample_index] & 0xFF0000) >> 16);
323 }
324 }
325 break;
326
327 case 4:
328 for (sample_index = 0; sample_index < len; sample_index++) {
329 for (channel_index = 0; channel_index < ff->channels;
330 channel_index++) {
331 buf32[out_index++] =
332 (float) buffer[channel_index][sample_index];
333 }
334 }
335 break;
336
337 default:
338 /* Word_size not supported. */
339 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
340 }
341
342 ff->decoded_samples += len;
343 ff->buffer_pos += bytes;
344 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
345 }
346
flac_close(FLACFILE * ff)347 static void flac_close(FLACFILE *ff)
348 {
349 lib.FLAC__stream_decoder_finish(ff->decoder);
350 lib.FLAC__stream_decoder_delete(ff->decoder);
351 /* Don't close ff->fh here. */
352 al_free(ff);
353 }
354
355 /* In seconds. */
flac_stream_get_position(ALLEGRO_AUDIO_STREAM * stream)356 static double flac_stream_get_position(ALLEGRO_AUDIO_STREAM *stream)
357 {
358 FLACFILE *ff = (FLACFILE *)stream->extra;
359 return ff->streamed_samples / ff->sample_rate;
360 }
361
362
363 /*
364 * Updates 'stream' with the next chunk of data.
365 * Returns the actual number of bytes written.
366 */
flac_stream_update(ALLEGRO_AUDIO_STREAM * stream,void * data,size_t buf_size)367 static size_t flac_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data,
368 size_t buf_size)
369 {
370 int bytes_per_sample;
371 uint64_t wanted_samples;
372 uint64_t read_samples;
373 size_t written_bytes = 0;
374 size_t read_bytes;
375 FLACFILE *ff = (FLACFILE *)stream->extra;
376
377 bytes_per_sample = ff->sample_size * ff->channels;
378 wanted_samples = buf_size / bytes_per_sample;
379
380 if (ff->streamed_samples + wanted_samples > ff->loop_end) {
381 if (ff->loop_end > ff->streamed_samples)
382 wanted_samples = ff->loop_end - ff->streamed_samples;
383 else
384 return 0;
385 }
386
387 while (wanted_samples > 0) {
388 read_samples = ff->decoded_samples - ff->streamed_samples;
389
390 /* If the buffer size is small, we shouldn't read a new frame or our
391 * buffer keeps growing - so only refill when needed.
392 */
393 if (!read_samples) {
394 if (!lib.FLAC__stream_decoder_process_single(ff->decoder))
395 break;
396 read_samples = ff->decoded_samples - ff->streamed_samples;
397 if (!read_samples) {
398 break;
399 }
400 }
401
402 if (read_samples > wanted_samples)
403 read_samples = wanted_samples;
404 ff->streamed_samples += read_samples;
405 wanted_samples -= read_samples;
406 read_bytes = read_samples * bytes_per_sample;
407 /* Copy data from the FLAC file buffer to the stream buffer. */
408 memcpy((uint8_t *)data + written_bytes, ff->buffer, read_bytes);
409 /* Make room in the FLACFILE buffer. */
410 memmove(ff->buffer, ff->buffer + read_bytes,
411 ff->buffer_pos - read_bytes);
412 ff->buffer_pos -= read_bytes;
413 written_bytes += read_bytes;
414 }
415
416 return written_bytes;
417 }
418
419 /* Called from al_destroy_audio_stream. */
flac_stream_close(ALLEGRO_AUDIO_STREAM * stream)420 static void flac_stream_close(ALLEGRO_AUDIO_STREAM *stream)
421 {
422 FLACFILE *ff = stream->extra;
423 _al_acodec_stop_feed_thread(stream);
424
425 al_fclose(ff->fh);
426 al_free(ff->buffer);
427 flac_close(ff);
428 }
429
real_seek(ALLEGRO_AUDIO_STREAM * stream,uint64_t sample)430 static bool real_seek(ALLEGRO_AUDIO_STREAM *stream, uint64_t sample)
431 {
432 FLACFILE *ff = stream->extra;
433
434 /* We use ff->streamed_samples as the exact sample position for looping and
435 * returning the position. Therefore we also use it as reference position
436 * when seeking - that is, we call flush below to make the FLAC decoder
437 * discard any additional samples it may have buffered already.
438 * */
439 lib.FLAC__stream_decoder_flush(ff->decoder);
440 lib.FLAC__stream_decoder_seek_absolute(ff->decoder, sample);
441
442 ff->buffer_pos = 0;
443 ff->streamed_samples = sample;
444 ff->decoded_samples = sample;
445 return true;
446 }
447
flac_stream_seek(ALLEGRO_AUDIO_STREAM * stream,double time)448 static bool flac_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time)
449 {
450 FLACFILE *ff = stream->extra;
451 uint64_t sample = time * ff->sample_rate;
452 return real_seek(stream, sample);
453 }
454
flac_stream_rewind(ALLEGRO_AUDIO_STREAM * stream)455 static bool flac_stream_rewind(ALLEGRO_AUDIO_STREAM *stream)
456 {
457 FLACFILE *ff = stream->extra;
458 return real_seek(stream, ff->loop_start);
459 }
460
flac_stream_get_length(ALLEGRO_AUDIO_STREAM * stream)461 static double flac_stream_get_length(ALLEGRO_AUDIO_STREAM *stream)
462 {
463 FLACFILE *ff = stream->extra;
464 return ff->total_samples / ff->sample_rate;
465 }
466
flac_stream_set_loop(ALLEGRO_AUDIO_STREAM * stream,double start,double end)467 static bool flac_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream, double start,
468 double end)
469 {
470 FLACFILE *ff = stream->extra;
471 ff->loop_start = start * ff->sample_rate;
472 ff->loop_end = end * ff->sample_rate;
473 return true;
474 }
475
flac_open(ALLEGRO_FILE * f)476 static FLACFILE *flac_open(ALLEGRO_FILE* f)
477 {
478 FLACFILE *ff;
479 FLAC__StreamDecoderInitStatus init_status;
480
481 if (!init_dynlib()) {
482 return NULL;
483 }
484
485 ff = al_calloc(1, sizeof *ff);
486
487 ff->decoder = lib.FLAC__stream_decoder_new();
488 if (!ff->decoder) {
489 ALLEGRO_ERROR("Error allocating FLAC decoder\n");
490 goto error;
491 }
492
493 ff->fh = f;
494 if (!ff->fh) {
495 ALLEGRO_ERROR("Error opening FLAC file\n");
496 goto error;
497 }
498
499 init_status = lib.FLAC__stream_decoder_init_stream(ff->decoder, read_callback,
500 seek_callback, tell_callback, length_callback, eof_callback,
501 write_callback, metadata_callback, error_callback, ff);
502 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
503 #ifdef ALLEGRO_CFG_ACODEC_FLAC_DLL
504 ALLEGRO_ERROR("Error initializing FLAC decoder\n"); /* lazy */
505 #else
506 ALLEGRO_ERROR("Error initializing FLAC decoder: %s\n",
507 FLAC__StreamDecoderInitStatusString[init_status]);
508 #endif
509 goto error;
510 }
511
512 lib.FLAC__stream_decoder_process_until_end_of_metadata(ff->decoder);
513
514 if (ff->sample_size == 0) {
515 ALLEGRO_ERROR("Error: don't support sub 8-bit sizes\n");
516 goto error;
517 }
518
519 ALLEGRO_DEBUG("Loaded FLAC sample with properties:\n");
520 ALLEGRO_DEBUG(" channels %d\n", ff->channels);
521 ALLEGRO_DEBUG(" sample_size %d\n", ff->sample_size);
522 ALLEGRO_DEBUG(" rate %.f\n", ff->sample_rate);
523 ALLEGRO_DEBUG(" total_samples %ld\n", (long) ff->total_samples);
524
525 return ff;
526
527 error:
528 if (ff) {
529 if (ff->decoder)
530 lib.FLAC__stream_decoder_delete(ff->decoder);
531 al_free(ff);
532 }
533 return NULL;
534 }
535
_al_load_flac(const char * filename)536 ALLEGRO_SAMPLE *_al_load_flac(const char *filename)
537 {
538 ALLEGRO_FILE *f;
539 ALLEGRO_SAMPLE *spl;
540 ASSERT(filename);
541
542 f = al_fopen(filename, "rb");
543 if (!f) {
544 ALLEGRO_ERROR("Unable to open %s for reading.\n", filename);
545 return NULL;
546 }
547
548 spl = _al_load_flac_f(f);
549
550 al_fclose(f);
551
552 return spl;
553 }
554
_al_load_flac_f(ALLEGRO_FILE * f)555 ALLEGRO_SAMPLE *_al_load_flac_f(ALLEGRO_FILE *f)
556 {
557 ALLEGRO_SAMPLE *sample;
558 FLACFILE *ff;
559
560 ff = flac_open(f);
561 if (!ff) {
562 return NULL;
563 }
564
565 ff->buffer_size = ff->total_samples * ff->channels * ff->sample_size;
566 ff->buffer = al_malloc(ff->buffer_size);
567
568 lib.FLAC__stream_decoder_process_until_end_of_stream(ff->decoder);
569
570 sample = al_create_sample(ff->buffer, ff->total_samples, ff->sample_rate,
571 _al_word_size_to_depth_conf(ff->sample_size),
572 _al_count_to_channel_conf(ff->channels), true);
573
574 if (!sample) {
575 ALLEGRO_ERROR("Failed to create a sample.\n");
576 al_free(ff->buffer);
577 }
578
579 flac_close(ff);
580
581 return sample;
582 }
583
_al_load_flac_audio_stream(const char * filename,size_t buffer_count,unsigned int samples)584 ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream(const char *filename,
585 size_t buffer_count, unsigned int samples)
586 {
587 ALLEGRO_FILE *f;
588 ALLEGRO_AUDIO_STREAM *stream;
589 ASSERT(filename);
590
591 f = al_fopen(filename, "rb");
592 if (!f) {
593 ALLEGRO_ERROR("Unable to open %s for reading.\n", filename);
594 return NULL;
595 }
596
597 stream = _al_load_flac_audio_stream_f(f, buffer_count, samples);
598 if (!stream) {
599 al_fclose(f);
600 }
601
602 return stream;
603 }
604
_al_load_flac_audio_stream_f(ALLEGRO_FILE * f,size_t buffer_count,unsigned int samples)605 ALLEGRO_AUDIO_STREAM *_al_load_flac_audio_stream_f(ALLEGRO_FILE* f,
606 size_t buffer_count, unsigned int samples)
607 {
608 ALLEGRO_AUDIO_STREAM *stream;
609 FLACFILE *ff;
610
611 ff = flac_open(f);
612 if (!ff) {
613 return NULL;
614 }
615
616 stream = al_create_audio_stream(buffer_count, samples, ff->sample_rate,
617 _al_word_size_to_depth_conf(ff->sample_size),
618 _al_count_to_channel_conf(ff->channels));
619
620 if (stream) {
621 stream->extra = ff;
622 ff->loop_start = 0;
623 ff->loop_end = ff->total_samples;
624 stream->feeder = flac_stream_update;
625 stream->unload_feeder = flac_stream_close;
626 stream->rewind_feeder = flac_stream_rewind;
627 stream->seek_feeder = flac_stream_seek;
628 stream->get_feeder_position = flac_stream_get_position;
629 stream->get_feeder_length = flac_stream_get_length;
630 stream->set_feeder_loop = flac_stream_set_loop;
631 _al_acodec_start_feed_thread(stream);
632 }
633 else {
634 ALLEGRO_ERROR("Failed to create stream.\n");
635 al_fclose(ff->fh);
636 flac_close(ff);
637 }
638
639 return stream;
640 }
641
642
643 /* vim: set sts=3 sw=3 et: */
644