Add a MIDI "decoder" using Timidity
[alure.git] / src / stream.cpp
blobe8f4ac17f669d6c8d3d260996a97acbd46f51237
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (C) 2009 by Chris Robinson.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 /* Title: Streaming */
23 #include "config.h"
25 #include "main.h"
27 #include <string.h>
29 #include <algorithm>
30 #include <vector>
31 #include <memory>
32 #include <string>
33 #include <istream>
34 #include <fstream>
35 #include <iostream>
38 static inline ALuint read_le32(std::istream *file)
40 ALubyte buffer[4];
41 if(!file->read(reinterpret_cast<char*>(buffer), 4)) return 0;
42 return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24);
45 static inline ALushort read_le16(std::istream *file)
47 ALubyte buffer[2];
48 if(!file->read(reinterpret_cast<char*>(buffer), 2)) return 0;
49 return buffer[0] | (buffer[1]<<8);
52 static inline ALuint read_be32(std::istream *file)
54 ALubyte buffer[4];
55 if(!file->read(reinterpret_cast<char*>(buffer), 4)) return 0;
56 return (buffer[0]<<24) | (buffer[1]<<16) | (buffer[2]<<8) | buffer[3];
59 static inline ALushort read_be16(std::istream *file)
61 ALubyte buffer[2];
62 if(!file->read(reinterpret_cast<char*>(buffer), 2)) return 0;
63 return (buffer[0]<<8) | buffer[1];
66 static inline ALuint read_be80extended(std::istream *file)
68 ALubyte buffer[10];
69 if(!file->read(reinterpret_cast<char*>(buffer), 10)) return 0;
70 ALuint mantissa, last = 0;
71 ALubyte exp = buffer[1];
72 exp = 30 - exp;
73 mantissa = (buffer[2]<<24) | (buffer[3]<<16) | (buffer[4]<<8) | buffer[5];
74 while (exp--)
76 last = mantissa;
77 mantissa >>= 1;
79 if((last&1)) mantissa++;
80 return mantissa;
84 struct nullStream : public alureStream {
85 virtual bool IsValid() { return false; }
86 virtual bool GetFormat(ALenum*,ALuint*,ALuint*) { return false; }
87 virtual ALuint GetData(ALubyte*,ALuint) { return 0; }
88 virtual bool Rewind() { return false; }
89 nullStream(){}
93 struct customStream : public alureStream {
94 void *usrFile;
95 ALenum format;
96 ALuint samplerate;
97 ALuint blockAlign;
98 MemDataInfo memInfo;
100 UserCallbacks cb;
102 virtual bool IsValid()
103 { return usrFile != NULL; }
105 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
107 if(this->format == 0)
109 if(!cb.get_fmt ||
110 !cb.get_fmt(usrFile, &this->format, &samplerate, &blockAlign))
111 return false;
114 *format = this->format;
115 *frequency = samplerate;
116 *blockalign = blockAlign;
117 return true;
120 virtual ALuint GetData(ALubyte *data, ALuint bytes)
122 bytes -= bytes%blockAlign;
123 return cb.decode(usrFile, data, bytes);
126 virtual bool Rewind()
128 if(cb.rewind && cb.rewind(usrFile))
129 return true;
131 SetError("Rewind failed");
132 return false;
135 customStream(const char *fname, const UserCallbacks &callbacks)
136 : usrFile(NULL), format(0), samplerate(0), blockAlign(0), cb(callbacks)
138 if(cb.open_file)
139 usrFile = cb.open_file(fname);
141 customStream(const MemDataInfo &memData, const UserCallbacks &callbacks)
142 : usrFile(NULL), format(0), samplerate(0), blockAlign(0),
143 memInfo(memData), cb(callbacks)
145 if(cb.open_mem)
146 usrFile = cb.open_mem(memInfo.Data, memInfo.Length);
148 customStream(void *userdata, ALenum fmt, ALuint srate, const UserCallbacks &callbacks)
149 : usrFile(userdata), format(fmt), samplerate(srate), blockAlign(1), cb(callbacks)
152 virtual ~customStream()
154 if(cb.close && usrFile)
155 cb.close(usrFile);
156 usrFile = NULL;
160 struct wavStream : public alureStream {
161 ALenum format;
162 int samplerate;
163 int blockAlign;
164 int sampleSize;
165 long dataStart;
166 long dataLen;
167 size_t remLen;
169 virtual bool IsValid()
170 { return (dataStart > 0 && format != AL_NONE); }
172 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
174 *format = this->format;
175 *frequency = samplerate;
176 *blockalign = blockAlign;
177 return true;
180 virtual ALuint GetData(ALubyte *data, ALuint bytes)
182 static const union {
183 int val;
184 char b[sizeof(int)];
185 } endian = { 1 };
187 std::streamsize rem = ((remLen >= bytes) ? bytes : remLen) / blockAlign;
188 fstream->read(reinterpret_cast<char*>(data), rem*blockAlign);
190 std::streamsize got = fstream->gcount();
191 got -= got%blockAlign;
192 remLen -= got;
194 if(endian.b[0] == 0 && sampleSize > 1)
196 if(sampleSize == 2)
197 for(std::streamsize i = 0;i < got;i+=2)
199 ALubyte tmp = data[i];
200 data[i] = data[i+1];
201 data[i+1] = tmp;
203 else if(sampleSize == 4)
204 for(std::streamsize i = 0;i < got;i+=4)
206 ALubyte tmp = data[i];
207 data[i] = data[i+3];
208 data[i+3] = tmp;
209 tmp = data[i+1];
210 data[i+1] = data[i+2];
211 data[i+2] = tmp;
215 return got;
218 virtual bool Rewind()
220 fstream->clear();
221 if(fstream->seekg(dataStart))
223 remLen = dataLen;
224 return true;
227 SetError("Seek failed");
228 return false;
231 wavStream(std::istream *_fstream)
232 : alureStream(_fstream), format(0), dataStart(0)
233 { Init(); }
235 virtual ~wavStream()
238 private:
239 void Init()
241 ALubyte buffer[25];
242 int length;
244 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
245 memcmp(buffer, "RIFF", 4) != 0 || memcmp(buffer+8, "WAVE", 4) != 0)
246 return;
248 while(!dataStart || format == AL_NONE)
250 char tag[4];
251 if(!fstream->read(tag, 4))
252 break;
254 /* read chunk length */
255 length = read_le32(fstream);
257 if(memcmp(tag, "fmt ", 4) == 0 && length >= 16)
259 /* Data type (should be 1 for PCM data) */
260 int type = read_le16(fstream);
261 if(type != 1)
262 break;
264 /* mono or stereo data */
265 int channels = read_le16(fstream);
267 /* sample frequency */
268 samplerate = read_le32(fstream);
270 /* skip four bytes */
271 fstream->ignore(4);
273 /* bytes per block */
274 blockAlign = read_le16(fstream);
275 if(blockAlign == 0)
276 break;
278 /* bits per sample */
279 sampleSize = read_le16(fstream) / 8;
281 format = alureGetSampleFormat(channels, sampleSize*8, 0);
283 length -= 16;
285 else if(memcmp(tag, "data", 4) == 0)
287 dataStart = fstream->tellg();
288 dataLen = remLen = length;
291 fstream->seekg(length, std::ios_base::cur);
294 if(dataStart > 0 && format != AL_NONE)
295 fstream->seekg(dataStart);
299 struct aiffStream : public alureStream {
300 ALenum format;
301 int samplerate;
302 int blockAlign;
303 int sampleSize;
304 long dataStart;
305 long dataLen;
306 size_t remLen;
308 virtual bool IsValid()
309 { return (dataStart > 0 && format != AL_NONE); }
311 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
313 *format = this->format;
314 *frequency = samplerate;
315 *blockalign = blockAlign;
316 return true;
319 virtual ALuint GetData(ALubyte *data, ALuint bytes)
321 static const union {
322 int val;
323 char b[sizeof(int)];
324 } endian = { 1 };
326 std::streamsize rem = ((remLen >= bytes) ? bytes : remLen) / blockAlign;
327 fstream->read(reinterpret_cast<char*>(data), rem*blockAlign);
329 std::streamsize got = fstream->gcount();
330 got -= got%blockAlign;
331 remLen -= got;
333 if(endian.b[0] == 1 && sampleSize > 1)
335 if(sampleSize == 2)
336 for(std::streamsize i = 0;i < got;i+=2)
338 ALubyte tmp = data[i];
339 data[i] = data[i+1];
340 data[i+1] = tmp;
342 else if(sampleSize == 4)
343 for(std::streamsize i = 0;i < got;i+=4)
345 ALubyte tmp = data[i];
346 data[i] = data[i+3];
347 data[i+3] = tmp;
348 tmp = data[i+1];
349 data[i+1] = data[i+2];
350 data[i+2] = tmp;
354 return got;
357 virtual bool Rewind()
359 fstream->clear();
360 if(fstream->seekg(dataStart))
362 remLen = dataLen;
363 return true;
366 SetError("Seek failed");
367 return false;
370 aiffStream(std::istream *_fstream)
371 : alureStream(_fstream), format(0), dataStart(0)
372 { Init(); }
374 virtual ~aiffStream()
377 private:
378 void Init()
380 ALubyte buffer[25];
381 int length;
383 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
384 memcmp(buffer, "FORM", 4) != 0 || memcmp(buffer+8, "AIFF", 4) != 0)
385 return;
387 while(!dataStart || format == AL_NONE)
389 char tag[4];
390 if(!fstream->read(tag, 4))
391 break;
393 /* read chunk length */
394 length = read_be32(fstream);
396 if(memcmp(tag, "COMM", 4) == 0 && length >= 18)
398 /* mono or stereo data */
399 int channels = read_be16(fstream);
401 /* number of sample frames */
402 fstream->ignore(4);
404 /* bits per sample */
405 sampleSize = read_be16(fstream) / 8;
407 /* sample frequency */
408 samplerate = read_be80extended(fstream);
410 /* block alignment */
411 blockAlign = channels * sampleSize;
413 format = alureGetSampleFormat(channels, sampleSize*8, 0);
415 length -= 18;
417 else if(memcmp(tag, "SSND", 4) == 0)
419 dataStart = fstream->tellg();
420 dataStart += 8;
421 dataLen = remLen = length - 8;
424 fstream->seekg(length, std::ios_base::cur);
427 if(dataStart > 0 && format != AL_NONE)
428 fstream->seekg(dataStart);
432 #ifdef HAS_SNDFILE
433 struct sndStream : public alureStream {
434 SNDFILE *sndFile;
435 SF_INFO sndInfo;
437 virtual bool IsValid()
438 { return sndFile != NULL; }
440 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
442 *format = alureGetSampleFormat(sndInfo.channels, 16, 0);
443 *frequency = sndInfo.samplerate;
444 *blockalign = sndInfo.channels*2;
445 return true;
448 virtual ALuint GetData(ALubyte *data, ALuint bytes)
450 const ALuint frameSize = 2*sndInfo.channels;
451 return sf_readf_short(sndFile, (short*)data, bytes/frameSize) * frameSize;
454 virtual bool Rewind()
456 if(sf_seek(sndFile, 0, SEEK_SET) != -1)
457 return true;
459 SetError("Seek failed");
460 return false;
463 sndStream(std::istream *_fstream)
464 : alureStream(_fstream), sndFile(NULL)
466 memset(&sndInfo, 0, sizeof(sndInfo));
468 static SF_VIRTUAL_IO streamIO = {
469 get_filelen, seek,
470 read, write, tell
472 sndFile = sf_open_virtual(&streamIO, SFM_READ, &sndInfo, fstream);
475 virtual ~sndStream()
477 if(sndFile)
478 sf_close(sndFile);
479 sndFile = NULL;
482 private:
483 // libSndFile iostream callbacks
484 static sf_count_t get_filelen(void *user_data)
486 std::istream *stream = static_cast<std::istream*>(user_data);
487 stream->clear();
489 std::streampos len = -1;
490 std::streampos pos = stream->tellg();
491 if(stream->seekg(0, std::ios_base::end))
493 len = stream->tellg();
494 stream->seekg(pos);
497 return len;
500 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
502 std::istream *stream = static_cast<std::istream*>(user_data);
503 stream->clear();
505 if(whence == SEEK_CUR)
506 stream->seekg(offset, std::ios_base::cur);
507 else if(whence == SEEK_SET)
508 stream->seekg(offset, std::ios_base::beg);
509 else if(whence == SEEK_END)
510 stream->seekg(offset, std::ios_base::end);
511 else
512 return -1;
514 return stream->tellg();
517 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
519 std::istream *stream = static_cast<std::istream*>(user_data);
520 stream->clear();
521 stream->read(static_cast<char*>(ptr), count);
522 return stream->gcount();
525 static sf_count_t write(const void*, sf_count_t, void*)
526 { return -1; }
528 static sf_count_t tell(void *user_data)
530 std::istream *stream = static_cast<std::istream*>(user_data);
531 stream->clear();
532 return stream->tellg();
535 #else
536 struct sndStream : public nullStream {
537 sndStream(std::istream*){}
539 #endif
541 #ifdef HAS_VORBISFILE
542 struct oggStream : public alureStream {
543 OggVorbis_File *oggFile;
544 int oggBitstream;
546 virtual bool IsValid()
547 { return oggFile != NULL; }
549 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
551 vorbis_info *info = ov_info(oggFile, -1);
552 if(!info) return false;
554 *format = alureGetSampleFormat(info->channels, 16, 0);
555 *frequency = info->rate;
556 *blockalign = info->channels*2;
557 return true;
560 virtual ALuint GetData(ALubyte *data, ALuint bytes)
562 static const union {
563 short s;
564 char b[sizeof(short)];
565 } endian = { 0x0100 };
567 vorbis_info *info = ov_info(oggFile, -1);
568 if(!info) return 0;
570 ALuint blockAlign = info->channels*2;
571 bytes -= bytes%blockAlign;
573 int got = 0;
574 while(bytes > 0)
576 int res = ov_read(oggFile, (char*)&data[got], bytes, endian.b[0], 2, 1, &oggBitstream);
577 if(res <= 0)
578 break;
579 bytes -= res;
580 got += res;
582 return got;
585 virtual bool Rewind()
587 if(ov_pcm_seek(oggFile, 0) == 0)
588 return true;
590 SetError("Seek failed");
591 return false;
594 oggStream(std::istream *_fstream)
595 : alureStream(_fstream), oggFile(NULL), oggBitstream(0)
597 const ov_callbacks streamIO = {
598 read, seek, NULL, tell
601 oggFile = new OggVorbis_File;
602 if(ov_open_callbacks(this, oggFile, NULL, 0, streamIO) != 0)
604 delete oggFile;
605 oggFile = NULL;
609 virtual ~oggStream()
611 if(oggFile)
613 ov_clear(oggFile);
614 delete oggFile;
618 private:
619 // libVorbisFile iostream callbacks
620 static int seek(void *user_data, ogg_int64_t offset, int whence)
622 oggStream *This = static_cast<oggStream*>(user_data);
623 This->fstream->clear();
625 if(whence == SEEK_CUR)
626 This->fstream->seekg(offset, std::ios_base::cur);
627 else if(whence == SEEK_SET)
628 This->fstream->seekg(offset, std::ios_base::beg);
629 else if(whence == SEEK_END)
630 This->fstream->seekg(offset, std::ios_base::end);
631 else
632 return -1;
634 return This->fstream->tellg();
637 static size_t read(void *ptr, size_t size, size_t nmemb, void *user_data)
639 oggStream *This = static_cast<oggStream*>(user_data);
640 This->fstream->clear();
642 This->fstream->read(static_cast<char*>(ptr), nmemb*size);
643 size_t ret = This->fstream->gcount();
644 return ret/size;
647 static long tell(void *user_data)
649 oggStream *This = static_cast<oggStream*>(user_data);
650 This->fstream->clear();
651 return This->fstream->tellg();
654 #else
655 struct oggStream : public nullStream {
656 oggStream(std::istream*){}
658 #endif
660 #ifdef HAS_FLAC
661 struct flacStream : public alureStream {
662 FLAC__StreamDecoder *flacFile;
663 ALenum format;
664 ALuint samplerate;
665 ALuint blockAlign;
667 std::vector<ALubyte> initialData;
669 ALubyte *outBytes;
670 ALuint outLen;
671 ALuint outTotal;
673 virtual bool IsValid()
674 { return flacFile != NULL; }
676 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
678 *format = this->format;
679 *frequency = samplerate;
680 *blockalign = blockAlign;
681 return true;
684 virtual ALuint GetData(ALubyte *data, ALuint bytes)
686 bytes -= bytes%blockAlign;
688 outBytes = data;
689 outTotal = 0;
690 outLen = bytes;
692 if(initialData.size() > 0)
694 size_t rem = std::min(initialData.size(), (size_t)bytes);
695 memcpy(data, &initialData[0], rem);
696 outTotal += rem;
697 initialData.erase(initialData.begin(), initialData.begin()+rem);
700 while(outTotal < bytes)
702 if(FLAC__stream_decoder_process_single(flacFile) == false ||
703 FLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
704 break;
707 return outTotal;
710 virtual bool Rewind()
712 if(FLAC__stream_decoder_seek_absolute(flacFile, 0) != false)
714 initialData.clear();
715 return true;
718 SetError("Seek failed");
719 return false;
722 flacStream(std::istream *_fstream)
723 : alureStream(_fstream), flacFile(NULL)
725 flacFile = FLAC__stream_decoder_new();
726 if(flacFile)
728 if(FLAC__stream_decoder_init_stream(flacFile, ReadCallback, SeekCallback, TellCallback, LengthCallback, EofCallback, WriteCallback, MetadataCallback, ErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK)
730 if(InitFlac())
732 // all ok
733 return;
736 FLAC__stream_decoder_finish(flacFile);
738 FLAC__stream_decoder_delete(flacFile);
739 flacFile = NULL;
743 virtual ~flacStream()
745 if(flacFile)
747 FLAC__stream_decoder_finish(flacFile);
748 FLAC__stream_decoder_delete(flacFile);
749 flacFile = NULL;
753 private:
754 bool InitFlac()
756 // We need to decode some data to be able to get the channel count, bit
757 // depth, and sample rate. It also ensures the file has FLAC data, as
758 // the FLAC__stream_decoder_init_* functions can succeed on non-FLAC
759 // Ogg files.
760 outLen = 0;
761 outTotal = 0;
762 while(initialData.size() == 0)
764 if(FLAC__stream_decoder_process_single(flacFile) == false ||
765 FLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
766 break;
769 if(initialData.size() > 0)
771 blockAlign = FLAC__stream_decoder_get_channels(flacFile) *
772 FLAC__stream_decoder_get_bits_per_sample(flacFile)/8;
773 samplerate = FLAC__stream_decoder_get_sample_rate(flacFile);
774 format = alureGetSampleFormat(FLAC__stream_decoder_get_channels(flacFile),
775 FLAC__stream_decoder_get_bits_per_sample(flacFile), 0);
776 return true;
778 return false;
781 static FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder*, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
783 flacStream *This = static_cast<flacStream*>(client_data);
784 ALubyte *data = This->outBytes + This->outTotal;
785 ALuint i = 0;
787 while(This->outTotal < This->outLen && i < frame->header.blocksize)
789 for(ALuint c = 0;c < frame->header.channels;c++)
791 if(frame->header.bits_per_sample == 8)
792 *((ALubyte*)data) = buffer[c][i]+128;
793 else if(frame->header.bits_per_sample == 16)
794 *((ALshort*)data) = buffer[c][i];
795 This->outTotal += frame->header.bits_per_sample/8;
796 data += frame->header.bits_per_sample/8;
798 i++;
801 if(i < frame->header.blocksize)
803 ALuint blocklen = (frame->header.blocksize-i) *
804 frame->header.channels *
805 frame->header.bits_per_sample/8;
806 ALuint start = This->initialData.size();
808 This->initialData.resize(start+blocklen);
809 data = &This->initialData[start];
811 while(i < frame->header.blocksize)
813 for(ALuint c = 0;c < frame->header.channels;c++)
815 if(frame->header.bits_per_sample == 8)
816 *((ALubyte*)data) = buffer[c][i]+128;
817 else if(frame->header.bits_per_sample == 16)
818 *((ALshort*)data) = buffer[c][i];
819 data += frame->header.bits_per_sample/8;
821 i++;
825 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
827 static void MetadataCallback(const FLAC__StreamDecoder*,const FLAC__StreamMetadata*,void*)
830 static void ErrorCallback(const FLAC__StreamDecoder*,FLAC__StreamDecoderErrorStatus,void*)
834 static FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t *bytes, void *client_data)
836 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
837 stream->clear();
839 if(*bytes <= 0)
840 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
842 stream->read(reinterpret_cast<char*>(buffer), *bytes);
843 *bytes = stream->gcount();
844 if(*bytes == 0 && stream->eof())
845 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
847 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
849 static FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void *client_data)
851 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
852 stream->clear();
854 if(!stream->seekg(absolute_byte_offset))
855 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
856 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
858 static FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder*, FLAC__uint64 *absolute_byte_offset, void *client_data)
860 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
861 stream->clear();
863 *absolute_byte_offset = stream->tellg();
864 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
866 static FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder*, FLAC__uint64 *stream_length, void *client_data)
868 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
869 stream->clear();
871 std::streampos pos = stream->tellg();
872 if(stream->seekg(0, std::ios_base::end))
874 *stream_length = stream->tellg();
875 stream->seekg(pos);
878 if(!stream->good())
879 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
880 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
882 static FLAC__bool EofCallback(const FLAC__StreamDecoder*, void *client_data)
884 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
885 return (stream->eof()) ? true : false;
888 #else
889 struct flacStream : public nullStream {
890 flacStream(std::istream*){}
892 #endif
895 #ifdef HAS_MPG123
896 struct mp3Stream : public alureStream {
897 mpg123_handle *mp3File;
898 long samplerate;
899 int channels;
900 std::istream *fstream;
902 virtual bool IsValid()
903 { return mp3File != NULL; }
905 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
907 ALenum fmt = alureGetSampleFormat(channels, 16, 0);
909 *format = fmt;
910 *frequency = samplerate;
911 *blockalign = channels*2;
912 return true;
915 virtual ALuint GetData(ALubyte *data, ALuint bytes)
917 const ALuint blockAlign = channels*2;
918 bytes -= bytes%blockAlign;
920 ALuint amt = 0;
921 do {
922 size_t got = 0;
923 int ret = mpg123_read(mp3File, data, bytes, &got);
925 bytes -= got;
926 data += got;
927 amt += got;
929 if(ret == MPG123_NEED_MORE)
931 unsigned char data[4096];
932 fstream->read((char*)data, sizeof(data));
933 std::streamsize insize = fstream->gcount();;
934 if(insize > 0 &&
935 mpg123_decode(mp3File, data, insize, NULL, 0, NULL) == MPG123_OK)
936 continue;
939 return amt;
940 } while(1);
943 virtual bool Rewind()
945 fstream->clear();
946 std::istream::pos_type oldpos = fstream->tellg();
947 fstream->seekg(0);
949 mpg123_handle *newFile = mpg123_new(NULL, NULL);
950 if(mpg123_open_feed(newFile) == MPG123_OK)
952 unsigned char data[4096];
953 long newrate;
954 int newchans;
955 int ret, enc;
957 ALuint amt, total = 0;
958 do {
959 fstream->read((char*)data, sizeof(data));
960 amt = fstream->gcount();
961 if(amt == 0) break;
962 total += amt;
963 ret = mpg123_decode(newFile, data, amt, NULL, 0, NULL);
964 } while(ret == MPG123_NEED_MORE && total < 64*1024);
966 if(ret == MPG123_NEW_FORMAT &&
967 mpg123_getformat(newFile, &newrate, &newchans, &enc) == MPG123_OK)
969 if(newrate == samplerate && newchans == channels &&
970 (enc == MPG123_ENC_SIGNED_16 ||
971 (mpg123_format_none(newFile) == MPG123_OK &&
972 mpg123_format(newFile, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)))
974 // All OK
975 mpg123_delete(mp3File);
976 mp3File = newFile;
977 return true;
980 mpg123_delete(newFile);
983 fstream->seekg(oldpos);
984 SetError("Restart failed");
985 return false;
988 mp3Stream(std::istream *_fstream)
989 : mp3File(NULL), fstream(_fstream)
991 mp3File = mpg123_new(NULL, NULL);
992 if(mpg123_open_feed(mp3File) == MPG123_OK)
994 unsigned char data[4096];
995 int ret, enc;
997 ALuint amt, total = 0;
998 do {
999 fstream->read((char*)data, sizeof(data));
1000 amt = fstream->gcount();
1001 if(amt == 0) break;
1002 total += amt;
1003 ret = mpg123_decode(mp3File, data, amt, NULL, 0, NULL);
1004 } while(ret == MPG123_NEED_MORE && total < 64*1024);
1006 if(ret == MPG123_NEW_FORMAT &&
1007 mpg123_getformat(mp3File, &samplerate, &channels, &enc) == MPG123_OK)
1009 if(enc == MPG123_ENC_SIGNED_16 ||
1010 (mpg123_format_none(mp3File) == MPG123_OK &&
1011 mpg123_format(mp3File, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK))
1013 // All OK
1014 return;
1018 mpg123_delete(mp3File);
1019 mp3File = NULL;
1022 virtual ~mp3Stream()
1024 if(mp3File)
1025 mpg123_delete(mp3File);
1026 mp3File = NULL;
1029 #else
1030 struct mp3Stream : public nullStream {
1031 mp3Stream(std::istream*){}
1033 #endif
1036 #ifdef HAS_DUMB
1037 struct dumbStream : public alureStream {
1038 DUMBFILE_SYSTEM vfs;
1039 DUMBFILE *dumbFile;
1040 DUH *duh;
1041 DUH_SIGRENDERER *renderer;
1042 std::vector<sample_t> sampleBuf;
1043 ALuint lastOrder;
1044 int prevSpeed;
1045 ALenum format;
1047 virtual bool IsValid()
1048 { return renderer != NULL; }
1050 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
1052 if(format == AL_NONE)
1054 format = alureGetSampleFormat(2, 0, 32);
1055 if(format == AL_NONE)
1056 format = AL_FORMAT_STEREO16;
1058 *fmt = format;
1059 *frequency = 65536;
1060 *blockalign = 2 * ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) :
1061 sizeof(ALfloat));
1062 return true;
1065 virtual ALuint GetData(ALubyte *data, ALuint bytes)
1067 ALuint ret = 0;
1069 if(dumb_it_sr_get_speed(duh_get_it_sigrenderer(renderer)) == 0)
1070 return 0;
1072 ALuint sample_count = bytes / ((format==AL_FORMAT_STEREO16) ?
1073 sizeof(ALshort) : sizeof(ALfloat));
1075 sampleBuf.resize(sample_count);
1076 sample_t *samples = &sampleBuf[0];
1078 dumb_silence(samples, sample_count);
1079 ret = duh_sigrenderer_generate_samples(renderer, 1.0f, 1.0f, sample_count/2, &samples);
1080 ret *= 2;
1081 if(format == AL_FORMAT_STEREO16)
1083 for(ALuint i = 0;i < ret;i++)
1084 ((ALshort*)data)[i] = clamp(samples[i]>>8, -32768, 32767);
1086 else
1088 for(ALuint i = 0;i < ret;i++)
1089 ((ALfloat*)data)[i] = ((samples[i]>=0) ?
1090 samples[i]/(float)0x7FFFFF :
1091 samples[i]/(float)0x800000);
1093 ret *= ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) : sizeof(ALfloat));
1095 return ret;
1098 virtual bool Rewind()
1100 if(prevSpeed)
1102 // If a previous speed was recorded, the stream tried to loop. So
1103 // let it loop on a rewind request.
1104 dumb_it_sr_set_speed(duh_get_it_sigrenderer(renderer), prevSpeed);
1105 prevSpeed = 0;
1106 return true;
1109 // Else, no loop point. Restart from scratch.
1110 DUH_SIGRENDERER *newrenderer;
1111 newrenderer = (lastOrder ? dumb_it_start_at_order(duh, 2, lastOrder) :
1112 duh_start_sigrenderer(duh, 0, 2, 0));
1113 if(!newrenderer)
1115 SetError("Could start renderer");
1116 return false;
1118 duh_end_sigrenderer(renderer);
1119 renderer = newrenderer;
1120 return true;
1123 virtual bool SetOrder(ALuint order)
1125 DUH_SIGRENDERER *newrenderer = dumb_it_start_at_order(duh, 2, order);
1126 if(!newrenderer)
1128 SetError("Could not set order");
1129 return false;
1131 duh_end_sigrenderer(renderer);
1132 renderer = newrenderer;
1134 lastOrder = order;
1135 return true;
1138 dumbStream(std::istream *_fstream)
1139 : alureStream(_fstream), dumbFile(NULL), duh(NULL), renderer(NULL),
1140 lastOrder(0), prevSpeed(0), format(AL_NONE)
1142 DUH* (*funcs[])(DUMBFILE*) = {
1143 dumb_read_it_quick,
1144 dumb_read_xm_quick,
1145 dumb_read_s3m_quick,
1146 dumb_read_mod_quick,
1147 NULL
1150 vfs.open = NULL;
1151 vfs.skip = skip;
1152 vfs.getc = read_char;
1153 vfs.getnc = read;
1154 vfs.close = NULL;
1156 for(size_t i = 0;funcs[i];i++)
1158 dumbFile = dumbfile_open_ex(this, &vfs);
1159 if(dumbFile)
1161 duh = funcs[i](dumbFile);
1162 if(duh)
1164 renderer = duh_start_sigrenderer(duh, 0, 2, 0);
1165 if(renderer)
1167 dumb_it_set_loop_callback(duh_get_it_sigrenderer(renderer), loop_cb, this);
1168 break;
1171 unload_duh(duh);
1172 duh = NULL;
1175 dumbfile_close(dumbFile);
1176 dumbFile = NULL;
1178 fstream->clear();
1179 fstream->seekg(0);
1183 virtual ~dumbStream()
1185 duh_end_sigrenderer(renderer);
1186 renderer = NULL;
1188 unload_duh(duh);
1189 duh = NULL;
1191 if(dumbFile)
1192 dumbfile_close(dumbFile);
1193 dumbFile = NULL;
1196 private:
1197 // DUMBFILE iostream callbacks
1198 static int skip(void *user_data, long offset)
1200 dumbStream *This = static_cast<dumbStream*>(user_data);
1201 This->fstream->clear();
1203 if(This->fstream->seekg(offset, std::ios_base::cur))
1204 return 0;
1205 return -1;
1208 static long read(char *ptr, long size, void *user_data)
1210 dumbStream *This = static_cast<dumbStream*>(user_data);
1211 This->fstream->clear();
1213 This->fstream->read(static_cast<char*>(ptr), size);
1214 return This->fstream->gcount();
1217 static int read_char(void *user_data)
1219 dumbStream *This = static_cast<dumbStream*>(user_data);
1220 This->fstream->clear();
1222 unsigned char ret;
1223 This->fstream->read(reinterpret_cast<char*>(&ret), 1);
1224 if(This->fstream->gcount() > 0)
1225 return ret;
1226 return -1;
1229 static int loop_cb(void *user_data)
1231 dumbStream *This = static_cast<dumbStream*>(user_data);
1232 This->prevSpeed = dumb_it_sr_get_speed(duh_get_it_sigrenderer(This->renderer));
1233 dumb_it_sr_set_speed(duh_get_it_sigrenderer(This->renderer), 0);
1234 return 0;
1237 #else
1238 struct dumbStream : public nullStream {
1239 dumbStream(std::istream*){}
1241 #endif
1244 #ifdef HAS_TIMIDITY
1245 struct midiStream : public alureStream {
1246 int pcmFile;
1247 pid_t cpid;
1248 int initialByte;
1250 static const ALuint Freq = 48000;
1252 virtual bool IsValid()
1253 { return cpid > 0; }
1255 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
1257 *fmt = AL_FORMAT_STEREO16;
1258 *frequency = Freq;
1259 *blockalign = 4;
1260 return true;
1263 virtual ALuint GetData(ALubyte *data, ALuint bytes)
1265 ALuint total = 0;
1266 if(initialByte != -1 && bytes > 0)
1268 *(data++) = initialByte&0xff;
1269 bytes--;
1270 initialByte = -1;
1272 while(bytes > 0)
1274 ssize_t got = read(pcmFile, data, bytes);
1275 if(got == -1 && errno == EINTR)
1276 continue;
1277 if(got <= 0)
1278 break;
1280 data += got;
1281 bytes -= got;
1282 total += got;
1284 return total;
1287 virtual bool Rewind()
1289 fstream->clear();
1290 fstream->seekg(0);
1292 int _pcmFile; pid_t _cpid;
1293 if(!StartStream(_pcmFile, _cpid))
1295 SetError("Failed to restart timidity");
1296 return false;
1299 kill(cpid, SIGTERM);
1300 waitpid(cpid, NULL, 0);
1301 cpid = _cpid;
1303 close(pcmFile);
1304 pcmFile = _pcmFile;
1306 return true;
1309 midiStream(std::istream *_fstream)
1310 : alureStream(_fstream), pcmFile(-1), cpid(-1), initialByte(-1)
1312 StartStream(pcmFile, cpid);
1315 virtual ~midiStream()
1317 if(cpid > 0)
1319 kill(cpid, SIGTERM);
1320 waitpid(cpid, NULL, 0);
1321 cpid = -1;
1323 if(pcmFile != -1)
1324 close(pcmFile);
1325 pcmFile = -1;
1328 private:
1329 bool StartStream(int &pcmFile, pid_t &pid)
1331 int midPipe[2] = { -1, -1 };
1332 int pcmPipe[2] = { -1, -1 };
1334 char hdr[4];
1335 std::vector<ALubyte> midiData;
1337 fstream->read(hdr, sizeof(hdr));
1338 if(fstream->gcount() != sizeof(hdr))
1339 return false;
1341 if(memcmp(hdr, "MThd", 4) == 0)
1343 char ch;
1344 for(size_t i = 0;i < sizeof(hdr);i++)
1345 midiData.push_back(hdr[i]);
1346 while(fstream->get(ch))
1347 midiData.push_back(ch);
1349 else
1350 return false;
1352 if(pipe(midPipe) == -1)
1353 return false;
1354 if(pipe(pcmPipe) == -1)
1356 close(midPipe[0]); midPipe[0] = -1;
1357 close(midPipe[1]); midPipe[1] = -1;
1358 return false;
1361 pid = fork();
1362 if(pid == 0)
1364 dup2(midPipe[0], STDIN_FILENO);
1365 dup2(pcmPipe[1], STDOUT_FILENO);
1367 close(midPipe[0]); midPipe[0] = -1;
1368 close(midPipe[1]); midPipe[1] = -1;
1369 close(pcmPipe[0]); pcmPipe[0] = -1;
1370 close(pcmPipe[1]); pcmPipe[1] = -1;
1372 execlp("timidity","timidity", "-", "-idqq", "-Or1sl", "-s", "48000",
1373 "-o", "-", NULL);
1374 _exit(1);
1376 else if(pid > 0)
1378 close(midPipe[0]); midPipe[0] = -1;
1379 close(pcmPipe[1]); pcmPipe[1] = -1;
1381 const ALubyte *cur = &midiData[0];
1382 size_t rem = midiData.size();
1383 do {
1384 ssize_t wrote = write(midPipe[1], cur, rem);
1385 if(wrote < 0)
1387 if(errno == EINTR)
1388 continue;
1389 break;
1391 cur += wrote;
1392 rem -= wrote;
1393 } while(rem > 0);
1394 close(midPipe[1]); midPipe[1] = -1;
1396 ALubyte ch = 0;
1397 ssize_t got;
1398 while((got=read(pcmPipe[0], &ch, 1)) == -1 && errno == EINTR)
1400 if(got != 1)
1402 kill(pid, SIGTERM);
1403 waitpid(pid, NULL, 0); pid = -1;
1404 close(pcmPipe[0]); pcmPipe[0] = -1;
1405 return false;
1407 initialByte = ch;
1409 else
1411 close(midPipe[0]); midPipe[0] = -1;
1412 close(midPipe[1]); midPipe[1] = -1;
1413 close(pcmPipe[0]); pcmPipe[0] = -1;
1414 close(pcmPipe[1]); pcmPipe[1] = -1;
1415 return false;
1418 pcmFile = pcmPipe[0];
1419 return true;
1422 #else
1423 struct midiStream : public nullStream {
1424 midiStream(std::istream*){}
1426 #endif
1429 #ifdef HAS_GSTREAMER
1430 struct gstStream : public alureStream {
1431 GstElement *gstPipeline;
1433 ALenum format;
1434 ALuint samplerate;
1435 ALuint blockAlign;
1437 std::vector<ALubyte> initialData;
1439 ALubyte *outBytes;
1440 ALuint outLen;
1441 ALuint outTotal;
1443 virtual bool IsValid()
1444 { return gstPipeline != NULL; }
1446 virtual bool GetFormat(ALenum *format, ALuint *frequency, ALuint *blockalign)
1448 *format = this->format;
1449 *frequency = samplerate;
1450 *blockalign = blockAlign;
1451 return true;
1454 virtual ALuint GetData(ALubyte *data, ALuint bytes)
1456 bytes -= bytes%blockAlign;
1458 outTotal = 0;
1459 outLen = bytes;
1460 outBytes = data;
1462 if(initialData.size() > 0)
1464 size_t rem = std::min(initialData.size(), (size_t)bytes);
1465 memcpy(data, &initialData[0], rem);
1466 outTotal += rem;
1467 initialData.erase(initialData.begin(), initialData.begin()+rem);
1470 GstElement *gstSink = gst_bin_get_by_name(GST_BIN(gstPipeline), "alureSink");
1471 while(outTotal < outLen && !gst_app_sink_is_eos((GstAppSink*)gstSink))
1472 on_new_buffer_from_source(gstSink);
1473 gst_object_unref(gstSink);
1475 return outTotal;
1478 virtual bool Rewind()
1480 GstSeekFlags flags = GstSeekFlags(GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_KEY_UNIT);
1481 if(gst_element_seek_simple(gstPipeline, GST_FORMAT_TIME, flags, 0))
1483 initialData.clear();
1484 return true;
1487 SetError("Seek failed");
1488 return false;
1491 gstStream(std::istream *_fstream)
1492 : alureStream(_fstream), gstPipeline(NULL), format(AL_NONE), outBytes(NULL),
1493 outLen(0), outTotal(0)
1494 { Init(); }
1496 virtual ~gstStream()
1498 if(gstPipeline)
1500 gst_element_set_state(gstPipeline, GST_STATE_NULL);
1501 gst_object_unref(gstPipeline);
1502 gstPipeline = NULL;
1506 private:
1507 void Init()
1509 fstream->seekg(0, std::ios_base::end);
1510 std::streamsize len = fstream->tellg();
1511 fstream->seekg(0, std::ios_base::beg);
1513 if(!fstream->good() || len <= 0)
1514 return;
1516 std::string gst_audio_caps;
1517 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
1519 static const struct {
1520 const char *ename;
1521 const char *chans;
1522 const char *order;
1523 } fmts32[] = {
1524 { "AL_FORMAT_71CHN32", "8", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT" },
1525 { "AL_FORMAT_51CHN32", "6", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1526 { "AL_FORMAT_QUAD32", "4", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1527 { "AL_FORMAT_STEREO_FLOAT32", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1528 { "AL_FORMAT_MONO_FLOAT32", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1529 { NULL, NULL, NULL }
1530 }, fmts16[] = {
1531 { "AL_FORMAT_71CHN16", "8", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT" },
1532 { "AL_FORMAT_51CHN16", "6", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1533 { "AL_FORMAT_QUAD16", "4", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1534 { "AL_FORMAT_STEREO16", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1535 { "AL_FORMAT_MONO16", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1536 { NULL, NULL, NULL }
1537 }, fmts8[] = {
1538 { "AL_FORMAT_71CHN8", "8", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT" },
1539 { "AL_FORMAT_51CHN8", "6", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1540 { "AL_FORMAT_QUAD8", "4", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT" },
1541 { "AL_FORMAT_STEREO8", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1542 { "AL_FORMAT_MONO8", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1543 { NULL, NULL, NULL }
1546 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
1548 for(int i = 0;fmts32[i].ename;i++)
1550 if(alGetEnumValue(fmts32[i].ename) == 0)
1551 continue;
1553 gst_audio_caps +=
1554 "audio/x-raw-float, \n\t"
1555 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER) " }, \n\t"
1556 "signed = (boolean) TRUE, \n\t"
1557 "width = (int) 32, \n\t"
1558 "depth = (int) 32, \n\t"
1559 "rate = (int) [ 1, MAX ], \n\t"
1560 "channels = (int) ";
1561 gst_audio_caps += fmts32[i].chans;
1562 gst_audio_caps += ", \n\t"
1563 "channel-positions = (GstAudioChannelPosition) < ";
1564 gst_audio_caps += fmts32[i].order;
1565 gst_audio_caps += " >; \n";
1568 for(int i = 0;fmts16[i].ename;i++)
1570 if(alGetEnumValue(fmts16[i].ename) == 0)
1571 continue;
1573 gst_audio_caps +=
1574 "audio/x-raw-int, \n\t"
1575 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER) " }, \n\t"
1576 "signed = (boolean) TRUE, \n\t"
1577 "width = (int) 16, \n\t"
1578 "depth = (int) 16, \n\t"
1579 "rate = (int) [ 1, MAX ], \n\t"
1580 "channels = (int) ";
1581 gst_audio_caps += fmts16[i].chans;
1582 gst_audio_caps += ", \n\t"
1583 "channel-positions = (GstAudioChannelPosition) < ";
1584 gst_audio_caps += fmts16[i].order;
1585 gst_audio_caps += " >; \n";
1587 for(int i = 0;fmts8[i].ename;i++)
1589 if(alGetEnumValue(fmts8[i].ename) == 0)
1590 continue;
1592 gst_audio_caps +=
1593 "audio/x-raw-int, \n\t"
1594 "signed = (boolean) FALSE, \n\t"
1595 "width = (int) 8, \n\t"
1596 "depth = (int) 8, \n\t"
1597 "rate = (int) [ 1, MAX ], \n\t"
1598 "channels = (int) ";
1599 gst_audio_caps += fmts8[i].chans;
1600 gst_audio_caps += ", \n\t"
1601 "channel-positions = (GstAudioChannelPosition) < ";
1602 gst_audio_caps += fmts8[i].order;
1603 gst_audio_caps += " >; \n";
1606 else
1608 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
1610 gst_audio_caps +=
1611 "audio/x-raw-float, \n\t"
1612 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER) " }, \n\t"
1613 "signed = (boolean) TRUE, \n\t"
1614 "width = (int) 32, \n\t"
1615 "depth = (int) 32, \n\t"
1616 "rate = (int) [ 1, MAX ], \n\t"
1617 "channels = (int) [ 1, 2 ]; \n";
1619 gst_audio_caps +=
1620 "audio/x-raw-int, \n\t"
1621 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER) " }, \n\t"
1622 "signed = (boolean) TRUE, \n\t"
1623 "width = (int) 16, \n\t"
1624 "depth = (int) 16, \n\t"
1625 "rate = (int) [ 1, MAX ], \n\t"
1626 "channels = (int) [ 1, 2 ]; \n";
1627 gst_audio_caps +=
1628 "audio/x-raw-int, \n\t"
1629 "signed = (boolean) FALSE, \n\t"
1630 "width = (int) 8, \n\t"
1631 "depth = (int) 8, \n\t"
1632 "rate = (int) [ 1, MAX ], \n\t"
1633 "channels = (int) [ 1, 2 ]; \n";
1636 gchar *string = g_strdup_printf("appsrc name=alureSrc ! decodebin ! audioconvert ! appsink caps=\"%s\" name=alureSink", gst_audio_caps.c_str());
1637 gstPipeline = gst_parse_launch(string, NULL);
1638 g_free(string);
1640 if(!gstPipeline)
1641 return;
1643 GstElement *gstSrc = gst_bin_get_by_name(GST_BIN(gstPipeline), "alureSrc");
1644 GstElement *gstSink = gst_bin_get_by_name(GST_BIN(gstPipeline), "alureSink");
1646 if(gstSrc && gstSink)
1648 g_object_set(G_OBJECT(gstSrc), "size", (gint64)len, NULL);
1649 g_object_set(G_OBJECT(gstSrc), "stream-type", 2, NULL);
1651 /* configure the appsrc, we will push a buffer to appsrc when it
1652 * needs more data */
1653 g_signal_connect(gstSrc, "need-data", G_CALLBACK(feed_data), this);
1654 g_signal_connect(gstSrc, "seek-data", G_CALLBACK(seek_data), this);
1656 g_object_set(G_OBJECT(gstSink), "preroll-queue-len", 1, NULL);
1657 g_object_set(G_OBJECT(gstSink), "max-buffers", 2, NULL);
1658 g_object_set(G_OBJECT(gstSink), "drop", FALSE, NULL);
1659 g_object_set(G_OBJECT(gstSink), "sync", FALSE, NULL);
1661 GstBus *bus = gst_element_get_bus(gstPipeline);
1662 if(bus)
1664 const GstMessageType types = GstMessageType(GST_MESSAGE_ERROR|GST_MESSAGE_ASYNC_DONE);
1665 GstMessage *msg;
1667 gst_element_set_state(gstPipeline, GST_STATE_PLAYING);
1668 while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL)
1670 if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ASYNC_DONE)
1672 on_new_preroll_from_source(gstSink);
1673 gst_message_unref(msg);
1674 break;
1677 if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
1679 gchar *debug;
1680 GError *error;
1682 gst_message_parse_error(msg, &error, &debug);
1683 g_printerr("GST Error: %s\n", error->message);
1685 g_free(debug);
1686 g_error_free(error);
1688 gst_message_unref(msg);
1689 break;
1691 gst_message_unref(msg);
1694 gst_object_unref(bus);
1695 bus = NULL;
1699 if(gstSrc) gst_object_unref(gstSrc);
1700 if(gstSink) gst_object_unref(gstSink);
1702 if(format == AL_NONE)
1704 gst_element_set_state(gstPipeline, GST_STATE_NULL);
1705 gst_object_unref(gstPipeline);
1706 gstPipeline = NULL;
1710 void on_new_preroll_from_source(GstElement *elt)
1712 // get the buffer from appsink
1713 GstBuffer *buffer = gst_app_sink_pull_preroll(GST_APP_SINK(elt));
1714 if(!buffer)
1715 return;
1717 if(format == AL_NONE)
1719 GstCaps *caps = GST_BUFFER_CAPS(buffer);
1720 //GST_LOG("caps are %" GST_PTR_FORMAT, caps);
1722 ALint i;
1723 gint rate = 0, channels = 0, bits = 0;
1724 for(i = gst_caps_get_size(caps)-1;i >= 0;i--)
1726 GstStructure *struc = gst_caps_get_structure(caps, i);
1727 if(gst_structure_has_field(struc, "channels"))
1728 gst_structure_get_int(struc, "channels", &channels);
1729 if(gst_structure_has_field(struc, "rate"))
1730 gst_structure_get_int(struc, "rate", &rate);
1731 if(gst_structure_has_field(struc, "width"))
1732 gst_structure_get_int(struc, "width", &bits);
1735 samplerate = rate;
1736 if(bits == 32)
1737 format = alureGetSampleFormat(channels, 0, bits);
1738 else
1739 format = alureGetSampleFormat(channels, bits, 0);
1740 blockAlign = channels * bits / 8;
1743 /* we don't need the appsink buffer anymore */
1744 gst_buffer_unref(buffer);
1747 void on_new_buffer_from_source(GstElement *elt)
1749 // get the buffer from appsink
1750 GstBuffer *buffer = gst_app_sink_pull_buffer(GST_APP_SINK(elt));
1751 if(!buffer)
1752 return;
1754 ALubyte *src_buffer = (ALubyte*)(GST_BUFFER_DATA(buffer));
1755 guint size = GST_BUFFER_SIZE(buffer);
1756 guint rem = std::min(size, outLen-outTotal);
1757 if(rem > 0)
1758 memcpy(outBytes+outTotal, src_buffer, rem);
1759 outTotal += rem;
1761 if(size > rem)
1763 size_t start = initialData.size();
1764 initialData.resize(start+size-rem);
1765 memcpy(&initialData[start], src_buffer+rem, initialData.size()-start);
1768 /* we don't need the appsink buffer anymore */
1769 gst_buffer_unref(buffer);
1772 static void feed_data(GstElement *appsrc, guint size, gstStream *app)
1774 GstFlowReturn ret;
1776 if(!app->fstream->good())
1778 // we are EOS, send end-of-stream
1779 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
1780 return;
1783 // read any amount of data, we are allowed to return less if we are EOS
1784 GstBuffer *buffer = gst_buffer_new();
1785 void *data = g_malloc(size);
1787 app->fstream->read(static_cast<char*>(data), size);
1789 GST_BUFFER_SIZE(buffer) = app->fstream->gcount();
1790 GST_BUFFER_MALLOCDATA(buffer) = static_cast<guint8*>(data);
1791 GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer);
1793 //GST_DEBUG("feed buffer %p, %u", buffer, GST_BUFFER_SIZE(buffer));
1794 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
1795 gst_buffer_unref(buffer);
1798 static gboolean seek_data(GstElement */*appsrc*/, guint64 position, gstStream *app)
1800 //GST_DEBUG("seek to offset %" G_GUINT64_FORMAT, position);
1801 app->fstream->clear();
1802 return (app->fstream->seekg(position) ? TRUE : FALSE);
1805 #else
1806 struct gstStream : public nullStream {
1807 gstStream(std::istream*){}
1809 #endif
1812 template <typename T>
1813 alureStream *create_stream(const T &fdata)
1815 alureStream *stream;
1817 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.begin();
1818 while(i != InstalledCallbacks.end() && i->first < 0)
1820 stream = new customStream(fdata, i->second);
1821 if(stream->IsValid())
1822 return stream;
1823 delete stream;
1824 i++;
1827 InStream *file = new InStream(fdata);
1828 if(file->IsOpen())
1830 stream = new wavStream(file);
1831 if(stream->IsValid())
1832 return stream;
1833 delete stream;
1835 file->clear();
1836 file->seekg(0, std::ios_base::beg);
1837 stream = new aiffStream(file);
1838 if(stream->IsValid())
1839 return stream;
1840 delete stream;
1842 // Try libVorbisFile
1843 file->clear();
1844 file->seekg(0, std::ios_base::beg);
1845 stream = new oggStream(file);
1846 if(stream->IsValid())
1847 return stream;
1848 delete stream;
1850 // Try libFLAC
1851 file->clear();
1852 file->seekg(0, std::ios_base::beg);
1853 stream = new flacStream(file);
1854 if(stream->IsValid())
1855 return stream;
1856 delete stream;
1858 // Try DUMB
1859 file->clear();
1860 file->seekg(0, std::ios_base::beg);
1861 stream = new dumbStream(file);
1862 if(stream->IsValid())
1863 return stream;
1864 delete stream;
1866 // Try libSndFile
1867 file->clear();
1868 file->seekg(0, std::ios_base::beg);
1869 stream = new sndStream(file);
1870 if(stream->IsValid())
1871 return stream;
1872 delete stream;
1874 // Try MPG123
1875 file->clear();
1876 file->seekg(0, std::ios_base::beg);
1877 stream = new mp3Stream(file);
1878 if(stream->IsValid())
1879 return stream;
1880 delete stream;
1882 // Try Timidity
1883 file->clear();
1884 file->seekg(0, std::ios_base::beg);
1885 stream = new midiStream(file);
1886 if(stream->IsValid())
1887 return stream;
1888 delete stream;
1890 // Try GStreamer
1891 file->clear();
1892 file->seekg(0, std::ios_base::beg);
1893 stream = new gstStream(file);
1894 if(stream->IsValid())
1895 return stream;
1896 delete stream;
1898 SetError("Unsupported type");
1899 delete file;
1901 else
1903 SetError("Failed to open file");
1904 delete file;
1907 while(i != InstalledCallbacks.end())
1909 stream = new customStream(fdata, i->second);
1910 if(stream->IsValid())
1911 return stream;
1912 delete stream;
1913 i++;
1916 return new nullStream;
1919 static alureStream *InitStream(alureStream *instream, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
1921 std::auto_ptr<alureStream> stream(instream);
1922 ALenum format;
1923 ALuint freq, blockAlign;
1925 if(!stream->GetFormat(&format, &freq, &blockAlign))
1927 SetError("Could not get stream format");
1928 return NULL;
1931 if(format == AL_NONE)
1933 SetError("No valid format");
1934 return NULL;
1936 if(blockAlign == 0)
1938 SetError("Invalid block size");
1939 return NULL;
1941 if(freq == 0)
1943 SetError("Invalid sample rate");
1944 return NULL;
1947 chunkLength -= chunkLength%blockAlign;
1948 if(chunkLength <= 0)
1950 SetError("Chunk length too small");
1951 return NULL;
1954 stream->chunkLen = chunkLength;
1955 stream->dataChunk = new ALubyte[stream->chunkLen];
1957 alGenBuffers(numBufs, bufs);
1958 if(alGetError() != AL_NO_ERROR)
1960 SetError("Buffer creation failed");
1961 return NULL;
1964 ALsizei filled = alureBufferDataFromStream(stream.get(), numBufs, bufs);
1965 if(filled < 0)
1967 alDeleteBuffers(numBufs, bufs);
1968 alGetError();
1970 SetError("Buffering error");
1971 return NULL;
1974 while(filled < numBufs)
1976 alBufferData(bufs[filled], format, stream->dataChunk, 0, freq);
1977 if(alGetError() != AL_NO_ERROR)
1979 SetError("Buffer load failed");
1980 return NULL;
1982 filled++;
1985 return stream.release();
1989 extern "C" {
1991 /* Function: alureCreateStreamFromFile
1993 * Opens a file and sets it up for streaming. The given chunkLength is the
1994 * number of bytes each buffer will fill with. ALURE will optionally generate
1995 * the specified number of buffer objects, fill them with the beginning of the
1996 * data, then place the new IDs into the provided storage, before returning.
1997 * Requires an active context.
1999 * Returns:
2000 * An opaque handle used to control the opened stream, or NULL on error.
2002 * See Also:
2003 * <alureCreateStreamFromMemory>, <alureCreateStreamFromStaticMemory>,
2004 * <alureCreateStreamFromCallback>, <alureBufferDataFromStream>,
2005 * <alureRewindStream>, <alureDestroyStream>
2007 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromFile(const ALchar *fname, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
2009 if(alGetError() != AL_NO_ERROR)
2011 SetError("Existing OpenAL error");
2012 return NULL;
2015 if(chunkLength < 0)
2017 SetError("Invalid chunk length");
2018 return NULL;
2021 if(numBufs < 0)
2023 SetError("Invalid buffer count");
2024 return NULL;
2027 alureStream *stream = create_stream(fname);
2028 if(!stream->IsValid())
2030 delete stream;
2031 return NULL;
2034 return InitStream(stream, chunkLength, numBufs, bufs);
2037 /* Function: alureCreateStreamFromMemory
2039 * Opens a file image from memory and sets it up for streaming, similar to
2040 * alureCreateStreamFromFile. The given data buffer can be safely deleted after
2041 * calling this function. Requires an active context.
2043 * Returns:
2044 * An opaque handle used to control the opened stream, or NULL on error.
2046 * See Also:
2047 * <alureCreateStreamFromFile>, <alureCreateStreamFromStaticMemory>,
2048 * <alureCreateStreamFromCallback>, <alureBufferDataFromStream>,
2049 * <alureRewindStream>, <alureDestroyStream>
2051 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromMemory(const ALubyte *fdata, ALuint length, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
2053 if(alGetError() != AL_NO_ERROR)
2055 SetError("Existing OpenAL error");
2056 return NULL;
2059 if(chunkLength < 0)
2061 SetError("Invalid chunk length");
2062 return NULL;
2065 if(numBufs < 0)
2067 SetError("Invalid buffer count");
2068 return NULL;
2071 if(length <= 0)
2073 SetError("Invalid data length");
2074 return NULL;
2077 ALubyte *streamData = new ALubyte[length];
2078 memcpy(streamData, fdata, length);
2080 MemDataInfo memData;
2081 memData.Data = streamData;
2082 memData.Length = length;
2083 memData.Pos = 0;
2085 alureStream *stream = create_stream(memData);
2086 stream->data = streamData;
2087 if(!stream->IsValid())
2089 delete stream;
2090 return NULL;
2093 return InitStream(stream, chunkLength, numBufs, bufs);
2096 /* Function: alureCreateStreamFromStaticMemory
2098 * Identical to alureCreateStreamFromMemory, except the given memory is used
2099 * directly and not duplicated. As a consequence, the data buffer must remain
2100 * valid while the stream is alive. Requires an active context.
2102 * Returns:
2103 * An opaque handle used to control the opened stream, or NULL on error.
2105 * See Also:
2106 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2107 * <alureCreateStreamFromCallback>, <alureBufferDataFromStream>,
2108 * <alureRewindStream>, <alureDestroyStream>
2110 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromStaticMemory(const ALubyte *fdata, ALuint length, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
2112 if(alGetError() != AL_NO_ERROR)
2114 SetError("Existing OpenAL error");
2115 return NULL;
2118 if(chunkLength < 0)
2120 SetError("Invalid chunk length");
2121 return NULL;
2124 if(numBufs < 0)
2126 SetError("Invalid buffer count");
2127 return NULL;
2130 if(length <= 0)
2132 SetError("Invalid data length");
2133 return NULL;
2136 MemDataInfo memData;
2137 memData.Data = fdata;
2138 memData.Length = length;
2139 memData.Pos = 0;
2141 alureStream *stream = create_stream(memData);
2142 if(!stream->IsValid())
2144 delete stream;
2145 return NULL;
2148 return InitStream(stream, chunkLength, numBufs, bufs);
2151 /* Function: alureCreateStreamFromCallback
2153 * Creates a stream using the specified callback to retrieve data. Requires an
2154 * active context.
2156 * Parameters:
2157 * callback - This is called when more data is needed from the stream. Up to
2158 * the specified number of bytes should be written to the data
2159 * pointer, and the number of bytes actually written should be
2160 * returned. The number of bytes written must be block aligned for
2161 * the format (eg. a multiple of 4 for AL_FORMAT_STEREO16), or an
2162 * OpenAL error may occur during buffering.
2163 * userdata - A handle passed through to the callback.
2164 * format - The format of the data the callback will be giving. The format must
2165 * be valid for the context.
2166 * samplerate - The sample rate (frequency) of the stream
2168 * Returns:
2169 * An opaque handle used to control the opened stream, or NULL on error.
2171 * See Also:
2172 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2173 * <alureCreateStreamFromStaticMemory>, <alureBufferDataFromStream>,
2174 * <alureRewindStream>, <alureDestroyStream>
2176 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromCallback(
2177 ALuint (*callback)(void *userdata, ALubyte *data, ALuint bytes),
2178 void *userdata, ALenum format, ALuint samplerate,
2179 ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
2181 if(alGetError() != AL_NO_ERROR)
2183 SetError("Existing OpenAL error");
2184 return NULL;
2187 if(callback == NULL)
2189 SetError("Invalid callback");
2190 return NULL;
2193 if(chunkLength < 0)
2195 SetError("Invalid chunk length");
2196 return NULL;
2199 if(numBufs < 0)
2201 SetError("Invalid buffer count");
2202 return NULL;
2205 UserCallbacks newcb;
2206 newcb.open_file = NULL;
2207 newcb.open_mem = NULL;
2208 newcb.get_fmt = NULL;
2209 newcb.decode = callback;
2210 newcb.rewind = NULL;
2211 newcb.close = NULL;
2213 customStream *stream = new customStream(userdata, format, samplerate, newcb);
2214 return InitStream(stream, chunkLength, numBufs, bufs);
2217 /* Function: alureGetStreamFormat
2219 * Retrieves the format, frequency, and block-alignment used for the given
2220 * stream. If a parameter is NULL, that value will not be returned.
2222 * Returns:
2223 * AL_FALSE on error.
2225 * See Also:
2226 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2227 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2229 ALURE_API ALboolean ALURE_APIENTRY alureGetStreamFormat(alureStream *stream,
2230 ALenum *format, ALuint *frequency, ALuint *blockAlign)
2232 ALenum _fmt;
2233 ALuint _rate, _balign;
2235 if(!alureStream::Verify(stream))
2237 SetError("Invalid stream pointer");
2238 return AL_FALSE;
2241 if(!format) format = &_fmt;
2242 if(!frequency) frequency = &_rate;
2243 if(!blockAlign) blockAlign = &_balign;
2245 if(!stream->GetFormat(format, frequency, blockAlign))
2247 SetError("Could not get stream format");
2248 return AL_FALSE;
2251 return AL_TRUE;
2254 /* Function: alureBufferDataFromStream
2256 * Buffers the given buffer objects with the next chunks of data from the
2257 * stream. The given buffer objects do not need to be ones given by the
2258 * alureCreateStreamFrom* functions. Requires an active context.
2260 * Returns:
2261 * The number of buffers filled with new data, or -1 on error. If the value
2262 * returned is less than the number requested, the end of the stream has been
2263 * reached.
2265 * See Also:
2266 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2267 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2268 * <alureRewindStream>, <alureDestroyStream>
2270 ALURE_API ALsizei ALURE_APIENTRY alureBufferDataFromStream(alureStream *stream, ALsizei numBufs, ALuint *bufs)
2272 if(alGetError() != AL_NO_ERROR)
2274 SetError("Existing OpenAL error");
2275 return -1;
2278 if(!alureStream::Verify(stream))
2280 SetError("Invalid stream pointer");
2281 return -1;
2284 if(numBufs < 0)
2286 SetError("Invalid buffer count");
2287 return -1;
2290 ALenum format;
2291 ALuint freq, blockAlign;
2293 if(!stream->GetFormat(&format, &freq, &blockAlign))
2295 SetError("Could not get stream format");
2296 return -1;
2299 ALsizei filled;
2300 for(filled = 0;filled < numBufs;filled++)
2302 ALuint got = stream->GetData(stream->dataChunk, stream->chunkLen);
2303 got -= got%blockAlign;
2304 if(got == 0) break;
2306 alBufferData(bufs[filled], format, stream->dataChunk, got, freq);
2307 if(alGetError() != AL_NO_ERROR)
2309 SetError("Buffer load failed");
2310 return -1;
2314 return filled;
2317 /* Function: alureRewindStream
2319 * Rewinds the stream so that the next alureBufferDataFromStream call will
2320 * restart from the beginning of the audio file.
2322 * Returns:
2323 * AL_FALSE on error.
2325 * See Also:
2326 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2327 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2328 * <alureBufferDataFromStream>, <alureSetStreamOrder>, <alureDestroyStream>
2330 ALURE_API ALboolean ALURE_APIENTRY alureRewindStream(alureStream *stream)
2332 if(!alureStream::Verify(stream))
2334 SetError("Invalid stream pointer");
2335 return AL_FALSE;
2338 return stream->Rewind();
2341 /* Function: alureSetStreamOrder
2343 * Skips the module decoder to the specified order, so following buffering
2344 * calls will decode from the specified order. For non-module formats, setting
2345 * order 0 is identical to rewinding the stream (other orders will fail).
2347 * Returns:
2348 * AL_FALSE on error.
2350 * See Also:
2351 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2352 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2353 * <alureBufferDataFromStream>, <alureRewindStream>, <alureDestroyStream>
2355 ALURE_API ALboolean ALURE_APIENTRY alureSetStreamOrder(alureStream *stream, ALuint order)
2357 if(!alureStream::Verify(stream))
2359 SetError("Invalid stream pointer");
2360 return AL_FALSE;
2363 return stream->SetOrder(order);
2366 /* Function: alureDestroyStream
2368 * Closes an opened stream. For convenience, it will also delete the given
2369 * buffer objects. The given buffer objects do not need to be ones given by the
2370 * alureCreateStreamFrom* functions. Requires an active context.
2372 * Returns:
2373 * AL_FALSE on error.
2375 * See Also:
2376 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2377 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2378 * <alureBufferDataFromStream>, <alureRewindStream>
2380 ALURE_API ALboolean ALURE_APIENTRY alureDestroyStream(alureStream *stream, ALsizei numBufs, ALuint *bufs)
2382 if(alGetError() != AL_NO_ERROR)
2384 SetError("Existing OpenAL error");
2385 return AL_FALSE;
2388 if(numBufs < 0)
2390 SetError("Invalid buffer count");
2391 return AL_FALSE;
2394 if(stream && !alureStream::Verify(stream))
2396 SetError("Invalid stream pointer");
2397 return AL_FALSE;
2400 alDeleteBuffers(numBufs, bufs);
2401 if(alGetError() != AL_NO_ERROR)
2403 SetError("Buffer deletion failed");
2404 return AL_FALSE;
2407 if(stream)
2409 StopStream(stream);
2410 std::istream *f = stream->fstream;
2411 delete stream; delete f;
2413 return AL_TRUE;