2 * ALURE OpenAL utility library
3 * Copyright (C) 2009-2010 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
37 static inline ALuint
read_le32(std::istream
*file
)
40 if(!file
->read(reinterpret_cast<char*>(buffer
), 4)) return 0;
41 return buffer
[0] | (buffer
[1]<<8) | (buffer
[2]<<16) | (buffer
[3]<<24);
44 static inline ALushort
read_le16(std::istream
*file
)
47 if(!file
->read(reinterpret_cast<char*>(buffer
), 2)) return 0;
48 return buffer
[0] | (buffer
[1]<<8);
51 static inline ALuint
read_be32(std::istream
*file
)
54 if(!file
->read(reinterpret_cast<char*>(buffer
), 4)) return 0;
55 return (buffer
[0]<<24) | (buffer
[1]<<16) | (buffer
[2]<<8) | buffer
[3];
58 static inline ALushort
read_be16(std::istream
*file
)
61 if(!file
->read(reinterpret_cast<char*>(buffer
), 2)) return 0;
62 return (buffer
[0]<<8) | buffer
[1];
65 static inline ALuint
read_be80extended(std::istream
*file
)
68 if(!file
->read(reinterpret_cast<char*>(buffer
), 10)) return 0;
69 ALuint mantissa
, last
= 0;
70 ALubyte exp
= buffer
[1];
72 mantissa
= (buffer
[2]<<24) | (buffer
[3]<<16) | (buffer
[4]<<8) | buffer
[5];
78 if((last
&1)) mantissa
++;
83 bool customStream::IsValid()
84 { return usrFile
!= NULL
; }
86 bool customStream::GetFormat(ALenum
*fmt
, ALuint
*frequency
, ALuint
*blockalign
)
91 !cb
.get_fmt(usrFile
, &this->format
, &samplerate
, &blockAlign
))
96 *frequency
= samplerate
;
97 *blockalign
= blockAlign
;
101 ALuint
customStream::GetData(ALubyte
*data
, ALuint bytes
)
102 { return cb
.decode(usrFile
, data
, bytes
); }
104 bool customStream::Rewind()
106 if(cb
.rewind
&& cb
.rewind(usrFile
))
108 SetError("Rewind failed");
112 customStream::customStream(const char *fname
, const UserCallbacks
&callbacks
)
113 : alureStream(NULL
), usrFile(NULL
), format(0), samplerate(0), blockAlign(0),
115 { if(cb
.open_file
) usrFile
= cb
.open_file(fname
); }
117 customStream::customStream(const MemDataInfo
&memData
, const UserCallbacks
&callbacks
)
118 : alureStream(NULL
), usrFile(NULL
), format(0), samplerate(0), blockAlign(0),
119 memInfo(memData
), cb(callbacks
)
120 { if(cb
.open_mem
) usrFile
= cb
.open_mem(memInfo
.Data
, memInfo
.Length
); }
122 customStream::customStream(void *userdata
, ALenum fmt
, ALuint srate
, const UserCallbacks
&callbacks
)
123 : alureStream(NULL
), usrFile(userdata
), format(fmt
), samplerate(srate
),
124 blockAlign(DetectBlockAlignment(format
)), cb(callbacks
)
127 customStream::~customStream()
129 if(cb
.close
&& usrFile
)
135 struct nullStream
: public alureStream
{
136 virtual bool IsValid() { return false; }
137 virtual bool GetFormat(ALenum
*,ALuint
*,ALuint
*) { return false; }
138 virtual ALuint
GetData(ALubyte
*,ALuint
) { return 0; }
139 virtual bool Rewind() { return false; }
140 nullStream():alureStream(NULL
) {}
144 struct wavStream
: public alureStream
{
153 virtual bool IsValid()
154 { return (dataStart
> 0 && format
!= AL_NONE
); }
156 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
158 *format
= this->format
;
159 *frequency
= samplerate
;
160 *blockalign
= blockAlign
;
164 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
166 std::streamsize rem
= ((remLen
>= bytes
) ? bytes
: remLen
) / blockAlign
;
167 fstream
->read(reinterpret_cast<char*>(data
), rem
*blockAlign
);
169 std::streamsize got
= fstream
->gcount();
170 got
-= got
%blockAlign
;
173 if(BigEndian
&& sampleSize
> 1)
176 for(std::streamsize i
= 0;i
< got
;i
+=2)
178 ALubyte tmp
= data
[i
];
182 else if(sampleSize
== 4)
183 for(std::streamsize i
= 0;i
< got
;i
+=4)
185 ALubyte tmp
= data
[i
];
189 data
[i
+1] = data
[i
+2];
197 virtual bool Rewind()
200 if(fstream
->seekg(dataStart
))
206 SetError("Seek failed");
210 wavStream(std::istream
*_fstream
)
211 : alureStream(_fstream
), format(0), dataStart(0)
223 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
224 memcmp(buffer
, "RIFF", 4) != 0 || memcmp(buffer
+8, "WAVE", 4) != 0)
227 while(!dataStart
|| format
== AL_NONE
)
230 if(!fstream
->read(tag
, 4))
233 /* read chunk length */
234 length
= read_le32(fstream
);
236 if(memcmp(tag
, "fmt ", 4) == 0 && length
>= 16)
238 /* Data type (should be 1 for PCM data) */
239 int type
= read_le16(fstream
);
243 /* mono or stereo data */
244 int channels
= read_le16(fstream
);
246 /* sample frequency */
247 samplerate
= read_le32(fstream
);
249 /* skip four bytes */
252 /* bytes per block */
253 blockAlign
= read_le16(fstream
);
257 /* bits per sample */
258 sampleSize
= read_le16(fstream
) / 8;
260 format
= alureGetSampleFormat(channels
, sampleSize
*8, 0);
264 else if(memcmp(tag
, "data", 4) == 0)
266 dataStart
= fstream
->tellg();
267 dataLen
= remLen
= length
;
270 fstream
->seekg(length
, std::ios_base::cur
);
273 if(dataStart
> 0 && format
!= AL_NONE
)
274 fstream
->seekg(dataStart
);
278 struct aiffStream
: public alureStream
{
287 virtual bool IsValid()
288 { return (dataStart
> 0 && format
!= AL_NONE
); }
290 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
292 *format
= this->format
;
293 *frequency
= samplerate
;
294 *blockalign
= blockAlign
;
298 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
300 std::streamsize rem
= ((remLen
>= bytes
) ? bytes
: remLen
) / blockAlign
;
301 fstream
->read(reinterpret_cast<char*>(data
), rem
*blockAlign
);
303 std::streamsize got
= fstream
->gcount();
304 got
-= got
%blockAlign
;
307 if(LittleEndian
&& sampleSize
> 1)
310 for(std::streamsize i
= 0;i
< got
;i
+=2)
312 ALubyte tmp
= data
[i
];
316 else if(sampleSize
== 4)
317 for(std::streamsize i
= 0;i
< got
;i
+=4)
319 ALubyte tmp
= data
[i
];
323 data
[i
+1] = data
[i
+2];
331 virtual bool Rewind()
334 if(fstream
->seekg(dataStart
))
340 SetError("Seek failed");
344 aiffStream(std::istream
*_fstream
)
345 : alureStream(_fstream
), format(0), dataStart(0)
348 virtual ~aiffStream()
357 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
358 memcmp(buffer
, "FORM", 4) != 0 || memcmp(buffer
+8, "AIFF", 4) != 0)
361 while(!dataStart
|| format
== AL_NONE
)
364 if(!fstream
->read(tag
, 4))
367 /* read chunk length */
368 length
= read_be32(fstream
);
370 if(memcmp(tag
, "COMM", 4) == 0 && length
>= 18)
372 /* mono or stereo data */
373 int channels
= read_be16(fstream
);
375 /* number of sample frames */
378 /* bits per sample */
379 sampleSize
= read_be16(fstream
) / 8;
381 /* sample frequency */
382 samplerate
= read_be80extended(fstream
);
384 /* block alignment */
385 blockAlign
= channels
* sampleSize
;
387 format
= alureGetSampleFormat(channels
, sampleSize
*8, 0);
391 else if(memcmp(tag
, "SSND", 4) == 0)
393 dataStart
= fstream
->tellg();
395 dataLen
= remLen
= length
- 8;
398 fstream
->seekg(length
, std::ios_base::cur
);
401 if(dataStart
> 0 && format
!= AL_NONE
)
402 fstream
->seekg(dataStart
);
407 struct sndStream
: public alureStream
{
411 virtual bool IsValid()
412 { return sndFile
!= NULL
; }
414 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
416 *format
= alureGetSampleFormat(sndInfo
.channels
, 16, 0);
417 *frequency
= sndInfo
.samplerate
;
418 *blockalign
= sndInfo
.channels
*2;
422 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
424 const ALuint frameSize
= 2*sndInfo
.channels
;
425 return sf_readf_short(sndFile
, (short*)data
, bytes
/frameSize
) * frameSize
;
428 virtual bool Rewind()
430 if(sf_seek(sndFile
, 0, SEEK_SET
) != -1)
433 SetError("Seek failed");
437 sndStream(std::istream
*_fstream
)
438 : alureStream(_fstream
), sndFile(NULL
)
440 memset(&sndInfo
, 0, sizeof(sndInfo
));
442 static SF_VIRTUAL_IO streamIO
= {
446 sndFile
= sf_open_virtual(&streamIO
, SFM_READ
, &sndInfo
, this);
457 // libSndFile iostream callbacks
458 static sf_count_t
get_filelen(void *user_data
)
460 std::istream
*stream
= static_cast<sndStream
*>(user_data
)->fstream
;
463 std::streampos len
= -1;
464 std::streampos pos
= stream
->tellg();
465 if(stream
->seekg(0, std::ios_base::end
))
467 len
= stream
->tellg();
474 static sf_count_t
seek(sf_count_t offset
, int whence
, void *user_data
)
476 std::istream
*stream
= static_cast<sndStream
*>(user_data
)->fstream
;
479 if(whence
== SEEK_CUR
)
480 stream
->seekg(offset
, std::ios_base::cur
);
481 else if(whence
== SEEK_SET
)
482 stream
->seekg(offset
, std::ios_base::beg
);
483 else if(whence
== SEEK_END
)
484 stream
->seekg(offset
, std::ios_base::end
);
488 return stream
->tellg();
491 static sf_count_t
read(void *ptr
, sf_count_t count
, void *user_data
)
493 std::istream
*stream
= static_cast<sndStream
*>(user_data
)->fstream
;
495 stream
->read(static_cast<char*>(ptr
), count
);
496 return stream
->gcount();
499 static sf_count_t
write(const void*, sf_count_t
, void*)
502 static sf_count_t
tell(void *user_data
)
504 std::istream
*stream
= static_cast<sndStream
*>(user_data
)->fstream
;
506 return stream
->tellg();
510 struct sndStream
: public nullStream
{
511 sndStream(std::istream
*){}
515 #ifdef HAS_VORBISFILE
516 struct oggStream
: public alureStream
{
517 OggVorbis_File
*oggFile
;
520 virtual bool IsValid()
521 { return oggFile
!= NULL
; }
523 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
525 vorbis_info
*info
= ov_info(oggFile
, -1);
526 if(!info
) return false;
528 *format
= alureGetSampleFormat(info
->channels
, 16, 0);
529 *frequency
= info
->rate
;
530 *blockalign
= info
->channels
*2;
534 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
539 int res
= ov_read(oggFile
, (char*)&data
[got
], bytes
, BigEndian
?1:0, 2, 1, &oggBitstream
);
548 virtual bool Rewind()
550 if(ov_pcm_seek(oggFile
, 0) == 0)
553 SetError("Seek failed");
557 oggStream(std::istream
*_fstream
)
558 : alureStream(_fstream
), oggFile(NULL
), oggBitstream(0)
560 const ov_callbacks streamIO
= {
561 read
, seek
, NULL
, tell
564 oggFile
= new OggVorbis_File
;
565 if(ov_open_callbacks(this, oggFile
, NULL
, 0, streamIO
) != 0)
582 // libVorbisFile iostream callbacks
583 static int seek(void *user_data
, ogg_int64_t offset
, int whence
)
585 std::istream
*stream
= static_cast<oggStream
*>(user_data
)->fstream
;
588 if(whence
== SEEK_CUR
)
589 stream
->seekg(offset
, std::ios_base::cur
);
590 else if(whence
== SEEK_SET
)
591 stream
->seekg(offset
, std::ios_base::beg
);
592 else if(whence
== SEEK_END
)
593 stream
->seekg(offset
, std::ios_base::end
);
597 return stream
->tellg();
600 static size_t read(void *ptr
, size_t size
, size_t nmemb
, void *user_data
)
602 std::istream
*stream
= static_cast<oggStream
*>(user_data
)->fstream
;
605 stream
->read(static_cast<char*>(ptr
), nmemb
*size
);
606 size_t ret
= stream
->gcount();
610 static long tell(void *user_data
)
612 std::istream
*stream
= static_cast<oggStream
*>(user_data
)->fstream
;
614 return stream
->tellg();
618 struct oggStream
: public nullStream
{
619 oggStream(std::istream
*){}
624 struct flacStream
: public alureStream
{
625 FLAC__StreamDecoder
*flacFile
;
631 std::vector
<ALubyte
> initialData
;
637 virtual bool IsValid()
638 { return flacFile
!= NULL
; }
640 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
642 *format
= this->format
;
643 *frequency
= samplerate
;
644 *blockalign
= blockAlign
;
648 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
654 if(initialData
.size() > 0)
656 size_t rem
= std::min(initialData
.size(), (size_t)bytes
);
657 memcpy(data
, &initialData
[0], rem
);
659 initialData
.erase(initialData
.begin(), initialData
.begin()+rem
);
662 while(outTotal
< bytes
)
664 if(FLAC__stream_decoder_process_single(flacFile
) == false ||
665 FLAC__stream_decoder_get_state(flacFile
) == FLAC__STREAM_DECODER_END_OF_STREAM
)
672 virtual bool Rewind()
674 if(FLAC__stream_decoder_seek_absolute(flacFile
, 0) != false)
680 SetError("Seek failed");
684 flacStream(std::istream
*_fstream
)
685 : alureStream(_fstream
), flacFile(NULL
), format(AL_NONE
), samplerate(0),
686 blockAlign(0), useFloat(AL_FALSE
)
688 flacFile
= FLAC__stream_decoder_new();
691 if(FLAC__stream_decoder_init_stream(flacFile
, ReadCallback
, SeekCallback
, TellCallback
, LengthCallback
, EofCallback
, WriteCallback
, MetadataCallback
, ErrorCallback
, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK
)
699 FLAC__stream_decoder_finish(flacFile
);
701 FLAC__stream_decoder_delete(flacFile
);
706 virtual ~flacStream()
710 FLAC__stream_decoder_finish(flacFile
);
711 FLAC__stream_decoder_delete(flacFile
);
719 // We need to decode some data to be able to get the channel count, bit
720 // depth, and sample rate. It also ensures the file has FLAC data, as
721 // the FLAC__stream_decoder_init_* functions can succeed on non-FLAC
725 while(initialData
.size() == 0)
727 if(FLAC__stream_decoder_process_single(flacFile
) == false ||
728 FLAC__stream_decoder_get_state(flacFile
) == FLAC__STREAM_DECODER_END_OF_STREAM
)
732 if(initialData
.size() > 0)
737 static FLAC__StreamDecoderWriteStatus
WriteCallback(const FLAC__StreamDecoder
*, const FLAC__Frame
*frame
, const FLAC__int32
*const buffer
[], void *client_data
)
739 flacStream
*This
= static_cast<flacStream
*>(client_data
);
740 ALubyte
*data
= This
->outBytes
+ This
->outTotal
;
743 if(This
->format
== AL_NONE
)
745 ALuint bps
= frame
->header
.bits_per_sample
;
746 if(bps
== 24 || bps
== 32)
748 This
->format
= alureGetSampleFormat(frame
->header
.channels
, 0, 32);
749 if(This
->format
!= AL_NONE
)
751 This
->useFloat
= AL_TRUE
;
756 if(This
->format
== AL_NONE
)
757 This
->format
= alureGetSampleFormat(frame
->header
.channels
, bps
, 0);
758 This
->blockAlign
= frame
->header
.channels
* bps
/8;
759 This
->samplerate
= frame
->header
.sample_rate
;
762 const ALboolean useFloat
= This
->useFloat
;
763 while(This
->outTotal
< This
->outLen
&& i
< frame
->header
.blocksize
)
765 for(ALuint c
= 0;c
< frame
->header
.channels
;c
++)
767 if(frame
->header
.bits_per_sample
== 8)
768 ((ALubyte
*)data
)[c
] = buffer
[c
][i
]+128;
769 else if(frame
->header
.bits_per_sample
== 16)
770 ((ALshort
*)data
)[c
] = buffer
[c
][i
];
771 else if(frame
->header
.bits_per_sample
== 24)
774 ((ALfloat
*)data
)[c
] = ((buffer
[c
][i
]>=0) ?
775 buffer
[c
][i
]/(float)0x7FFFFF :
776 buffer
[c
][i
]/(float)0x800000);
778 ((ALshort
*)data
)[c
] = buffer
[c
][i
]>>8;
780 else if(frame
->header
.bits_per_sample
== 32)
783 ((ALfloat
*)data
)[c
] = ((buffer
[c
][i
]>=0) ?
784 buffer
[c
][i
]/(float)0x7FFFFFFF :
785 buffer
[c
][i
]/(float)0x80000000u
);
787 ((ALshort
*)data
)[c
] = buffer
[c
][i
]>>16;
790 This
->outTotal
+= This
->blockAlign
;
791 data
+= This
->blockAlign
;
795 if(i
< frame
->header
.blocksize
)
797 ALuint blocklen
= (frame
->header
.blocksize
-i
) *
799 ALuint start
= This
->initialData
.size();
801 This
->initialData
.resize(start
+blocklen
);
802 data
= &This
->initialData
[start
];
805 for(ALuint c
= 0;c
< frame
->header
.channels
;c
++)
807 if(frame
->header
.bits_per_sample
== 8)
808 ((ALubyte
*)data
)[c
] = buffer
[c
][i
]+128;
809 else if(frame
->header
.bits_per_sample
== 16)
810 ((ALshort
*)data
)[c
] = buffer
[c
][i
];
811 else if(frame
->header
.bits_per_sample
== 24)
814 ((ALfloat
*)data
)[c
] = ((buffer
[c
][i
]>=0) ?
815 buffer
[c
][i
]/(float)0x7FFFFF :
816 buffer
[c
][i
]/(float)0x800000);
818 ((ALshort
*)data
)[c
] = buffer
[c
][i
]>>8;
820 else if(frame
->header
.bits_per_sample
== 32)
823 ((ALfloat
*)data
)[c
] = ((buffer
[c
][i
]>=0) ?
824 buffer
[c
][i
]/(float)0x7FFFFFFF :
825 buffer
[c
][i
]/(float)0x80000000u
);
827 ((ALshort
*)data
)[c
] = buffer
[c
][i
]>>16;
830 data
+= This
->blockAlign
;
832 } while(i
< frame
->header
.blocksize
);
835 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
837 static void MetadataCallback(const FLAC__StreamDecoder
*,const FLAC__StreamMetadata
*,void*)
840 static void ErrorCallback(const FLAC__StreamDecoder
*,FLAC__StreamDecoderErrorStatus
,void*)
844 static FLAC__StreamDecoderReadStatus
ReadCallback(const FLAC__StreamDecoder
*, FLAC__byte buffer
[], size_t *bytes
, void *client_data
)
846 std::istream
*stream
= static_cast<flacStream
*>(client_data
)->fstream
;
850 return FLAC__STREAM_DECODER_READ_STATUS_ABORT
;
852 stream
->read(reinterpret_cast<char*>(buffer
), *bytes
);
853 *bytes
= stream
->gcount();
854 if(*bytes
== 0 && stream
->eof())
855 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
857 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
859 static FLAC__StreamDecoderSeekStatus
SeekCallback(const FLAC__StreamDecoder
*, FLAC__uint64 absolute_byte_offset
, void *client_data
)
861 std::istream
*stream
= static_cast<flacStream
*>(client_data
)->fstream
;
864 if(!stream
->seekg(absolute_byte_offset
))
865 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
;
866 return FLAC__STREAM_DECODER_SEEK_STATUS_OK
;
868 static FLAC__StreamDecoderTellStatus
TellCallback(const FLAC__StreamDecoder
*, FLAC__uint64
*absolute_byte_offset
, void *client_data
)
870 std::istream
*stream
= static_cast<flacStream
*>(client_data
)->fstream
;
873 *absolute_byte_offset
= stream
->tellg();
874 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
876 static FLAC__StreamDecoderLengthStatus
LengthCallback(const FLAC__StreamDecoder
*, FLAC__uint64
*stream_length
, void *client_data
)
878 std::istream
*stream
= static_cast<flacStream
*>(client_data
)->fstream
;
881 std::streampos pos
= stream
->tellg();
882 if(stream
->seekg(0, std::ios_base::end
))
884 *stream_length
= stream
->tellg();
889 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
;
890 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK
;
892 static FLAC__bool
EofCallback(const FLAC__StreamDecoder
*, void *client_data
)
894 std::istream
*stream
= static_cast<flacStream
*>(client_data
)->fstream
;
895 return (stream
->eof()) ? true : false;
899 struct flacStream
: public nullStream
{
900 flacStream(std::istream
*){}
906 struct mp3Stream
: public alureStream
{
907 mpg123_handle
*mp3File
;
911 virtual bool IsValid()
912 { return mp3File
!= NULL
; }
914 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
916 ALenum fmt
= alureGetSampleFormat(channels
, 16, 0);
919 *frequency
= samplerate
;
920 *blockalign
= channels
*2;
924 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
930 int ret
= mpg123_read(mp3File
, data
, bytes
, &got
);
936 if(ret
== MPG123_NEW_FORMAT
)
940 mpg123_getformat(mp3File
, &newrate
, &newchans
, &enc
);
942 if(ret
== MPG123_NEED_MORE
)
944 unsigned char data
[4096];
945 fstream
->read((char*)data
, sizeof(data
));
946 std::streamsize insize
= fstream
->gcount();
947 if(insize
> 0 && mpg123_feed(mp3File
, data
, insize
) == MPG123_OK
)
956 virtual bool Rewind()
959 std::istream::pos_type oldpos
= fstream
->tellg();
962 mpg123_handle
*newFile
= mpg123_new(NULL
, NULL
);
963 if(mpg123_open_feed(newFile
) == MPG123_OK
)
965 unsigned char data
[4096];
970 ALuint amt
, total
= 0;
972 fstream
->read((char*)data
, sizeof(data
));
973 amt
= fstream
->gcount();
976 ret
= mpg123_decode(newFile
, data
, amt
, NULL
, 0, NULL
);
977 } while(ret
== MPG123_NEED_MORE
&& total
< 64*1024);
979 if(ret
== MPG123_NEW_FORMAT
&&
980 mpg123_getformat(newFile
, &newrate
, &newchans
, &enc
) == MPG123_OK
)
982 if(mpg123_format_none(newFile
) == MPG123_OK
&&
983 mpg123_format(newFile
, samplerate
, channels
, MPG123_ENC_SIGNED_16
) == MPG123_OK
)
986 mpg123_delete(mp3File
);
991 mpg123_delete(newFile
);
994 fstream
->seekg(oldpos
);
995 SetError("Restart failed");
999 mp3Stream(std::istream
*_fstream
)
1000 : alureStream(_fstream
), mp3File(NULL
)
1002 mp3File
= mpg123_new(NULL
, NULL
);
1003 if(mpg123_open_feed(mp3File
) == MPG123_OK
)
1005 unsigned char data
[4096];
1008 ALuint amt
, total
= 0;
1010 fstream
->read((char*)data
, sizeof(data
));
1011 amt
= fstream
->gcount();
1014 ret
= mpg123_decode(mp3File
, data
, amt
, NULL
, 0, NULL
);
1015 } while(ret
== MPG123_NEED_MORE
&& total
< 64*1024);
1017 if(ret
== MPG123_NEW_FORMAT
&&
1018 mpg123_getformat(mp3File
, &samplerate
, &channels
, &enc
) == MPG123_OK
)
1020 if(mpg123_format_none(mp3File
) == MPG123_OK
&&
1021 mpg123_format(mp3File
, samplerate
, channels
, MPG123_ENC_SIGNED_16
) == MPG123_OK
)
1028 mpg123_delete(mp3File
);
1032 virtual ~mp3Stream()
1035 mpg123_delete(mp3File
);
1040 struct mp3Stream
: public nullStream
{
1041 mp3Stream(std::istream
*){}
1047 struct dumbStream
: public alureStream
{
1048 DUMBFILE_SYSTEM vfs
;
1051 DUH_SIGRENDERER
*renderer
;
1052 std::vector
<sample_t
> sampleBuf
;
1057 virtual bool IsValid()
1058 { return renderer
!= NULL
; }
1060 virtual bool GetFormat(ALenum
*fmt
, ALuint
*frequency
, ALuint
*blockalign
)
1062 if(format
== AL_NONE
)
1064 format
= alureGetSampleFormat(2, 0, 32);
1065 if(format
== AL_NONE
)
1066 format
= AL_FORMAT_STEREO16
;
1070 *blockalign
= 2 * ((format
==AL_FORMAT_STEREO16
) ? sizeof(ALshort
) :
1075 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1079 if(dumb_it_sr_get_speed(duh_get_it_sigrenderer(renderer
)) == 0)
1082 ALuint sample_count
= bytes
/ ((format
==AL_FORMAT_STEREO16
) ?
1083 sizeof(ALshort
) : sizeof(ALfloat
));
1085 sampleBuf
.resize(sample_count
);
1086 sample_t
*samples
= &sampleBuf
[0];
1088 dumb_silence(samples
, sample_count
);
1089 ret
= duh_sigrenderer_generate_samples(renderer
, 1.0f
, 1.0f
, sample_count
/2, &samples
);
1091 if(format
== AL_FORMAT_STEREO16
)
1093 for(ALuint i
= 0;i
< ret
;i
++)
1094 ((ALshort
*)data
)[i
] = clamp(samples
[i
]>>8, -32768, 32767);
1098 for(ALuint i
= 0;i
< ret
;i
++)
1099 ((ALfloat
*)data
)[i
] = ((samples
[i
]>=0) ?
1100 samples
[i
]/(float)0x7FFFFF :
1101 samples
[i
]/(float)0x800000);
1103 ret
*= ((format
==AL_FORMAT_STEREO16
) ? sizeof(ALshort
) : sizeof(ALfloat
));
1108 virtual bool Rewind()
1112 // If a previous speed was recorded, the stream tried to loop. So
1113 // let it loop on a rewind request.
1114 dumb_it_sr_set_speed(duh_get_it_sigrenderer(renderer
), prevSpeed
);
1119 // Else, no loop point. Restart from scratch.
1120 DUH_SIGRENDERER
*newrenderer
;
1121 newrenderer
= (lastOrder
? dumb_it_start_at_order(duh
, 2, lastOrder
) :
1122 duh_start_sigrenderer(duh
, 0, 2, 0));
1125 SetError("Could start renderer");
1128 duh_end_sigrenderer(renderer
);
1129 renderer
= newrenderer
;
1133 virtual bool SetOrder(ALuint order
)
1135 DUH_SIGRENDERER
*newrenderer
= dumb_it_start_at_order(duh
, 2, order
);
1138 SetError("Could not set order");
1141 duh_end_sigrenderer(renderer
);
1142 renderer
= newrenderer
;
1148 dumbStream(std::istream
*_fstream
)
1149 : alureStream(_fstream
), dumbFile(NULL
), duh(NULL
), renderer(NULL
),
1150 lastOrder(0), prevSpeed(0), format(AL_NONE
)
1152 DUH
* (*funcs
[])(DUMBFILE
*) = {
1155 dumb_read_s3m_quick
,
1156 dumb_read_mod_quick
,
1162 vfs
.getc
= read_char
;
1166 for(size_t i
= 0;funcs
[i
];i
++)
1168 dumbFile
= dumbfile_open_ex(this, &vfs
);
1171 duh
= funcs
[i
](dumbFile
);
1174 renderer
= duh_start_sigrenderer(duh
, 0, 2, 0);
1177 dumb_it_set_loop_callback(duh_get_it_sigrenderer(renderer
), loop_cb
, this);
1185 dumbfile_close(dumbFile
);
1193 virtual ~dumbStream()
1195 duh_end_sigrenderer(renderer
);
1202 dumbfile_close(dumbFile
);
1207 // DUMBFILE iostream callbacks
1208 static int skip(void *user_data
, long offset
)
1210 std::istream
*stream
= static_cast<dumbStream
*>(user_data
)->fstream
;
1213 if(stream
->seekg(offset
, std::ios_base::cur
))
1218 static long read(char *ptr
, long size
, void *user_data
)
1220 std::istream
*stream
= static_cast<dumbStream
*>(user_data
)->fstream
;
1223 stream
->read(static_cast<char*>(ptr
), size
);
1224 return stream
->gcount();
1227 static int read_char(void *user_data
)
1229 std::istream
*stream
= static_cast<dumbStream
*>(user_data
)->fstream
;
1233 stream
->read(reinterpret_cast<char*>(&ret
), 1);
1234 if(stream
->gcount() > 0)
1239 static int loop_cb(void *user_data
)
1241 dumbStream
*This
= static_cast<dumbStream
*>(user_data
);
1242 This
->prevSpeed
= dumb_it_sr_get_speed(duh_get_it_sigrenderer(This
->renderer
));
1243 dumb_it_sr_set_speed(duh_get_it_sigrenderer(This
->renderer
), 0);
1248 struct dumbStream
: public nullStream
{
1249 dumbStream(std::istream
*){}
1255 struct midiStream
: public alureStream
{
1259 static const ALuint Freq
= 48000;
1261 virtual bool IsValid()
1262 { return cpid
> 0; }
1264 virtual bool GetFormat(ALenum
*fmt
, ALuint
*frequency
, ALuint
*blockalign
)
1266 *fmt
= AL_FORMAT_STEREO16
;
1272 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1278 while((got
=read(pcmFile
, &data
[total
], bytes
)) == -1 && errno
== EINTR
)
1288 for(ALuint i
= 0;i
< total
;i
+=2)
1290 ALubyte tmp
= data
[i
];
1291 data
[i
] = data
[i
+1];
1299 virtual bool Rewind()
1304 int _pcmFile
; pid_t _cpid
;
1305 if(!StartStream(_pcmFile
, _cpid
))
1307 SetError("Failed to restart timidity");
1311 kill(cpid
, SIGTERM
);
1312 waitpid(cpid
, NULL
, 0);
1321 midiStream(std::istream
*_fstream
)
1322 : alureStream(_fstream
), pcmFile(-1), cpid(-1)
1324 StartStream(pcmFile
, cpid
);
1327 virtual ~midiStream()
1331 kill(cpid
, SIGTERM
);
1332 waitpid(cpid
, NULL
, 0);
1341 bool StartStream(int &pcmFile
, pid_t
&cpid
)
1344 std::vector
<ALubyte
> midiData
;
1346 fstream
->read(hdr
, sizeof(hdr
));
1347 if(fstream
->gcount() != sizeof(hdr
))
1350 if(memcmp(hdr
, "MThd", 4) == 0)
1353 for(size_t i
= 0;i
< sizeof(hdr
);i
++)
1354 midiData
.push_back(hdr
[i
]);
1355 while(fstream
->get(ch
))
1356 midiData
.push_back(ch
);
1358 else if(memcmp(hdr
, "MUS\x1a", sizeof(hdr
)) == 0)
1360 if(!ConvertMUS(midiData
))
1366 int midPipe
[2], pcmPipe
[2];
1367 if(pipe(midPipe
) == -1)
1369 if(pipe(pcmPipe
) == -1)
1388 if(dup2(midPipe
[0], STDIN_FILENO
) != -1 &&
1389 dup2(pcmPipe
[1], STDOUT_FILENO
) != -1)
1396 std::stringstream freqstr
;
1399 execlp("timidity","timidity","-","-idqq","-Ow1sl","-o","-",
1400 "-s", freqstr
.str().c_str(), NULL
);
1405 close(midPipe
[0]); midPipe
[0] = -1;
1406 close(pcmPipe
[1]); pcmPipe
[1] = -1;
1408 void (*oldhandler
)(int) = signal(SIGPIPE
, SIG_IGN
);
1409 ALubyte
*cur
= &midiData
[0];
1410 size_t rem
= midiData
.size();
1413 while((wrote
=write(midPipe
[1], cur
, rem
)) == -1 && errno
== EINTR
)
1420 close(midPipe
[1]); midPipe
[1] = -1;
1421 signal(SIGPIPE
, oldhandler
);
1425 rem
= sizeof(fmthdr
);
1428 while((got
=read(pcmPipe
[0], cur
, rem
)) == -1 && errno
== EINTR
)
1438 waitpid(pid
, NULL
, 0);
1443 pcmFile
= pcmPipe
[0];
1448 alureUInt64
ReadVarLen()
1450 alureUInt64 val
= 0;
1454 if(!fstream
->get(ch
))
1456 val
= (val
<<7) | (ch
&0x7f);
1462 void WriteVarLen(std::vector
<ALubyte
> &out
, alureUInt64 val
)
1464 alureUInt64 buffer
= val
&0x7f;
1465 while((val
>>=7) > 0)
1466 buffer
= (buffer
<<8) | 0x80 | (val
&0x7f);
1469 out
.push_back(buffer
&0xff);
1476 static const ALubyte MIDI_SYSEX
= 0xF0; // SysEx begin
1477 static const ALubyte MIDI_SYSEXEND
= 0xF7; // SysEx end
1478 static const ALubyte MIDI_META
= 0xFF; // Meta event begin
1479 static const ALubyte MIDI_META_TEMPO
= 0x51;
1480 static const ALubyte MIDI_META_EOT
= 0x2F; // End-of-track
1481 static const ALubyte MIDI_META_SSPEC
= 0x7F; // System-specific event
1483 static const ALubyte MIDI_NOTEOFF
= 0x80; // + note + velocity
1484 static const ALubyte MIDI_NOTEON
= 0x90; // + note + velocity
1485 static const ALubyte MIDI_POLYPRESS
= 0xA0; // + pressure (2 bytes)
1486 static const ALubyte MIDI_CTRLCHANGE
= 0xB0; // + ctrlr + value
1487 static const ALubyte MIDI_PRGMCHANGE
= 0xC0; // + new patch
1488 static const ALubyte MIDI_CHANPRESS
= 0xD0; // + pressure (1 byte)
1489 static const ALubyte MIDI_PITCHBEND
= 0xE0; // + pitch bend (2 bytes)
1491 static const ALubyte MUS_EVENT_CHANNEL_MASK
= 0x0F;
1492 static const ALubyte MUS_EVENT_DELTA_MASK
= 0x80;
1494 static const ALubyte MUS_NOTEOFF
= 0x00;
1495 static const ALubyte MUS_NOTEON
= 0x10;
1496 static const ALubyte MUS_PITCHBEND
= 0x20;
1497 static const ALubyte MUS_SYSEVENT
= 0x30;
1498 static const ALubyte MUS_CTRLCHANGE
= 0x40;
1499 static const ALubyte MUS_SCOREEND
= 0x60;
1501 bool ConvertMUS(std::vector
<ALubyte
> &midiData
)
1503 static const ALubyte CtrlTranslate
[15] = {
1504 0, // program change
1506 1, // modulation pot
1509 11, // expression pot
1512 64, // sustain pedal
1514 120, // all sounds off
1515 123, // all notes off
1518 121 // reset all controllers
1521 static const ALubyte MIDIhead
[22] = {
1522 'M','T','h','d', 0, 0, 0, 6,
1523 0, 0, // format 0: only one track
1524 0, 1, // yes, there is really only one track
1525 0, 70, // 70 divisions
1526 'M','T','r','k', 0xFF, 0xFF, 0xFF, 0xFF
1529 // The MUS\x1a ID was already read and verified
1530 ALushort songLen
= read_le16(fstream
);
1531 ALushort songStart
= read_le16(fstream
);
1532 ALushort numChans
= read_le16(fstream
);
1534 // Sanity check the MUS file's channel count
1538 fstream
->seekg(songStart
);
1539 std::streamsize maxmus_p
= songLen
;
1540 maxmus_p
+= fstream
->tellg();
1542 ALubyte chanVel
[16];
1543 for(size_t i
= 0;i
< 16;i
++)
1547 for(size_t i
= 0;i
< 16;i
++)
1550 alureUInt64 deltaTime
= 0;
1555 for(size_t i
= 0;i
< sizeof(MIDIhead
);i
++)
1556 midiData
.push_back(MIDIhead
[i
]);
1558 // The first event sets the tempo to 500,000 microsec/quarter note
1559 midiData
.push_back(0);
1560 midiData
.push_back(MIDI_META
| 0);
1561 midiData
.push_back(MIDI_META_TEMPO
| 0);
1562 midiData
.push_back(3);
1563 midiData
.push_back(0x07);
1564 midiData
.push_back(0xA1);
1565 midiData
.push_back(0x20);
1567 while(fstream
->good() && fstream
->tellg() < maxmus_p
&& event
!= MUS_SCOREEND
)
1569 event
= fstream
->get();
1571 bool hasDelta
= event
&MUS_EVENT_DELTA_MASK
;
1572 ALubyte channel
= event
&MUS_EVENT_CHANNEL_MASK
;
1574 event
&= ~MUS_EVENT_DELTA_MASK
;
1575 event
&= ~MUS_EVENT_CHANNEL_MASK
;
1577 // Convert percussion channel (MUS #15 -> MIDI #9)
1580 else if(channel
>= 9)
1583 if(firstUse
[channel
])
1585 // This is the first time this channel has been used,
1586 // so sets its volume to 127.
1587 firstUse
[channel
] = false;
1588 midiData
.push_back(0);
1589 midiData
.push_back(MIDI_CTRLCHANGE
| channel
);
1590 midiData
.push_back(7);
1591 midiData
.push_back(127);
1595 if(event
!= MUS_SCOREEND
)
1598 ALubyte midArgs
= 2;
1599 ALubyte midStatus
= channel
;
1600 ALubyte mid1
= 0, mid2
= 0;
1606 midStatus
|= MIDI_NOTEOFF
;
1612 midStatus
|= MIDI_NOTEON
;
1615 chanVel
[channel
] = fstream
->get()&0x7f;
1616 mid2
= chanVel
[channel
];
1620 midStatus
|= MIDI_PITCHBEND
;
1622 mid2
= (t
>>1) & 0x7f;
1626 if(t
< 10 || t
> 14)
1630 midStatus
|= MIDI_CTRLCHANGE
;
1631 mid1
= CtrlTranslate
[t
];
1632 mid2
= ((t
==12) /* Mono */ ? numChans
: 0);
1636 case MUS_CTRLCHANGE
:
1639 // Program change, only one arg
1641 midStatus
|= MIDI_PRGMCHANGE
;
1642 mid1
= fstream
->get()&0x7f;
1646 midStatus
|= MIDI_CTRLCHANGE
;
1647 mid1
= CtrlTranslate
[t
];
1648 mid2
= fstream
->get();
1655 midStatus
= MIDI_META
;
1656 mid1
= MIDI_META_EOT
;
1666 // A system-specific event with no data is a no-op.
1667 midStatus
= MIDI_META
;
1668 mid1
= MIDI_META_SSPEC
;
1672 WriteVarLen(midiData
, deltaTime
);
1673 if(midStatus
!= status
)
1676 midiData
.push_back(status
);
1679 midiData
.push_back(mid1
);
1681 midiData
.push_back(mid2
);
1683 deltaTime
= (hasDelta
? ReadVarLen() : 0);
1686 // If reading failed or we overran the song length, the song is bad
1687 if(!fstream
->good() || fstream
->tellg() > maxmus_p
)
1690 // Fill in track length
1691 size_t trackLen
= midiData
.size() - 22;
1692 midiData
[18] = (trackLen
>>24) & 0xff;
1693 midiData
[19] = (trackLen
>>16) & 0xff;
1694 midiData
[20] = (trackLen
>>8) & 0xff;
1695 midiData
[21] = trackLen
&0xff;
1700 struct midiStream
: public nullStream
{
1701 midiStream(std::istream
*){}
1706 #ifdef HAS_GSTREAMER
1707 struct gstStream
: public alureStream
{
1708 GstElement
*gstPipeline
;
1714 std::vector
<ALubyte
> initialData
;
1720 virtual bool IsValid()
1721 { return gstPipeline
!= NULL
; }
1723 virtual bool GetFormat(ALenum
*format
, ALuint
*frequency
, ALuint
*blockalign
)
1725 *format
= this->format
;
1726 *frequency
= samplerate
;
1727 *blockalign
= blockAlign
;
1731 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
1737 if(initialData
.size() > 0)
1739 size_t rem
= std::min(initialData
.size(), (size_t)bytes
);
1740 memcpy(data
, &initialData
[0], rem
);
1742 initialData
.erase(initialData
.begin(), initialData
.begin()+rem
);
1745 GstElement
*gstSink
= gst_bin_get_by_name(GST_BIN(gstPipeline
), "alureSink");
1746 while(outTotal
< outLen
&& !gst_app_sink_is_eos((GstAppSink
*)gstSink
))
1747 on_new_buffer_from_source(gstSink
);
1748 gst_object_unref(gstSink
);
1753 virtual bool Rewind()
1755 GstSeekFlags flags
= GstSeekFlags(GST_SEEK_FLAG_FLUSH
|GST_SEEK_FLAG_KEY_UNIT
);
1756 if(gst_element_seek_simple(gstPipeline
, GST_FORMAT_TIME
, flags
, 0))
1758 initialData
.clear();
1762 SetError("Seek failed");
1766 gstStream(std::istream
*_fstream
)
1767 : alureStream(_fstream
), gstPipeline(NULL
), format(AL_NONE
), outBytes(NULL
),
1768 outLen(0), outTotal(0)
1771 virtual ~gstStream()
1775 gst_element_set_state(gstPipeline
, GST_STATE_NULL
);
1776 gst_object_unref(gstPipeline
);
1784 fstream
->seekg(0, std::ios_base::end
);
1785 std::streamsize len
= fstream
->tellg();
1786 fstream
->seekg(0, std::ios_base::beg
);
1788 if(!fstream
->good() || len
<= 0)
1791 std::string gst_audio_caps
;
1792 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
1794 static const struct {
1799 { "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" },
1800 { "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" },
1801 { "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" },
1802 { "AL_FORMAT_STEREO_FLOAT32", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1803 { "AL_FORMAT_MONO_FLOAT32", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1804 { NULL
, NULL
, NULL
}
1806 { "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" },
1807 { "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" },
1808 { "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" },
1809 { "AL_FORMAT_STEREO16", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1810 { "AL_FORMAT_MONO16", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1811 { NULL
, NULL
, NULL
}
1813 { "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" },
1814 { "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" },
1815 { "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" },
1816 { "AL_FORMAT_STEREO8", "2", "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT" },
1817 { "AL_FORMAT_MONO8", "1", "GST_AUDIO_CHANNEL_POSITION_FRONT_MONO" },
1818 { NULL
, NULL
, NULL
}
1821 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
1823 for(int i
= 0;fmts32
[i
].ename
;i
++)
1825 if(alGetEnumValue(fmts32
[i
].ename
) == 0)
1829 "audio/x-raw-float, \n\t"
1830 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER
) " }, \n\t"
1831 "signed = (boolean) TRUE, \n\t"
1832 "width = (int) 32, \n\t"
1833 "depth = (int) 32, \n\t"
1834 "rate = (int) [ 1, MAX ], \n\t"
1835 "channels = (int) ";
1836 gst_audio_caps
+= fmts32
[i
].chans
;
1837 gst_audio_caps
+= ", \n\t"
1838 "channel-positions = (GstAudioChannelPosition) < ";
1839 gst_audio_caps
+= fmts32
[i
].order
;
1840 gst_audio_caps
+= " >; \n";
1843 for(int i
= 0;fmts16
[i
].ename
;i
++)
1845 if(alGetEnumValue(fmts16
[i
].ename
) == 0)
1849 "audio/x-raw-int, \n\t"
1850 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER
) " }, \n\t"
1851 "signed = (boolean) TRUE, \n\t"
1852 "width = (int) 16, \n\t"
1853 "depth = (int) 16, \n\t"
1854 "rate = (int) [ 1, MAX ], \n\t"
1855 "channels = (int) ";
1856 gst_audio_caps
+= fmts16
[i
].chans
;
1857 gst_audio_caps
+= ", \n\t"
1858 "channel-positions = (GstAudioChannelPosition) < ";
1859 gst_audio_caps
+= fmts16
[i
].order
;
1860 gst_audio_caps
+= " >; \n";
1862 for(int i
= 0;fmts8
[i
].ename
;i
++)
1864 if(alGetEnumValue(fmts8
[i
].ename
) == 0)
1868 "audio/x-raw-int, \n\t"
1869 "signed = (boolean) FALSE, \n\t"
1870 "width = (int) 8, \n\t"
1871 "depth = (int) 8, \n\t"
1872 "rate = (int) [ 1, MAX ], \n\t"
1873 "channels = (int) ";
1874 gst_audio_caps
+= fmts8
[i
].chans
;
1875 gst_audio_caps
+= ", \n\t"
1876 "channel-positions = (GstAudioChannelPosition) < ";
1877 gst_audio_caps
+= fmts8
[i
].order
;
1878 gst_audio_caps
+= " >; \n";
1883 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
1886 "audio/x-raw-float, \n\t"
1887 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER
) " }, \n\t"
1888 "signed = (boolean) TRUE, \n\t"
1889 "width = (int) 32, \n\t"
1890 "depth = (int) 32, \n\t"
1891 "rate = (int) [ 1, MAX ], \n\t"
1892 "channels = (int) [ 1, 2 ]; \n";
1895 "audio/x-raw-int, \n\t"
1896 "endianness = (int) { " G_STRINGIFY(G_BYTE_ORDER
) " }, \n\t"
1897 "signed = (boolean) TRUE, \n\t"
1898 "width = (int) 16, \n\t"
1899 "depth = (int) 16, \n\t"
1900 "rate = (int) [ 1, MAX ], \n\t"
1901 "channels = (int) [ 1, 2 ]; \n";
1903 "audio/x-raw-int, \n\t"
1904 "signed = (boolean) FALSE, \n\t"
1905 "width = (int) 8, \n\t"
1906 "depth = (int) 8, \n\t"
1907 "rate = (int) [ 1, MAX ], \n\t"
1908 "channels = (int) [ 1, 2 ]; \n";
1911 gchar
*string
= g_strdup_printf("appsrc name=alureSrc ! decodebin ! audioconvert ! appsink caps=\"%s\" name=alureSink", gst_audio_caps
.c_str());
1912 gstPipeline
= gst_parse_launch(string
, NULL
);
1918 GstElement
*gstSrc
= gst_bin_get_by_name(GST_BIN(gstPipeline
), "alureSrc");
1919 GstElement
*gstSink
= gst_bin_get_by_name(GST_BIN(gstPipeline
), "alureSink");
1921 if(gstSrc
&& gstSink
)
1923 g_object_set(G_OBJECT(gstSrc
), "size", (gint64
)len
, NULL
);
1924 g_object_set(G_OBJECT(gstSrc
), "stream-type", 2, NULL
);
1926 /* configure the appsrc, we will push a buffer to appsrc when it
1927 * needs more data */
1928 g_signal_connect(gstSrc
, "need-data", G_CALLBACK(feed_data
), this);
1929 g_signal_connect(gstSrc
, "seek-data", G_CALLBACK(seek_data
), this);
1931 g_object_set(G_OBJECT(gstSink
), "preroll-queue-len", 1, NULL
);
1932 g_object_set(G_OBJECT(gstSink
), "max-buffers", 2, NULL
);
1933 g_object_set(G_OBJECT(gstSink
), "drop", FALSE
, NULL
);
1934 g_object_set(G_OBJECT(gstSink
), "sync", FALSE
, NULL
);
1936 GstBus
*bus
= gst_element_get_bus(gstPipeline
);
1939 const GstMessageType types
= GstMessageType(GST_MESSAGE_ERROR
|GST_MESSAGE_ASYNC_DONE
);
1942 gst_element_set_state(gstPipeline
, GST_STATE_PLAYING
);
1943 while((msg
=gst_bus_timed_pop_filtered(bus
, GST_CLOCK_TIME_NONE
, types
)) != NULL
)
1945 if(GST_MESSAGE_TYPE(msg
) == GST_MESSAGE_ASYNC_DONE
)
1947 on_new_preroll_from_source(gstSink
);
1948 gst_message_unref(msg
);
1952 if(GST_MESSAGE_TYPE(msg
) == GST_MESSAGE_ERROR
)
1957 gst_message_parse_error(msg
, &error
, &debug
);
1958 g_printerr("GST Error: %s\n", error
->message
);
1961 g_error_free(error
);
1963 gst_message_unref(msg
);
1966 gst_message_unref(msg
);
1969 gst_object_unref(bus
);
1974 if(gstSrc
) gst_object_unref(gstSrc
);
1975 if(gstSink
) gst_object_unref(gstSink
);
1977 if(format
== AL_NONE
)
1979 gst_element_set_state(gstPipeline
, GST_STATE_NULL
);
1980 gst_object_unref(gstPipeline
);
1985 void on_new_preroll_from_source(GstElement
*elt
)
1987 // get the buffer from appsink
1988 GstBuffer
*buffer
= gst_app_sink_pull_preroll(GST_APP_SINK(elt
));
1992 if(format
== AL_NONE
)
1994 GstCaps
*caps
= GST_BUFFER_CAPS(buffer
);
1995 //GST_LOG("caps are %" GST_PTR_FORMAT, caps);
1998 gint rate
= 0, channels
= 0, bits
= 0;
1999 for(i
= gst_caps_get_size(caps
)-1;i
>= 0;i
--)
2001 GstStructure
*struc
= gst_caps_get_structure(caps
, i
);
2002 if(gst_structure_has_field(struc
, "channels"))
2003 gst_structure_get_int(struc
, "channels", &channels
);
2004 if(gst_structure_has_field(struc
, "rate"))
2005 gst_structure_get_int(struc
, "rate", &rate
);
2006 if(gst_structure_has_field(struc
, "width"))
2007 gst_structure_get_int(struc
, "width", &bits
);
2012 format
= alureGetSampleFormat(channels
, 0, bits
);
2014 format
= alureGetSampleFormat(channels
, bits
, 0);
2015 blockAlign
= channels
* bits
/ 8;
2018 /* we don't need the appsink buffer anymore */
2019 gst_buffer_unref(buffer
);
2022 void on_new_buffer_from_source(GstElement
*elt
)
2024 // get the buffer from appsink
2025 GstBuffer
*buffer
= gst_app_sink_pull_buffer(GST_APP_SINK(elt
));
2029 ALubyte
*src_buffer
= (ALubyte
*)(GST_BUFFER_DATA(buffer
));
2030 guint size
= GST_BUFFER_SIZE(buffer
);
2031 guint rem
= std::min(size
, outLen
-outTotal
);
2033 memcpy(outBytes
+outTotal
, src_buffer
, rem
);
2038 size_t start
= initialData
.size();
2039 initialData
.resize(start
+size
-rem
);
2040 memcpy(&initialData
[start
], src_buffer
+rem
, initialData
.size()-start
);
2043 /* we don't need the appsink buffer anymore */
2044 gst_buffer_unref(buffer
);
2047 static void feed_data(GstElement
*appsrc
, guint size
, gstStream
*app
)
2051 if(!app
->fstream
->good())
2053 // we are EOS, send end-of-stream
2054 g_signal_emit_by_name(appsrc
, "end-of-stream", &ret
);
2058 // read any amount of data, we are allowed to return less if we are EOS
2059 GstBuffer
*buffer
= gst_buffer_new();
2060 void *data
= g_malloc(size
);
2062 app
->fstream
->read(static_cast<char*>(data
), size
);
2064 GST_BUFFER_SIZE(buffer
) = app
->fstream
->gcount();
2065 GST_BUFFER_MALLOCDATA(buffer
) = static_cast<guint8
*>(data
);
2066 GST_BUFFER_DATA(buffer
) = GST_BUFFER_MALLOCDATA(buffer
);
2068 //GST_DEBUG("feed buffer %p, %u", buffer, GST_BUFFER_SIZE(buffer));
2069 g_signal_emit_by_name(appsrc
, "push-buffer", buffer
, &ret
);
2070 gst_buffer_unref(buffer
);
2073 static gboolean
seek_data(GstElement */
*appsrc*/
, guint64 position
, gstStream
*app
)
2075 //GST_DEBUG("seek to offset %" G_GUINT64_FORMAT, position);
2076 app
->fstream
->clear();
2077 return (app
->fstream
->seekg(position
) ? TRUE
: FALSE
);
2081 struct gstStream
: public nullStream
{
2082 gstStream(std::istream
*){}
2087 template <typename T
>
2088 alureStream
*get_stream_decoder(const T
&fdata
)
2090 alureStream
*stream
;
2092 std::map
<ALint
,UserCallbacks
>::iterator i
= InstalledCallbacks
.begin();
2093 while(i
!= InstalledCallbacks
.end() && i
->first
< 0)
2095 stream
= new customStream(fdata
, i
->second
);
2096 if(stream
->IsValid())
2102 std::istream
*file
= new InStream(fdata
);
2105 stream
= new wavStream(file
);
2106 if(stream
->IsValid())
2111 file
->seekg(0, std::ios_base::beg
);
2112 stream
= new aiffStream(file
);
2113 if(stream
->IsValid())
2117 // Try libVorbisFile
2119 file
->seekg(0, std::ios_base::beg
);
2120 stream
= new oggStream(file
);
2121 if(stream
->IsValid())
2127 file
->seekg(0, std::ios_base::beg
);
2128 stream
= new flacStream(file
);
2129 if(stream
->IsValid())
2135 file
->seekg(0, std::ios_base::beg
);
2136 stream
= new dumbStream(file
);
2137 if(stream
->IsValid())
2143 file
->seekg(0, std::ios_base::beg
);
2144 stream
= new sndStream(file
);
2145 if(stream
->IsValid())
2151 file
->seekg(0, std::ios_base::beg
);
2152 stream
= new mp3Stream(file
);
2153 if(stream
->IsValid())
2159 file
->seekg(0, std::ios_base::beg
);
2160 stream
= new midiStream(file
);
2161 if(stream
->IsValid())
2167 file
->seekg(0, std::ios_base::beg
);
2168 stream
= new gstStream(file
);
2169 if(stream
->IsValid())
2173 SetError("Unsupported type");
2178 SetError("Failed to open file");
2182 while(i
!= InstalledCallbacks
.end())
2184 stream
= new customStream(fdata
, i
->second
);
2185 if(stream
->IsValid())
2191 return new nullStream
;
2194 alureStream
*create_stream(const char *fname
)
2195 { return get_stream_decoder(fname
); }
2196 alureStream
*create_stream(const MemDataInfo
&memData
)
2197 { return get_stream_decoder(memData
); }