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 */
38 static inline ALuint
read_le32(std::istream
*file
)
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
)
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
)
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
)
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
)
69 if(!file
->read(reinterpret_cast<char*>(buffer
), 10)) return 0;
70 ALuint mantissa
, last
= 0;
71 ALubyte exp
= buffer
[1];
73 mantissa
= (buffer
[2]<<24) | (buffer
[3]<<16) | (buffer
[4]<<8) | buffer
[5];
79 if((last
&1)) 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; }
93 struct customStream
: public alureStream
{
102 virtual bool IsValid()
103 { return usrFile
!= NULL
; }
105 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
107 if(this->format
== 0)
110 !cb
.get_fmt(usrFile
, &this->format
, &samplerate
, &blockAlign
))
114 *format
= this->format
;
115 *frequency
= samplerate
;
116 *blockalign
= blockAlign
;
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
))
131 SetError("Rewind failed");
135 customStream(const char *fname
, const UserCallbacks
&callbacks
)
136 : usrFile(NULL
), format(0), samplerate(0), blockAlign(0), cb(callbacks
)
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
)
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
)
160 struct wavStream
: public alureStream
{
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
;
180 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
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
;
194 if(endian
.b
[0] == 0 && sampleSize
> 1)
197 for(std::streamsize i
= 0;i
< got
;i
+=2)
199 ALubyte tmp
= data
[i
];
203 else if(sampleSize
== 4)
204 for(std::streamsize i
= 0;i
< got
;i
+=4)
206 ALubyte tmp
= data
[i
];
210 data
[i
+1] = data
[i
+2];
218 virtual bool Rewind()
221 if(fstream
->seekg(dataStart
))
227 SetError("Seek failed");
231 wavStream(std::istream
*_fstream
)
232 : alureStream(_fstream
), format(0), dataStart(0)
244 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
245 memcmp(buffer
, "RIFF", 4) != 0 || memcmp(buffer
+8, "WAVE", 4) != 0)
248 while(!dataStart
|| format
== AL_NONE
)
251 if(!fstream
->read(tag
, 4))
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
);
264 /* mono or stereo data */
265 int channels
= read_le16(fstream
);
267 /* sample frequency */
268 samplerate
= read_le32(fstream
);
270 /* skip four bytes */
273 /* bytes per block */
274 blockAlign
= read_le16(fstream
);
278 /* bits per sample */
279 sampleSize
= read_le16(fstream
) / 8;
281 format
= alureGetSampleFormat(channels
, sampleSize
*8, 0);
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
{
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
;
319 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
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
;
333 if(endian
.b
[0] == 1 && sampleSize
> 1)
336 for(std::streamsize i
= 0;i
< got
;i
+=2)
338 ALubyte tmp
= data
[i
];
342 else if(sampleSize
== 4)
343 for(std::streamsize i
= 0;i
< got
;i
+=4)
345 ALubyte tmp
= data
[i
];
349 data
[i
+1] = data
[i
+2];
357 virtual bool Rewind()
360 if(fstream
->seekg(dataStart
))
366 SetError("Seek failed");
370 aiffStream(std::istream
*_fstream
)
371 : alureStream(_fstream
), format(0), dataStart(0)
374 virtual ~aiffStream()
383 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
384 memcmp(buffer
, "FORM", 4) != 0 || memcmp(buffer
+8, "AIFF", 4) != 0)
387 while(!dataStart
|| format
== AL_NONE
)
390 if(!fstream
->read(tag
, 4))
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 */
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);
417 else if(memcmp(tag
, "SSND", 4) == 0)
419 dataStart
= fstream
->tellg();
421 dataLen
= remLen
= length
- 8;
424 fstream
->seekg(length
, std::ios_base::cur
);
427 if(dataStart
> 0 && format
!= AL_NONE
)
428 fstream
->seekg(dataStart
);
433 struct sndStream
: public alureStream
{
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;
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)
459 SetError("Seek failed");
463 sndStream(std::istream
*_fstream
)
464 : alureStream(_fstream
), sndFile(NULL
)
466 memset(&sndInfo
, 0, sizeof(sndInfo
));
468 static SF_VIRTUAL_IO streamIO
= {
472 sndFile
= sf_open_virtual(&streamIO
, SFM_READ
, &sndInfo
, fstream
);
483 // libSndFile iostream callbacks
484 static sf_count_t
get_filelen(void *user_data
)
486 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
489 std::streampos len
= -1;
490 std::streampos pos
= stream
->tellg();
491 if(stream
->seekg(0, std::ios_base::end
))
493 len
= stream
->tellg();
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
);
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
);
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
);
521 stream
->read(static_cast<char*>(ptr
), count
);
522 return stream
->gcount();
525 static sf_count_t
write(const void*, sf_count_t
, void*)
528 static sf_count_t
tell(void *user_data
)
530 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
532 return stream
->tellg();
536 struct sndStream
: public nullStream
{
537 sndStream(std::istream
*){}
541 #ifdef HAS_VORBISFILE
542 struct oggStream
: public alureStream
{
543 OggVorbis_File
*oggFile
;
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;
560 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
564 char b
[sizeof(short)];
565 } endian
= { 0x0100 };
567 vorbis_info
*info
= ov_info(oggFile
, -1);
570 ALuint blockAlign
= info
->channels
*2;
571 bytes
-= bytes
%blockAlign
;
576 int res
= ov_read(oggFile
, (char*)&data
[got
], bytes
, endian
.b
[0], 2, 1, &oggBitstream
);
585 virtual bool Rewind()
587 if(ov_pcm_seek(oggFile
, 0) == 0)
590 SetError("Seek failed");
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)
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
);
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();
647 static long tell(void *user_data
)
649 oggStream
*This
= static_cast<oggStream
*>(user_data
);
650 This
->fstream
->clear();
651 return This
->fstream
->tellg();
655 struct oggStream
: public nullStream
{
656 oggStream(std::istream
*){}
661 struct flacStream
: public alureStream
{
662 FLAC__StreamDecoder
*flacFile
;
667 std::vector
<ALubyte
> initialData
;
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
;
684 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
686 bytes
-= bytes
%blockAlign
;
692 if(initialData
.size() > 0)
694 size_t rem
= std::min(initialData
.size(), (size_t)bytes
);
695 memcpy(data
, &initialData
[0], 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
)
710 virtual bool Rewind()
712 if(FLAC__stream_decoder_seek_absolute(flacFile
, 0) != false)
718 SetError("Seek failed");
722 flacStream(std::istream
*_fstream
)
723 : alureStream(_fstream
), flacFile(NULL
)
725 flacFile
= FLAC__stream_decoder_new();
728 if(FLAC__stream_decoder_init_stream(flacFile
, ReadCallback
, SeekCallback
, TellCallback
, LengthCallback
, EofCallback
, WriteCallback
, MetadataCallback
, ErrorCallback
, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK
)
736 FLAC__stream_decoder_finish(flacFile
);
738 FLAC__stream_decoder_delete(flacFile
);
743 virtual ~flacStream()
747 FLAC__stream_decoder_finish(flacFile
);
748 FLAC__stream_decoder_delete(flacFile
);
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
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
)
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);
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
;
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;
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;
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
;
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
;
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
;
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
;
871 std::streampos pos
= stream
->tellg();
872 if(stream
->seekg(0, std::ios_base::end
))
874 *stream_length
= stream
->tellg();
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;
889 struct flacStream
: public nullStream
{
890 flacStream(std::istream
*){}
896 struct mp3Stream
: public alureStream
{
897 mpg123_handle
*mp3File
;
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);
910 *frequency
= samplerate
;
911 *blockalign
= channels
*2;
915 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
917 const ALuint blockAlign
= channels
*2;
918 bytes
-= bytes
%blockAlign
;
923 int ret
= mpg123_read(mp3File
, data
, bytes
, &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();;
935 mpg123_decode(mp3File
, data
, insize
, NULL
, 0, NULL
) == MPG123_OK
)
943 virtual bool Rewind()
946 std::istream::pos_type oldpos
= fstream
->tellg();
949 mpg123_handle
*newFile
= mpg123_new(NULL
, NULL
);
950 if(mpg123_open_feed(newFile
) == MPG123_OK
)
952 unsigned char data
[4096];
957 ALuint amt
, total
= 0;
959 fstream
->read((char*)data
, sizeof(data
));
960 amt
= fstream
->gcount();
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
)))
975 mpg123_delete(mp3File
);
980 mpg123_delete(newFile
);
983 fstream
->seekg(oldpos
);
984 SetError("Restart failed");
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];
997 ALuint amt
, total
= 0;
999 fstream
->read((char*)data
, sizeof(data
));
1000 amt
= fstream
->gcount();
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
))
1018 mpg123_delete(mp3File
);
1022 virtual ~mp3Stream()
1025 mpg123_delete(mp3File
);
1030 struct mp3Stream
: public nullStream
{
1031 mp3Stream(std::istream
*){}
1037 struct dumbStream
: public alureStream
{
1038 DUMBFILE_SYSTEM vfs
;
1041 DUH_SIGRENDERER
*renderer
;
1042 std::vector
<sample_t
> sampleBuf
;
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
;
1060 *blockalign
= 2 * ((format
==AL_FORMAT_STEREO16
) ? sizeof(ALshort
) :
1065 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1069 if(dumb_it_sr_get_speed(duh_get_it_sigrenderer(renderer
)) == 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
);
1081 if(format
== AL_FORMAT_STEREO16
)
1083 for(ALuint i
= 0;i
< ret
;i
++)
1084 ((ALshort
*)data
)[i
] = clamp(samples
[i
]>>8, -32768, 32767);
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
));
1098 virtual bool Rewind()
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
);
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));
1115 SetError("Could start renderer");
1118 duh_end_sigrenderer(renderer
);
1119 renderer
= newrenderer
;
1123 virtual bool SetOrder(ALuint order
)
1125 DUH_SIGRENDERER
*newrenderer
= dumb_it_start_at_order(duh
, 2, order
);
1128 SetError("Could not set order");
1131 duh_end_sigrenderer(renderer
);
1132 renderer
= newrenderer
;
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
*) = {
1145 dumb_read_s3m_quick
,
1146 dumb_read_mod_quick
,
1152 vfs
.getc
= read_char
;
1156 for(size_t i
= 0;funcs
[i
];i
++)
1158 dumbFile
= dumbfile_open_ex(this, &vfs
);
1161 duh
= funcs
[i
](dumbFile
);
1164 renderer
= duh_start_sigrenderer(duh
, 0, 2, 0);
1167 dumb_it_set_loop_callback(duh_get_it_sigrenderer(renderer
), loop_cb
, this);
1175 dumbfile_close(dumbFile
);
1183 virtual ~dumbStream()
1185 duh_end_sigrenderer(renderer
);
1192 dumbfile_close(dumbFile
);
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
))
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();
1223 This
->fstream
->read(reinterpret_cast<char*>(&ret
), 1);
1224 if(This
->fstream
->gcount() > 0)
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);
1238 struct dumbStream
: public nullStream
{
1239 dumbStream(std::istream
*){}
1245 struct midiStream
: public alureStream
{
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
;
1263 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1266 if(initialByte
!= -1 && bytes
> 0)
1268 *(data
++) = initialByte
&0xff;
1274 ssize_t got
= read(pcmFile
, data
, bytes
);
1275 if(got
== -1 && errno
== EINTR
)
1287 virtual bool Rewind()
1292 int _pcmFile
; pid_t _cpid
;
1293 if(!StartStream(_pcmFile
, _cpid
))
1295 SetError("Failed to restart timidity");
1299 kill(cpid
, SIGTERM
);
1300 waitpid(cpid
, NULL
, 0);
1309 midiStream(std::istream
*_fstream
)
1310 : alureStream(_fstream
), pcmFile(-1), cpid(-1), initialByte(-1)
1312 StartStream(pcmFile
, cpid
);
1315 virtual ~midiStream()
1319 kill(cpid
, SIGTERM
);
1320 waitpid(cpid
, NULL
, 0);
1329 bool StartStream(int &pcmFile
, pid_t
&pid
)
1331 int midPipe
[2] = { -1, -1 };
1332 int pcmPipe
[2] = { -1, -1 };
1335 std::vector
<ALubyte
> midiData
;
1337 fstream
->read(hdr
, sizeof(hdr
));
1338 if(fstream
->gcount() != sizeof(hdr
))
1341 if(memcmp(hdr
, "MThd", 4) == 0)
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
);
1352 if(pipe(midPipe
) == -1)
1354 if(pipe(pcmPipe
) == -1)
1356 close(midPipe
[0]); midPipe
[0] = -1;
1357 close(midPipe
[1]); midPipe
[1] = -1;
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",
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();
1384 ssize_t wrote
= write(midPipe
[1], cur
, rem
);
1394 close(midPipe
[1]); midPipe
[1] = -1;
1398 while((got
=read(pcmPipe
[0], &ch
, 1)) == -1 && errno
== EINTR
)
1403 waitpid(pid
, NULL
, 0); pid
= -1;
1404 close(pcmPipe
[0]); pcmPipe
[0] = -1;
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;
1418 pcmFile
= pcmPipe
[0];
1423 struct midiStream
: public nullStream
{
1424 midiStream(std::istream
*){}
1429 #ifdef HAS_GSTREAMER
1430 struct gstStream
: public alureStream
{
1431 GstElement
*gstPipeline
;
1437 std::vector
<ALubyte
> initialData
;
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
;
1454 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1456 bytes
-= bytes
%blockAlign
;
1462 if(initialData
.size() > 0)
1464 size_t rem
= std::min(initialData
.size(), (size_t)bytes
);
1465 memcpy(data
, &initialData
[0], 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
);
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();
1487 SetError("Seek failed");
1491 gstStream(std::istream
*_fstream
)
1492 : alureStream(_fstream
), gstPipeline(NULL
), format(AL_NONE
), outBytes(NULL
),
1493 outLen(0), outTotal(0)
1496 virtual ~gstStream()
1500 gst_element_set_state(gstPipeline
, GST_STATE_NULL
);
1501 gst_object_unref(gstPipeline
);
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)
1516 std::string gst_audio_caps
;
1517 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
1519 static const struct {
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
}
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
}
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)
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)
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)
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";
1608 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
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";
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";
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
);
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
);
1664 const GstMessageType types
= GstMessageType(GST_MESSAGE_ERROR
|GST_MESSAGE_ASYNC_DONE
);
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
);
1677 if(GST_MESSAGE_TYPE(msg
) == GST_MESSAGE_ERROR
)
1682 gst_message_parse_error(msg
, &error
, &debug
);
1683 g_printerr("GST Error: %s\n", error
->message
);
1686 g_error_free(error
);
1688 gst_message_unref(msg
);
1691 gst_message_unref(msg
);
1694 gst_object_unref(bus
);
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
);
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
));
1717 if(format
== AL_NONE
)
1719 GstCaps
*caps
= GST_BUFFER_CAPS(buffer
);
1720 //GST_LOG("caps are %" GST_PTR_FORMAT, caps);
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
);
1737 format
= alureGetSampleFormat(channels
, 0, bits
);
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
));
1754 ALubyte
*src_buffer
= (ALubyte
*)(GST_BUFFER_DATA(buffer
));
1755 guint size
= GST_BUFFER_SIZE(buffer
);
1756 guint rem
= std::min(size
, outLen
-outTotal
);
1758 memcpy(outBytes
+outTotal
, src_buffer
, 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
)
1776 if(!app
->fstream
->good())
1778 // we are EOS, send end-of-stream
1779 g_signal_emit_by_name(appsrc
, "end-of-stream", &ret
);
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
);
1806 struct gstStream
: public nullStream
{
1807 gstStream(std::istream
*){}
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())
1827 InStream
*file
= new InStream(fdata
);
1830 stream
= new wavStream(file
);
1831 if(stream
->IsValid())
1836 file
->seekg(0, std::ios_base::beg
);
1837 stream
= new aiffStream(file
);
1838 if(stream
->IsValid())
1842 // Try libVorbisFile
1844 file
->seekg(0, std::ios_base::beg
);
1845 stream
= new oggStream(file
);
1846 if(stream
->IsValid())
1852 file
->seekg(0, std::ios_base::beg
);
1853 stream
= new flacStream(file
);
1854 if(stream
->IsValid())
1860 file
->seekg(0, std::ios_base::beg
);
1861 stream
= new dumbStream(file
);
1862 if(stream
->IsValid())
1868 file
->seekg(0, std::ios_base::beg
);
1869 stream
= new sndStream(file
);
1870 if(stream
->IsValid())
1876 file
->seekg(0, std::ios_base::beg
);
1877 stream
= new mp3Stream(file
);
1878 if(stream
->IsValid())
1884 file
->seekg(0, std::ios_base::beg
);
1885 stream
= new midiStream(file
);
1886 if(stream
->IsValid())
1892 file
->seekg(0, std::ios_base::beg
);
1893 stream
= new gstStream(file
);
1894 if(stream
->IsValid())
1898 SetError("Unsupported type");
1903 SetError("Failed to open file");
1907 while(i
!= InstalledCallbacks
.end())
1909 stream
= new customStream(fdata
, i
->second
);
1910 if(stream
->IsValid())
1916 return new nullStream
;
1919 static alureStream
*InitStream(alureStream
*instream
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
1921 std::auto_ptr
<alureStream
> stream(instream
);
1923 ALuint freq
, blockAlign
;
1925 if(!stream
->GetFormat(&format
, &freq
, &blockAlign
))
1927 SetError("Could not get stream format");
1931 if(format
== AL_NONE
)
1933 SetError("No valid format");
1938 SetError("Invalid block size");
1943 SetError("Invalid sample rate");
1947 chunkLength
-= chunkLength
%blockAlign
;
1948 if(chunkLength
<= 0)
1950 SetError("Chunk length too small");
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");
1964 ALsizei filled
= alureBufferDataFromStream(stream
.get(), numBufs
, bufs
);
1967 alDeleteBuffers(numBufs
, bufs
);
1970 SetError("Buffering error");
1974 while(filled
< numBufs
)
1976 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, 0, freq
);
1977 if(alGetError() != AL_NO_ERROR
)
1979 SetError("Buffer load failed");
1985 return stream
.release();
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.
2000 * An opaque handle used to control the opened stream, or NULL on error.
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");
2017 SetError("Invalid chunk length");
2023 SetError("Invalid buffer count");
2027 alureStream
*stream
= create_stream(fname
);
2028 if(!stream
->IsValid())
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.
2044 * An opaque handle used to control the opened stream, or NULL on error.
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");
2061 SetError("Invalid chunk length");
2067 SetError("Invalid buffer count");
2073 SetError("Invalid data length");
2077 ALubyte
*streamData
= new ALubyte
[length
];
2078 memcpy(streamData
, fdata
, length
);
2080 MemDataInfo memData
;
2081 memData
.Data
= streamData
;
2082 memData
.Length
= length
;
2085 alureStream
*stream
= create_stream(memData
);
2086 stream
->data
= streamData
;
2087 if(!stream
->IsValid())
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.
2103 * An opaque handle used to control the opened stream, or NULL on error.
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");
2120 SetError("Invalid chunk length");
2126 SetError("Invalid buffer count");
2132 SetError("Invalid data length");
2136 MemDataInfo memData
;
2137 memData
.Data
= fdata
;
2138 memData
.Length
= length
;
2141 alureStream
*stream
= create_stream(memData
);
2142 if(!stream
->IsValid())
2148 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
2151 /* Function: alureCreateStreamFromCallback
2153 * Creates a stream using the specified callback to retrieve data. Requires an
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
2169 * An opaque handle used to control the opened stream, or NULL on error.
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");
2187 if(callback
== NULL
)
2189 SetError("Invalid callback");
2195 SetError("Invalid chunk length");
2201 SetError("Invalid buffer count");
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
;
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.
2223 * AL_FALSE on error.
2226 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
2227 * <alureCreateStreamFromStaticMemory>, <alureCreateStreamFromCallback>,
2229 ALURE_API ALboolean ALURE_APIENTRY
alureGetStreamFormat(alureStream
*stream
,
2230 ALenum
*format
, ALuint
*frequency
, ALuint
*blockAlign
)
2233 ALuint _rate
, _balign
;
2235 if(!alureStream::Verify(stream
))
2237 SetError("Invalid stream pointer");
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");
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.
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
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");
2278 if(!alureStream::Verify(stream
))
2280 SetError("Invalid stream pointer");
2286 SetError("Invalid buffer count");
2291 ALuint freq
, blockAlign
;
2293 if(!stream
->GetFormat(&format
, &freq
, &blockAlign
))
2295 SetError("Could not get stream format");
2300 for(filled
= 0;filled
< numBufs
;filled
++)
2302 ALuint got
= stream
->GetData(stream
->dataChunk
, stream
->chunkLen
);
2303 got
-= got
%blockAlign
;
2306 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, got
, freq
);
2307 if(alGetError() != AL_NO_ERROR
)
2309 SetError("Buffer load failed");
2317 /* Function: alureRewindStream
2319 * Rewinds the stream so that the next alureBufferDataFromStream call will
2320 * restart from the beginning of the audio file.
2323 * AL_FALSE on error.
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");
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).
2348 * AL_FALSE on error.
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");
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.
2373 * AL_FALSE on error.
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");
2390 SetError("Invalid buffer count");
2394 if(stream
&& !alureStream::Verify(stream
))
2396 SetError("Invalid stream pointer");
2400 alDeleteBuffers(numBufs
, bufs
);
2401 if(alGetError() != AL_NO_ERROR
)
2403 SetError("Buffer deletion failed");
2410 std::istream
*f
= stream
->fstream
;
2411 delete stream
; delete f
;