Remove the GStreamer decoder
[alure.git] / src / streamdec.cpp
blob745035ae4381525ba162d4a2bea6af042803b22f
1 /*
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
21 #include "config.h"
23 #include "main.h"
25 #include <string.h>
27 #include <algorithm>
28 #include <vector>
29 #include <memory>
30 #include <string>
31 #include <istream>
32 #include <fstream>
33 #include <iostream>
34 #include <sstream>
37 static inline ALuint read_le32(std::istream *file)
39 ALubyte buffer[4];
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)
46 ALubyte buffer[2];
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)
53 ALubyte buffer[4];
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)
60 ALubyte buffer[2];
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)
67 ALubyte buffer[10];
68 if(!file->read(reinterpret_cast<char*>(buffer), 10)) return 0;
69 ALuint mantissa, last = 0;
70 ALubyte exp = buffer[1];
71 exp = 30 - exp;
72 mantissa = (buffer[2]<<24) | (buffer[3]<<16) | (buffer[4]<<8) | buffer[5];
73 while (exp--)
75 last = mantissa;
76 mantissa >>= 1;
78 if((last&1)) mantissa++;
79 return mantissa;
83 struct nullStream : public alureStream {
84 virtual bool IsValid() { return false; }
85 virtual bool GetFormat(ALenum*,ALuint*,ALuint*) { return false; }
86 virtual ALuint GetData(ALubyte*,ALuint) { return 0; }
87 virtual bool Rewind() { return false; }
88 nullStream():alureStream(NULL) {}
92 struct customStream : public alureStream {
93 void *usrFile;
94 ALenum format;
95 ALuint samplerate;
96 ALuint blockAlign;
97 MemDataInfo memInfo;
99 UserCallbacks cb;
101 virtual bool IsValid()
102 { return usrFile != NULL; }
104 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
106 if(format == AL_NONE)
108 if(!cb.get_fmt ||
109 !cb.get_fmt(usrFile, &this->format, &samplerate, &blockAlign))
110 return false;
113 *fmt = format;
114 *frequency = samplerate;
115 *blockalign = blockAlign;
116 return true;
119 virtual ALuint GetData(ALubyte *data, ALuint bytes)
120 { return cb.decode(usrFile, data, bytes); }
122 virtual bool Rewind()
124 if(cb.rewind && cb.rewind(usrFile))
125 return true;
126 SetError("Rewind failed");
127 return false;
130 customStream(const char *fname, const UserCallbacks &callbacks)
131 : alureStream(NULL), usrFile(NULL), format(0), samplerate(0),
132 blockAlign(0), cb(callbacks)
133 { if(cb.open_file) usrFile = cb.open_file(fname); }
135 customStream(const MemDataInfo &memData, const UserCallbacks &callbacks)
136 : alureStream(NULL), usrFile(NULL), format(0), samplerate(0),
137 blockAlign(0), memInfo(memData), cb(callbacks)
138 { if(cb.open_mem) usrFile = cb.open_mem(memInfo.Data, memInfo.Length); }
140 customStream(void *userdata, ALenum fmt, ALuint srate, const UserCallbacks &callbacks)
141 : alureStream(NULL), usrFile(userdata), format(fmt), samplerate(srate),
142 blockAlign(DetectBlockAlignment(format)), cb(callbacks)
145 virtual ~customStream()
147 if(cb.close && usrFile)
148 cb.close(usrFile);
149 usrFile = NULL;
154 struct wavStream : public alureStream {
155 ALenum format;
156 int samplerate;
157 int blockAlign;
158 int sampleSize;
159 long dataStart;
160 long dataLen;
161 size_t remLen;
163 virtual bool IsValid()
164 { return (dataStart > 0 && format != AL_NONE); }
166 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
168 *fmt = format;
169 *frequency = samplerate;
170 *blockalign = blockAlign;
171 return true;
174 virtual ALuint GetData(ALubyte *data, ALuint bytes)
176 std::streamsize rem = ((remLen >= bytes) ? bytes : remLen) / blockAlign;
177 fstream->read(reinterpret_cast<char*>(data), rem*blockAlign);
179 std::streamsize got = fstream->gcount();
180 got -= got%blockAlign;
181 remLen -= got;
183 if(BigEndian && sampleSize > 1)
185 if(sampleSize == 2)
187 for(std::streamsize i = 0;i < got;i+=2)
188 swap(data[i], data[i+1]);
190 else if(sampleSize == 4)
192 for(std::streamsize i = 0;i < got;i+=4)
194 swap(data[i+0], data[i+3]);
195 swap(data[i+1], data[i+2]);
200 return got;
203 virtual bool Rewind()
205 fstream->clear();
206 if(fstream->seekg(dataStart))
208 remLen = dataLen;
209 return true;
212 SetError("Seek failed");
213 return false;
216 wavStream(std::istream *_fstream)
217 : alureStream(_fstream), format(0), dataStart(0)
219 ALubyte buffer[25];
220 int length;
222 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
223 memcmp(buffer, "RIFF", 4) != 0 || memcmp(buffer+8, "WAVE", 4) != 0)
224 return;
226 while(!dataStart || format == AL_NONE)
228 char tag[4];
229 if(!fstream->read(tag, 4))
230 break;
232 /* read chunk length */
233 length = read_le32(fstream);
235 if(memcmp(tag, "fmt ", 4) == 0 && length >= 16)
237 /* Data type (should be 1 for PCM data) */
238 int type = read_le16(fstream);
239 if(type != 1)
240 break;
242 /* mono or stereo data */
243 int channels = read_le16(fstream);
245 /* sample frequency */
246 samplerate = read_le32(fstream);
248 /* skip four bytes */
249 fstream->ignore(4);
251 /* bytes per block */
252 blockAlign = read_le16(fstream);
253 if(blockAlign == 0)
254 break;
256 /* bits per sample */
257 sampleSize = read_le16(fstream) / 8;
259 format = GetSampleFormat(channels, sampleSize*8, false);
261 length -= 16;
263 else if(memcmp(tag, "data", 4) == 0)
265 dataStart = fstream->tellg();
266 dataLen = remLen = length;
269 fstream->seekg(length, std::ios_base::cur);
272 if(dataStart > 0 && format != AL_NONE)
273 fstream->seekg(dataStart);
276 virtual ~wavStream()
280 struct aiffStream : public alureStream {
281 ALenum format;
282 int samplerate;
283 int blockAlign;
284 int sampleSize;
285 long dataStart;
286 long dataLen;
287 size_t remLen;
289 virtual bool IsValid()
290 { return (dataStart > 0 && format != AL_NONE); }
292 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
294 *fmt = format;
295 *frequency = samplerate;
296 *blockalign = blockAlign;
297 return true;
300 virtual ALuint GetData(ALubyte *data, ALuint bytes)
302 std::streamsize rem = ((remLen >= bytes) ? bytes : remLen) / blockAlign;
303 fstream->read(reinterpret_cast<char*>(data), rem*blockAlign);
305 std::streamsize got = fstream->gcount();
306 got -= got%blockAlign;
307 remLen -= got;
309 if(LittleEndian)
311 if(sampleSize == 2)
313 for(std::streamsize i = 0;i < got;i+=2)
314 swap(data[i], data[i+1]);
316 else if(sampleSize == 4)
318 for(std::streamsize i = 0;i < got;i+=4)
320 swap(data[i+0], data[i+3]);
321 swap(data[i+1], data[i+2]);
326 return got;
329 virtual bool Rewind()
331 fstream->clear();
332 if(fstream->seekg(dataStart))
334 remLen = dataLen;
335 return true;
338 SetError("Seek failed");
339 return false;
342 aiffStream(std::istream *_fstream)
343 : alureStream(_fstream), format(0), dataStart(0)
345 ALubyte buffer[25];
346 int length;
348 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
349 memcmp(buffer, "FORM", 4) != 0 || memcmp(buffer+8, "AIFF", 4) != 0)
350 return;
352 while(!dataStart || format == AL_NONE)
354 char tag[4];
355 if(!fstream->read(tag, 4))
356 break;
358 /* read chunk length */
359 length = read_be32(fstream);
361 if(memcmp(tag, "COMM", 4) == 0 && length >= 18)
363 /* mono or stereo data */
364 int channels = read_be16(fstream);
366 /* number of sample frames */
367 fstream->ignore(4);
369 /* bits per sample */
370 sampleSize = read_be16(fstream) / 8;
372 /* sample frequency */
373 samplerate = read_be80extended(fstream);
375 /* block alignment */
376 blockAlign = channels * sampleSize;
378 format = GetSampleFormat(channels, sampleSize*8, false);
380 length -= 18;
382 else if(memcmp(tag, "SSND", 4) == 0)
384 dataStart = fstream->tellg();
385 dataStart += 8;
386 dataLen = remLen = length - 8;
389 fstream->seekg(length, std::ios_base::cur);
392 if(dataStart > 0 && format != AL_NONE)
393 fstream->seekg(dataStart);
396 virtual ~aiffStream()
400 #ifdef HAS_SNDFILE
401 struct sndStream : public alureStream {
402 SNDFILE *sndFile;
403 SF_INFO sndInfo;
404 ALenum format;
406 virtual bool IsValid()
407 { return sndFile != NULL; }
409 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
411 if(format == AL_NONE)
412 format = GetSampleFormat(sndInfo.channels, 16, false);
413 *fmt = format;
414 *frequency = sndInfo.samplerate;
415 *blockalign = sndInfo.channels*2;
416 return true;
419 virtual ALuint GetData(ALubyte *data, ALuint bytes)
421 const ALuint frameSize = 2*sndInfo.channels;
422 return psf_readf_short(sndFile, (short*)data, bytes/frameSize) * frameSize;
425 virtual bool Rewind()
427 if(psf_seek(sndFile, 0, SEEK_SET) != -1)
428 return true;
430 SetError("Seek failed");
431 return false;
434 sndStream(std::istream *_fstream)
435 : alureStream(_fstream), sndFile(NULL), format(AL_NONE)
437 memset(&sndInfo, 0, sizeof(sndInfo));
439 if(!sndfile_handle) return;
441 static SF_VIRTUAL_IO streamIO = {
442 get_filelen, seek,
443 read, write, tell
445 sndFile = psf_open_virtual(&streamIO, SFM_READ, &sndInfo, this);
448 virtual ~sndStream()
450 if(sndFile)
451 psf_close(sndFile);
452 sndFile = NULL;
455 private:
456 // libSndFile iostream callbacks
457 static sf_count_t get_filelen(void *user_data)
459 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
460 stream->clear();
462 std::streampos len = -1;
463 std::streampos pos = stream->tellg();
464 if(stream->seekg(0, std::ios_base::end))
466 len = stream->tellg();
467 stream->seekg(pos);
470 return len;
473 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
475 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
476 stream->clear();
478 if(whence == SEEK_CUR)
479 stream->seekg(offset, std::ios_base::cur);
480 else if(whence == SEEK_SET)
481 stream->seekg(offset, std::ios_base::beg);
482 else if(whence == SEEK_END)
483 stream->seekg(offset, std::ios_base::end);
484 else
485 return -1;
487 return stream->tellg();
490 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
492 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
493 stream->clear();
494 stream->read(static_cast<char*>(ptr), count);
495 return stream->gcount();
498 static sf_count_t write(const void*, sf_count_t, void*)
499 { return -1; }
501 static sf_count_t tell(void *user_data)
503 std::istream *stream = static_cast<sndStream*>(user_data)->fstream;
504 stream->clear();
505 return stream->tellg();
508 #else
509 struct sndStream : public nullStream {
510 sndStream(std::istream*){}
512 #endif
514 #ifdef HAS_VORBISFILE
515 struct oggStream : public alureStream {
516 OggVorbis_File oggFile;
517 vorbis_info *oggInfo;
518 int oggBitstream;
519 ALenum format;
521 virtual bool IsValid()
522 { return oggInfo != NULL; }
524 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
526 if(format == AL_NONE)
527 format = GetSampleFormat(oggInfo->channels, 16, false);
528 *fmt = format;
529 *frequency = oggInfo->rate;
530 *blockalign = oggInfo->channels*2;
531 return true;
534 virtual ALuint GetData(ALubyte *data, ALuint bytes)
536 ALuint got = 0;
537 while(bytes > 0)
539 int res = pov_read(&oggFile, (char*)&data[got], bytes, BigEndian?1:0, 2, 1, &oggBitstream);
540 if(res <= 0)
541 break;
542 bytes -= res;
543 got += res;
545 // 1, 2, and 4 channel files decode into the same channel order as
546 // OpenAL, however 6(5.1), 7(6.1), and 8(7.1) channel files need to be
547 // re-ordered
548 if(oggInfo->channels == 6)
550 ALshort *samples = (ALshort*)data;
551 for(ALuint i = 0;i < got/sizeof(ALshort);i+=6)
553 // OpenAL : FL, FR, FC, LFE, RL, RR
554 // Vorbis : FL, FC, FR, RL, RR, LFE
555 swap(samples[i+1], samples[i+2]);
556 swap(samples[i+3], samples[i+5]);
557 swap(samples[i+4], samples[i+5]);
560 else if(oggInfo->channels == 7)
562 ALshort *samples = (ALshort*)data;
563 for(ALuint i = 0;i < got/sizeof(ALshort);i+=7)
565 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
566 // Vorbis : FL, FC, FR, SL, SR, RC, LFE
567 swap(samples[i+1], samples[i+2]);
568 swap(samples[i+3], samples[i+6]);
569 swap(samples[i+4], samples[i+6]);
570 swap(samples[i+5], samples[i+6]);
573 else if(oggInfo->channels == 8)
575 ALshort *samples = (ALshort*)data;
576 for(ALuint i = 0;i < got/sizeof(ALshort);i+=8)
578 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
579 // Vorbis : FL, FC, FR, SL, SR, RL, RR, LFE
580 swap(samples[i+1], samples[i+2]);
581 swap(samples[i+3], samples[i+7]);
582 swap(samples[i+4], samples[i+5]);
583 swap(samples[i+5], samples[i+6]);
584 swap(samples[i+6], samples[i+7]);
587 return got;
590 virtual bool Rewind()
592 if(pov_pcm_seek(&oggFile, 0) == 0)
593 return true;
595 SetError("Seek failed");
596 return false;
599 oggStream(std::istream *_fstream)
600 : alureStream(_fstream), oggInfo(NULL), oggBitstream(0), format(AL_NONE)
602 if(!vorbisfile_handle) return;
604 const ov_callbacks streamIO = {
605 read, seek, NULL, tell
608 if(pov_open_callbacks(this, &oggFile, NULL, 0, streamIO) == 0)
610 oggInfo = pov_info(&oggFile, -1);
611 if(!oggInfo)
612 pov_clear(&oggFile);
616 virtual ~oggStream()
618 if(oggInfo)
619 pov_clear(&oggFile);
620 oggInfo = NULL;
623 private:
624 // libVorbisFile iostream callbacks
625 static int seek(void *user_data, ogg_int64_t offset, int whence)
627 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
628 stream->clear();
630 if(whence == SEEK_CUR)
631 stream->seekg(offset, std::ios_base::cur);
632 else if(whence == SEEK_SET)
633 stream->seekg(offset, std::ios_base::beg);
634 else if(whence == SEEK_END)
635 stream->seekg(offset, std::ios_base::end);
636 else
637 return -1;
639 return stream->tellg();
642 static size_t read(void *ptr, size_t size, size_t nmemb, void *user_data)
644 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
645 stream->clear();
647 stream->read(static_cast<char*>(ptr), nmemb*size);
648 size_t ret = stream->gcount();
649 return ret/size;
652 static long tell(void *user_data)
654 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
655 stream->clear();
656 return stream->tellg();
659 #else
660 struct oggStream : public nullStream {
661 oggStream(std::istream*){}
663 #endif
665 #ifdef HAS_FLAC
666 struct flacStream : public alureStream {
667 FLAC__StreamDecoder *flacFile;
668 ALenum format;
669 ALuint samplerate;
670 ALuint blockAlign;
671 ALboolean useFloat;
673 std::vector<ALubyte> initialData;
675 ALubyte *outBytes;
676 ALuint outLen;
677 ALuint outTotal;
679 virtual bool IsValid()
680 { return flacFile != NULL; }
682 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
684 *fmt = format;
685 *frequency = samplerate;
686 *blockalign = blockAlign;
687 return true;
690 virtual ALuint GetData(ALubyte *data, ALuint bytes)
692 outBytes = data;
693 outTotal = 0;
694 outLen = bytes;
696 if(initialData.size() > 0)
698 size_t rem = std::min(initialData.size(), (size_t)bytes);
699 memcpy(data, &initialData[0], rem);
700 outTotal += rem;
701 initialData.erase(initialData.begin(), initialData.begin()+rem);
704 while(outTotal < bytes)
706 if(pFLAC__stream_decoder_process_single(flacFile) == false ||
707 pFLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
708 break;
711 return outTotal;
714 virtual bool Rewind()
716 if(pFLAC__stream_decoder_seek_absolute(flacFile, 0) != false)
718 initialData.clear();
719 return true;
722 SetError("Seek failed");
723 return false;
726 flacStream(std::istream *_fstream)
727 : alureStream(_fstream), flacFile(NULL), format(AL_NONE), samplerate(0),
728 blockAlign(0), useFloat(AL_FALSE)
730 if(!flac_handle) return;
732 flacFile = pFLAC__stream_decoder_new();
733 if(flacFile)
735 if(pFLAC__stream_decoder_init_stream(flacFile, ReadCallback, SeekCallback, TellCallback, LengthCallback, EofCallback, WriteCallback, MetadataCallback, ErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK)
737 if(InitFlac())
739 // all ok
740 return;
743 pFLAC__stream_decoder_finish(flacFile);
745 pFLAC__stream_decoder_delete(flacFile);
746 flacFile = NULL;
750 virtual ~flacStream()
752 if(flacFile)
754 pFLAC__stream_decoder_finish(flacFile);
755 pFLAC__stream_decoder_delete(flacFile);
756 flacFile = NULL;
760 private:
761 bool InitFlac()
763 // We need to decode some data to be able to get the channel count, bit
764 // depth, and sample rate. It also ensures the file has FLAC data, as
765 // the FLAC__stream_decoder_init_* functions can succeed on non-FLAC
766 // Ogg files.
767 outLen = 0;
768 outTotal = 0;
769 while(initialData.size() == 0)
771 if(pFLAC__stream_decoder_process_single(flacFile) == false ||
772 pFLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
773 break;
776 if(initialData.size() > 0)
777 return true;
778 return false;
781 static FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder*, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
783 flacStream *self = static_cast<flacStream*>(client_data);
784 ALubyte *data = self->outBytes + self->outTotal;
785 ALuint i = 0;
787 if(self->format == AL_NONE)
789 ALuint bps = frame->header.bits_per_sample;
790 if(bps == 24 || bps == 32)
792 self->format = GetSampleFormat(frame->header.channels, 32, true);
793 if(self->format != AL_NONE)
795 self->useFloat = AL_TRUE;
796 bps = 32;
798 else bps = 16;
800 if(self->format == AL_NONE)
801 self->format = GetSampleFormat(frame->header.channels, bps, false);
802 self->blockAlign = frame->header.channels * bps/8;
803 self->samplerate = frame->header.sample_rate;
806 const ALboolean useFloat = self->useFloat;
807 while(self->outTotal < self->outLen && i < frame->header.blocksize)
809 for(ALuint c = 0;c < frame->header.channels;c++)
811 if(frame->header.bits_per_sample == 8)
812 ((ALubyte*)data)[c] = buffer[c][i]+128;
813 else if(frame->header.bits_per_sample == 16)
814 ((ALshort*)data)[c] = buffer[c][i];
815 else if(frame->header.bits_per_sample == 24)
817 if(useFloat)
818 ((ALfloat*)data)[c] = ((buffer[c][i]>=0) ?
819 buffer[c][i]/(float)0x7FFFFF :
820 buffer[c][i]/(float)0x800000);
821 else
822 ((ALshort*)data)[c] = buffer[c][i]>>8;
824 else if(frame->header.bits_per_sample == 32)
826 if(useFloat)
827 ((ALfloat*)data)[c] = ((buffer[c][i]>=0) ?
828 buffer[c][i]/(float)0x7FFFFFFF :
829 buffer[c][i]/(float)0x80000000u);
830 else
831 ((ALshort*)data)[c] = buffer[c][i]>>16;
834 self->outTotal += self->blockAlign;
835 data += self->blockAlign;
836 i++;
839 if(i < frame->header.blocksize)
841 ALuint blocklen = (frame->header.blocksize-i) *
842 self->blockAlign;
843 ALuint start = self->initialData.size();
845 self->initialData.resize(start+blocklen);
846 data = &self->initialData[start];
848 do {
849 for(ALuint c = 0;c < frame->header.channels;c++)
851 if(frame->header.bits_per_sample == 8)
852 ((ALubyte*)data)[c] = buffer[c][i]+128;
853 else if(frame->header.bits_per_sample == 16)
854 ((ALshort*)data)[c] = buffer[c][i];
855 else if(frame->header.bits_per_sample == 24)
857 if(useFloat)
858 ((ALfloat*)data)[c] = ((buffer[c][i]>=0) ?
859 buffer[c][i]/(float)0x7FFFFF :
860 buffer[c][i]/(float)0x800000);
861 else
862 ((ALshort*)data)[c] = buffer[c][i]>>8;
864 else if(frame->header.bits_per_sample == 32)
866 if(useFloat)
867 ((ALfloat*)data)[c] = ((buffer[c][i]>=0) ?
868 buffer[c][i]/(float)0x7FFFFFFF :
869 buffer[c][i]/(float)0x80000000u);
870 else
871 ((ALshort*)data)[c] = buffer[c][i]>>16;
874 data += self->blockAlign;
875 i++;
876 } while(i < frame->header.blocksize);
879 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
881 static void MetadataCallback(const FLAC__StreamDecoder*,const FLAC__StreamMetadata*,void*)
884 static void ErrorCallback(const FLAC__StreamDecoder*,FLAC__StreamDecoderErrorStatus,void*)
888 static FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t *bytes, void *client_data)
890 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
891 stream->clear();
893 if(*bytes <= 0)
894 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
896 stream->read(reinterpret_cast<char*>(buffer), *bytes);
897 *bytes = stream->gcount();
898 if(*bytes == 0 && stream->eof())
899 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
901 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
903 static FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void *client_data)
905 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
906 stream->clear();
908 if(!stream->seekg(absolute_byte_offset))
909 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
910 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
912 static FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder*, FLAC__uint64 *absolute_byte_offset, void *client_data)
914 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
915 stream->clear();
917 *absolute_byte_offset = stream->tellg();
918 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
920 static FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder*, FLAC__uint64 *stream_length, void *client_data)
922 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
923 stream->clear();
925 std::streampos pos = stream->tellg();
926 if(stream->seekg(0, std::ios_base::end))
928 *stream_length = stream->tellg();
929 stream->seekg(pos);
932 if(!stream->good())
933 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
934 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
936 static FLAC__bool EofCallback(const FLAC__StreamDecoder*, void *client_data)
938 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
939 return (stream->eof()) ? true : false;
942 #else
943 struct flacStream : public nullStream {
944 flacStream(std::istream*){}
946 #endif
949 #ifdef HAS_MPG123
950 struct mp3Stream : public alureStream {
951 mpg123_handle *mp3File;
952 long samplerate;
953 int channels;
954 ALenum format;
956 virtual bool IsValid()
957 { return mp3File != NULL; }
959 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
961 *fmt = format;
962 *frequency = samplerate;
963 *blockalign = channels*2;
964 return true;
967 virtual ALuint GetData(ALubyte *data, ALuint bytes)
969 ALuint amt = 0;
970 while(bytes > 0)
972 size_t got = 0;
973 int ret = pmpg123_read(mp3File, data, bytes, &got);
975 bytes -= got;
976 data += got;
977 amt += got;
979 if(ret == MPG123_NEW_FORMAT)
981 long newrate;
982 int newchans, enc;
983 pmpg123_getformat(mp3File, &newrate, &newchans, &enc);
984 continue;
986 if(ret == MPG123_NEED_MORE)
988 unsigned char data[4096];
989 fstream->read((char*)data, sizeof(data));
990 std::streamsize insize = fstream->gcount();
991 if(insize > 0 && pmpg123_feed(mp3File, data, insize) == MPG123_OK)
992 continue;
994 if(got == 0)
995 break;
997 return amt;
1000 virtual bool Rewind()
1002 fstream->clear();
1003 std::istream::pos_type oldpos = fstream->tellg();
1004 fstream->seekg(0);
1006 mpg123_handle *newFile = pmpg123_new(NULL, NULL);
1007 if(pmpg123_open_feed(newFile) == MPG123_OK)
1009 unsigned char data[4096];
1010 long newrate;
1011 int newchans;
1012 int ret, enc;
1014 ALuint amt, total = 0;
1015 do {
1016 fstream->read((char*)data, sizeof(data));
1017 amt = fstream->gcount();
1018 if(amt == 0) break;
1019 total += amt;
1020 ret = pmpg123_decode(newFile, data, amt, NULL, 0, NULL);
1021 } while(ret == MPG123_NEED_MORE && total < 64*1024);
1023 if(ret == MPG123_NEW_FORMAT &&
1024 pmpg123_getformat(newFile, &newrate, &newchans, &enc) == MPG123_OK)
1026 if(pmpg123_format_none(newFile) == MPG123_OK &&
1027 pmpg123_format(newFile, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
1029 // All OK
1030 pmpg123_delete(mp3File);
1031 mp3File = newFile;
1032 return true;
1035 pmpg123_delete(newFile);
1038 fstream->seekg(oldpos);
1039 SetError("Restart failed");
1040 return false;
1043 mp3Stream(std::istream *_fstream)
1044 : alureStream(_fstream), mp3File(NULL), format(AL_NONE)
1046 if(!mp123_handle) return;
1048 mp3File = pmpg123_new(NULL, NULL);
1049 if(pmpg123_open_feed(mp3File) == MPG123_OK)
1051 unsigned char data[4096];
1052 int ret, enc;
1054 ALuint amt, total = 0;
1055 do {
1056 fstream->read((char*)data, sizeof(data));
1057 amt = fstream->gcount();
1058 if(amt == 0) break;
1059 total += amt;
1060 ret = pmpg123_decode(mp3File, data, amt, NULL, 0, NULL);
1061 } while(ret == MPG123_NEED_MORE && total < 64*1024);
1063 if(ret == MPG123_NEW_FORMAT &&
1064 pmpg123_getformat(mp3File, &samplerate, &channels, &enc) == MPG123_OK)
1066 format = GetSampleFormat(channels, 16, false);
1067 if(pmpg123_format_none(mp3File) == MPG123_OK &&
1068 pmpg123_format(mp3File, samplerate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
1070 // All OK
1071 return;
1075 pmpg123_delete(mp3File);
1076 mp3File = NULL;
1079 virtual ~mp3Stream()
1081 if(mp3File)
1082 pmpg123_delete(mp3File);
1083 mp3File = NULL;
1086 #else
1087 struct mp3Stream : public nullStream {
1088 mp3Stream(std::istream*){}
1090 #endif
1093 #ifdef HAS_DUMB
1094 struct dumbStream : public alureStream {
1095 DUMBFILE_SYSTEM vfs;
1096 DUMBFILE *dumbFile;
1097 DUH *duh;
1098 DUH_SIGRENDERER *renderer;
1099 std::vector<sample_t> sampleBuf;
1100 ALuint lastOrder;
1101 int prevSpeed;
1102 ALenum format;
1104 virtual bool IsValid()
1105 { return renderer != NULL; }
1107 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
1109 if(format == AL_NONE)
1111 format = GetSampleFormat(2, 32, true);
1112 if(format == AL_NONE)
1113 format = AL_FORMAT_STEREO16;
1115 *fmt = format;
1116 *frequency = 65536;
1117 *blockalign = 2 * ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) :
1118 sizeof(ALfloat));
1119 return true;
1122 virtual ALuint GetData(ALubyte *data, ALuint bytes)
1124 ALuint ret = 0;
1126 if(pdumb_it_sr_get_speed(pduh_get_it_sigrenderer(renderer)) == 0)
1127 return 0;
1129 ALuint sample_count = bytes / ((format==AL_FORMAT_STEREO16) ?
1130 sizeof(ALshort) : sizeof(ALfloat));
1132 sampleBuf.resize(sample_count);
1133 sample_t *samples[] = {
1134 &sampleBuf[0]
1137 pdumb_silence(samples[0], sample_count);
1138 ret = pduh_sigrenderer_generate_samples(renderer, 1.0f, 1.0f, sample_count/2, samples);
1139 ret *= 2;
1140 if(format == AL_FORMAT_STEREO16)
1142 for(ALuint i = 0;i < ret;i++)
1143 ((ALshort*)data)[i] = clamp(samples[0][i]>>8, -32768, 32767);
1145 else
1147 for(ALuint i = 0;i < ret;i++)
1148 ((ALfloat*)data)[i] = ((samples[0][i]>=0) ?
1149 samples[0][i]/(float)0x7FFFFF :
1150 samples[0][i]/(float)0x800000);
1152 ret *= ((format==AL_FORMAT_STEREO16) ? sizeof(ALshort) : sizeof(ALfloat));
1154 return ret;
1157 virtual bool Rewind()
1159 if(prevSpeed)
1161 // If a previous speed was recorded, the stream tried to loop. So
1162 // let it loop on a rewind request.
1163 pdumb_it_sr_set_speed(pduh_get_it_sigrenderer(renderer), prevSpeed);
1164 prevSpeed = 0;
1165 return true;
1168 // Else, no loop point. Restart from scratch.
1169 DUH_SIGRENDERER *newrenderer = pdumb_it_start_at_order(duh, 2, lastOrder);
1170 if(!newrenderer)
1172 SetError("Could start renderer");
1173 return false;
1175 pduh_end_sigrenderer(renderer);
1176 renderer = newrenderer;
1177 return true;
1180 virtual bool SetOrder(ALuint order)
1182 DUH_SIGRENDERER *newrenderer = pdumb_it_start_at_order(duh, 2, order);
1183 if(!newrenderer)
1185 SetError("Could not set order");
1186 return false;
1188 pduh_end_sigrenderer(renderer);
1189 renderer = newrenderer;
1191 lastOrder = order;
1192 return true;
1195 dumbStream(std::istream *_fstream)
1196 : alureStream(_fstream), dumbFile(NULL), duh(NULL), renderer(NULL),
1197 lastOrder(0), prevSpeed(0), format(AL_NONE)
1199 if(!dumb_handle) return;
1201 DUH* (*funcs[])(DUMBFILE*) = {
1202 pdumb_read_it,
1203 pdumb_read_xm,
1204 pdumb_read_s3m,
1205 pdumb_read_mod,
1206 NULL
1209 vfs.open = NULL;
1210 vfs.skip = skip;
1211 vfs.getc = read_char;
1212 vfs.getnc = read;
1213 vfs.close = NULL;
1215 for(size_t i = 0;funcs[i];i++)
1217 dumbFile = pdumbfile_open_ex(this, &vfs);
1218 if(dumbFile)
1220 duh = funcs[i](dumbFile);
1221 if(duh)
1223 renderer = pdumb_it_start_at_order(duh, 2, lastOrder);
1224 if(renderer)
1226 pdumb_it_set_loop_callback(pduh_get_it_sigrenderer(renderer), loop_cb, this);
1227 break;
1230 punload_duh(duh);
1231 duh = NULL;
1234 pdumbfile_close(dumbFile);
1235 dumbFile = NULL;
1237 fstream->clear();
1238 fstream->seekg(0);
1242 virtual ~dumbStream()
1244 if(renderer)
1245 pduh_end_sigrenderer(renderer);
1246 renderer = NULL;
1248 if(duh)
1249 punload_duh(duh);
1250 duh = NULL;
1252 if(dumbFile)
1253 pdumbfile_close(dumbFile);
1254 dumbFile = NULL;
1257 private:
1258 // DUMBFILE iostream callbacks
1259 static int skip(void *user_data, long offset)
1261 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
1262 stream->clear();
1264 if(stream->seekg(offset, std::ios_base::cur))
1265 return 0;
1266 return -1;
1269 static long read(char *ptr, long size, void *user_data)
1271 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
1272 stream->clear();
1274 stream->read(ptr, size);
1275 return stream->gcount();
1278 static int read_char(void *user_data)
1280 std::istream *stream = static_cast<dumbStream*>(user_data)->fstream;
1281 stream->clear();
1283 unsigned char ret;
1284 stream->read(reinterpret_cast<char*>(&ret), 1);
1285 if(stream->gcount() > 0)
1286 return ret;
1287 return -1;
1290 static int loop_cb(void *user_data)
1292 dumbStream *self = static_cast<dumbStream*>(user_data);
1293 self->prevSpeed = pdumb_it_sr_get_speed(pduh_get_it_sigrenderer(self->renderer));
1294 pdumb_it_sr_set_speed(pduh_get_it_sigrenderer(self->renderer), 0);
1295 return 0;
1298 #else
1299 struct dumbStream : public nullStream {
1300 dumbStream(std::istream*){}
1302 #endif
1305 #ifdef HAS_TIMIDITY
1306 struct midiStream : public alureStream {
1307 #ifdef _WIN32
1308 HANDLE pcmFile;
1309 HANDLE cpid;
1310 #else
1311 #define INVALID_HANDLE_VALUE (-1)
1312 int pcmFile;
1313 pid_t cpid;
1314 #endif
1315 ALCint Freq;
1317 virtual bool IsValid()
1318 { return cpid != INVALID_HANDLE_VALUE; }
1320 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
1322 *fmt = AL_FORMAT_STEREO16;
1323 *frequency = Freq;
1324 *blockalign = 4;
1325 return true;
1328 virtual ALuint GetData(ALubyte *data, ALuint bytes)
1330 ALuint total = 0;
1331 while(bytes > 0)
1333 #ifdef _WIN32
1334 DWORD got = 0;
1335 if(!ReadFile(pcmFile, data, bytes, &got, NULL))
1336 got = 0;
1337 #else
1338 ssize_t got;
1339 while((got=read(pcmFile, &data[total], bytes)) == -1 && errno == EINTR)
1341 #endif
1342 if(got <= 0)
1343 break;
1344 bytes -= got;
1345 total += got;
1348 if(BigEndian)
1350 for(ALuint i = 0;i < total;i+=2)
1351 swap(data[i], data[i+1]);
1354 return total;
1357 virtual bool Rewind()
1359 fstream->clear();
1360 fstream->seekg(0);
1362 #ifdef _WIN32
1363 HANDLE _pcmFile, _cpid;
1364 if(!StartStream(_pcmFile, _cpid))
1366 SetError("Failed to restart timidity");
1367 return false;
1370 TerminateProcess(cpid, 0);
1371 CloseHandle(cpid);
1372 cpid = _cpid;
1374 CloseHandle(pcmFile);
1375 pcmFile = _pcmFile;
1376 #else
1377 int _pcmFile; pid_t _cpid;
1378 if(!StartStream(_pcmFile, _cpid))
1380 SetError("Failed to restart timidity");
1381 return false;
1384 kill(cpid, SIGTERM);
1385 waitpid(cpid, NULL, 0);
1386 cpid = _cpid;
1388 close(pcmFile);
1389 pcmFile = _pcmFile;
1390 #endif
1392 return true;
1395 midiStream(std::istream *_fstream)
1396 : alureStream(_fstream), pcmFile(INVALID_HANDLE_VALUE),
1397 cpid(INVALID_HANDLE_VALUE), Freq(44100)
1399 ALCcontext *ctx = alcGetCurrentContext();
1400 ALCdevice *dev = alcGetContextsDevice(ctx);
1401 alcGetIntegerv(dev, ALC_FREQUENCY, 1, &Freq);
1403 StartStream(pcmFile, cpid);
1406 virtual ~midiStream()
1408 if(cpid != INVALID_HANDLE_VALUE)
1410 #ifdef _WIN32
1411 TerminateProcess(cpid, 0);
1412 CloseHandle(cpid);
1413 #else
1414 kill(cpid, SIGTERM);
1415 waitpid(cpid, NULL, 0);
1416 #endif
1417 cpid = INVALID_HANDLE_VALUE;
1420 if(pcmFile != INVALID_HANDLE_VALUE)
1422 #ifdef _WIN32
1423 CloseHandle(pcmFile);
1424 #else
1425 close(pcmFile);
1426 #endif
1427 pcmFile = INVALID_HANDLE_VALUE;
1431 private:
1432 #ifdef _WIN32
1433 bool StartStream(HANDLE &pcmFile, HANDLE &cpid)
1434 #else
1435 bool StartStream(int &pcmFile, pid_t &cpid)
1436 #endif
1438 char hdr[4];
1439 std::vector<ALubyte> midiData;
1441 fstream->read(hdr, sizeof(hdr));
1442 if(fstream->gcount() != sizeof(hdr))
1443 return false;
1445 if(memcmp(hdr, "MThd", 4) == 0)
1447 char ch;
1448 for(size_t i = 0;i < sizeof(hdr);i++)
1449 midiData.push_back(hdr[i]);
1450 while(fstream->get(ch))
1451 midiData.push_back(ch);
1453 else if(memcmp(hdr, "MUS\x1a", sizeof(hdr)) == 0)
1455 if(!ConvertMUS(midiData))
1456 return false;
1458 else
1459 return false;
1461 #ifdef _WIN32
1462 SECURITY_ATTRIBUTES attr;
1463 attr.nLength = sizeof(attr);
1464 attr.bInheritHandle = TRUE;
1465 attr.lpSecurityDescriptor = NULL;
1467 HANDLE midPipe[2], pcmPipe[2];
1468 if(!CreatePipe(&midPipe[0], &midPipe[1], &attr, 0))
1469 return false;
1470 if(!CreatePipe(&pcmPipe[0], &pcmPipe[1], &attr, 0))
1472 CloseHandle(midPipe[0]);
1473 CloseHandle(midPipe[1]);
1474 return false;
1477 PROCESS_INFORMATION procInfo;
1478 memset(&procInfo, 0, sizeof(procInfo));
1480 STARTUPINFO startInfo;
1481 memset(&startInfo, 0, sizeof(startInfo));
1482 startInfo.cb = sizeof(startInfo);
1483 startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1484 startInfo.hStdOutput = pcmPipe[1];
1485 startInfo.hStdInput = midPipe[0];
1486 startInfo.dwFlags |= STARTF_USESTDHANDLES;
1488 std::stringstream cmdstr;
1489 cmdstr << "timidity - -idqq -Ow1sl -o - -s " << Freq;
1490 std::string cmdline = cmdstr.str();
1492 if(!CreateProcessA(NULL, const_cast<CHAR*>(cmdline.c_str()), NULL,
1493 NULL, TRUE, 0, NULL, NULL, &startInfo, &procInfo))
1495 CloseHandle(midPipe[0]);
1496 CloseHandle(midPipe[1]);
1497 CloseHandle(pcmPipe[0]);
1498 CloseHandle(pcmPipe[1]);
1499 return false;
1502 CloseHandle(midPipe[0]);
1503 CloseHandle(pcmPipe[1]);
1505 CloseHandle(procInfo.hThread);
1506 HANDLE pid = procInfo.hProcess;
1508 ALubyte *cur = &midiData[0];
1509 size_t rem = midiData.size();
1510 do {
1511 DWORD wrote;
1512 if(!WriteFile(midPipe[1], cur, rem, &wrote, NULL) ||
1513 wrote <= 0)
1514 break;
1515 cur += wrote;
1516 rem -= wrote;
1517 } while(rem > 0);
1518 CloseHandle(midPipe[1]); midPipe[1] = INVALID_HANDLE_VALUE;
1520 ALubyte fmthdr[44];
1521 cur = fmthdr;
1522 rem = sizeof(fmthdr);
1523 do {
1524 DWORD got;
1525 if(!ReadFile(pcmPipe[0], cur, rem, &got, NULL) ||
1526 got <= 0)
1527 break;
1528 cur += got;
1529 rem -= got;
1530 } while(rem > 0);
1531 if(rem > 0)
1533 TerminateProcess(pid, 0);
1534 CloseHandle(pid);
1535 CloseHandle(pcmPipe[0]);
1536 return false;
1538 #else
1539 int midPipe[2], pcmPipe[2];
1540 if(pipe(midPipe) == -1)
1541 return false;
1542 if(pipe(pcmPipe) == -1)
1544 close(midPipe[0]);
1545 close(midPipe[1]);
1546 return false;
1549 pid_t pid = fork();
1550 if(pid < 0)
1552 close(midPipe[0]);
1553 close(midPipe[1]);
1554 close(pcmPipe[0]);
1555 close(pcmPipe[1]);
1556 return false;
1559 if(pid == 0)
1561 if(dup2(midPipe[0], STDIN_FILENO) != -1 &&
1562 dup2(pcmPipe[1], STDOUT_FILENO) != -1)
1564 close(midPipe[0]);
1565 close(midPipe[1]);
1566 close(pcmPipe[0]);
1567 close(pcmPipe[1]);
1569 std::stringstream freqstr;
1570 freqstr << Freq;
1572 execlp("timidity","timidity","-","-idqq","-Ow1sl","-o","-",
1573 "-s", freqstr.str().c_str(), NULL);
1575 _exit(1);
1578 close(midPipe[0]); midPipe[0] = -1;
1579 close(pcmPipe[1]); pcmPipe[1] = -1;
1581 void (*oldhandler)(int) = signal(SIGPIPE, SIG_IGN);
1582 ALubyte *cur = &midiData[0];
1583 size_t rem = midiData.size();
1584 do {
1585 ssize_t wrote;
1586 while((wrote=write(midPipe[1], cur, rem)) == -1 && errno == EINTR)
1588 if(wrote <= 0)
1589 break;
1590 cur += wrote;
1591 rem -= wrote;
1592 } while(rem > 0);
1593 close(midPipe[1]); midPipe[1] = -1;
1594 signal(SIGPIPE, oldhandler);
1596 ALubyte fmthdr[44];
1597 cur = fmthdr;
1598 rem = sizeof(fmthdr);
1599 do {
1600 ssize_t got;
1601 while((got=read(pcmPipe[0], cur, rem)) == -1 && errno == EINTR)
1603 if(got <= 0)
1604 break;
1605 cur += got;
1606 rem -= got;
1607 } while(rem > 0);
1608 if(rem > 0)
1610 kill(pid, SIGTERM);
1611 waitpid(pid, NULL, 0);
1612 close(pcmPipe[0]);
1613 return false;
1615 #endif
1617 pcmFile = pcmPipe[0];
1618 cpid = pid;
1619 return true;
1622 alureUInt64 ReadVarLen()
1624 alureUInt64 val = 0;
1625 char ch;
1627 do {
1628 if(!fstream->get(ch))
1629 break;
1630 val = (val<<7) | (ch&0x7f);
1631 } while((ch&0x80));
1633 return val;
1636 void WriteVarLen(std::vector<ALubyte> &out, alureUInt64 val)
1638 alureUInt64 buffer = val&0x7f;
1639 while((val>>=7) > 0)
1640 buffer = (buffer<<8) | 0x80 | (val&0x7f);
1641 while(1)
1643 out.push_back(buffer&0xff);
1644 if(!(buffer&0x80))
1645 break;
1646 buffer >>= 8;
1650 static const ALubyte MIDI_SYSEX = 0xF0; // SysEx begin
1651 static const ALubyte MIDI_SYSEXEND = 0xF7; // SysEx end
1652 static const ALubyte MIDI_META = 0xFF; // Meta event begin
1653 static const ALubyte MIDI_META_TEMPO = 0x51;
1654 static const ALubyte MIDI_META_EOT = 0x2F; // End-of-track
1655 static const ALubyte MIDI_META_SSPEC = 0x7F; // System-specific event
1657 static const ALubyte MIDI_NOTEOFF = 0x80; // + note + velocity
1658 static const ALubyte MIDI_NOTEON = 0x90; // + note + velocity
1659 static const ALubyte MIDI_POLYPRESS = 0xA0; // + pressure (2 bytes)
1660 static const ALubyte MIDI_CTRLCHANGE = 0xB0; // + ctrlr + value
1661 static const ALubyte MIDI_PRGMCHANGE = 0xC0; // + new patch
1662 static const ALubyte MIDI_CHANPRESS = 0xD0; // + pressure (1 byte)
1663 static const ALubyte MIDI_PITCHBEND = 0xE0; // + pitch bend (2 bytes)
1665 static const ALubyte MUS_EVENT_CHANNEL_MASK = 0x0F;
1666 static const ALubyte MUS_EVENT_DELTA_MASK = 0x80;
1668 static const ALubyte MUS_NOTEOFF = 0x00;
1669 static const ALubyte MUS_NOTEON = 0x10;
1670 static const ALubyte MUS_PITCHBEND = 0x20;
1671 static const ALubyte MUS_SYSEVENT = 0x30;
1672 static const ALubyte MUS_CTRLCHANGE = 0x40;
1673 static const ALubyte MUS_SCOREEND = 0x60;
1675 bool ConvertMUS(std::vector<ALubyte> &midiData)
1677 static const ALubyte CtrlTranslate[15] = {
1678 0, // program change
1679 0, // bank select
1680 1, // modulation pot
1681 7, // volume
1682 10, // pan pot
1683 11, // expression pot
1684 91, // reverb depth
1685 93, // chorus depth
1686 64, // sustain pedal
1687 67, // soft pedal
1688 120, // all sounds off
1689 123, // all notes off
1690 126, // mono
1691 127, // poly
1692 121 // reset all controllers
1695 static const ALubyte MIDIhead[22] = {
1696 'M','T','h','d', 0, 0, 0, 6,
1697 0, 0, // format 0: only one track
1698 0, 1, // yes, there is really only one track
1699 0, 70, // 70 divisions
1700 'M','T','r','k', 0xFF, 0xFF, 0xFF, 0xFF
1703 // The MUS\x1a ID was already read and verified
1704 ALushort songLen = read_le16(fstream);
1705 ALushort songStart = read_le16(fstream);
1706 ALushort numChans = read_le16(fstream);
1708 // Sanity check the MUS file's channel count
1709 if(numChans > 15)
1710 return false;
1712 fstream->seekg(songStart);
1713 std::streamsize maxmus_p = songLen;
1714 maxmus_p += fstream->tellg();
1716 ALubyte chanVel[16];
1717 for(size_t i = 0;i < 16;i++)
1718 chanVel[i] = 100;
1720 bool firstUse[16];
1721 for(size_t i = 0;i < 16;i++)
1722 firstUse[i] = true;
1724 alureUInt64 deltaTime = 0;
1725 ALubyte event = 0;
1726 ALubyte status = 0;
1728 // Setup header
1729 for(size_t i = 0;i < sizeof(MIDIhead);i++)
1730 midiData.push_back(MIDIhead[i]);
1732 // The first event sets the tempo to 500,000 microsec/quarter note
1733 midiData.push_back(0);
1734 midiData.push_back(MIDI_META | 0);
1735 midiData.push_back(MIDI_META_TEMPO | 0);
1736 midiData.push_back(3);
1737 midiData.push_back(0x07);
1738 midiData.push_back(0xA1);
1739 midiData.push_back(0x20);
1741 while(fstream->good() && fstream->tellg() < maxmus_p && event != MUS_SCOREEND)
1743 event = fstream->get();
1745 bool hasDelta = event&MUS_EVENT_DELTA_MASK;
1746 ALubyte channel = event&MUS_EVENT_CHANNEL_MASK;
1748 event &= ~MUS_EVENT_DELTA_MASK;
1749 event &= ~MUS_EVENT_CHANNEL_MASK;
1751 // Convert percussion channel (MUS #15 -> MIDI #9)
1752 if(channel == 15)
1753 channel = 9;
1754 else if(channel >= 9)
1755 channel++;
1757 if(firstUse[channel])
1759 // This is the first time this channel has been used,
1760 // so sets its volume to 127.
1761 firstUse[channel] = false;
1762 midiData.push_back(0);
1763 midiData.push_back(MIDI_CTRLCHANGE | channel);
1764 midiData.push_back(7);
1765 midiData.push_back(127);
1768 ALubyte t = 0;
1769 if(event != MUS_SCOREEND)
1770 t = fstream->get();
1772 ALubyte midArgs = 2;
1773 ALubyte midStatus = channel;
1774 ALubyte mid1 = 0, mid2 = 0;
1775 bool noop = false;
1777 switch(event)
1779 case MUS_NOTEOFF:
1780 midStatus |= MIDI_NOTEOFF;
1781 mid1 = t&0x7f;
1782 mid2 = 64;
1783 break;
1785 case MUS_NOTEON:
1786 midStatus |= MIDI_NOTEON;
1787 mid1 = t&0x7f;
1788 if((t&0x80))
1789 chanVel[channel] = fstream->get()&0x7f;
1790 mid2 = chanVel[channel];
1791 break;
1793 case MUS_PITCHBEND:
1794 midStatus |= MIDI_PITCHBEND;
1795 mid1 = (t&1) << 6;
1796 mid2 = (t>>1) & 0x7f;
1797 break;
1799 case MUS_SYSEVENT:
1800 if(t < 10 || t > 14)
1801 noop = true;
1802 else
1804 midStatus |= MIDI_CTRLCHANGE;
1805 mid1 = CtrlTranslate[t];
1806 mid2 = ((t==12) /* Mono */ ? numChans : 0);
1808 break;
1810 case MUS_CTRLCHANGE:
1811 if(t == 0)
1813 // Program change, only one arg
1814 midArgs = 1;
1815 midStatus |= MIDI_PRGMCHANGE;
1816 mid1 = fstream->get()&0x7f;
1818 else if(t < 10)
1820 midStatus |= MIDI_CTRLCHANGE;
1821 mid1 = CtrlTranslate[t];
1822 mid2 = fstream->get();
1824 else
1825 noop = true;
1826 break;
1828 case MUS_SCOREEND:
1829 midStatus = MIDI_META;
1830 mid1 = MIDI_META_EOT;
1831 mid2 = 0;
1832 break;
1834 default:
1835 return false;
1838 if(noop)
1840 // A system-specific event with no data is a no-op.
1841 midStatus = MIDI_META;
1842 mid1 = MIDI_META_SSPEC;
1843 mid2 = 0;
1846 WriteVarLen(midiData, deltaTime);
1847 if(midStatus != status)
1849 status = midStatus;
1850 midiData.push_back(status);
1852 if(midArgs >= 1)
1853 midiData.push_back(mid1);
1854 if(midArgs >= 2)
1855 midiData.push_back(mid2);
1857 deltaTime = (hasDelta ? ReadVarLen() : 0);
1860 // If reading failed or we overran the song length, the song is bad
1861 if(!fstream->good() || fstream->tellg() > maxmus_p)
1862 return false;
1864 // Fill in track length
1865 size_t trackLen = midiData.size() - 22;
1866 midiData[18] = (trackLen>>24) & 0xff;
1867 midiData[19] = (trackLen>>16) & 0xff;
1868 midiData[20] = (trackLen>>8) & 0xff;
1869 midiData[21] = trackLen&0xff;
1870 return true;
1873 #else
1874 struct midiStream : public nullStream {
1875 midiStream(std::istream*){}
1877 #endif
1880 template <typename T>
1881 alureStream *get_stream_decoder(const T &fdata)
1883 alureStream *stream;
1885 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.begin();
1886 while(i != InstalledCallbacks.end() && i->first < 0)
1888 stream = new customStream(fdata, i->second);
1889 if(stream->IsValid())
1890 return stream;
1891 delete stream;
1892 i++;
1895 std::istream *file = new InStream(fdata);
1896 if(!file->fail())
1898 stream = new wavStream(file);
1899 if(stream->IsValid())
1900 return stream;
1901 delete stream;
1903 file->clear();
1904 file->seekg(0, std::ios_base::beg);
1905 stream = new aiffStream(file);
1906 if(stream->IsValid())
1907 return stream;
1908 delete stream;
1910 // Try libVorbisFile
1911 file->clear();
1912 file->seekg(0, std::ios_base::beg);
1913 stream = new oggStream(file);
1914 if(stream->IsValid())
1915 return stream;
1916 delete stream;
1918 // Try libFLAC
1919 file->clear();
1920 file->seekg(0, std::ios_base::beg);
1921 stream = new flacStream(file);
1922 if(stream->IsValid())
1923 return stream;
1924 delete stream;
1926 // Try DUMB
1927 file->clear();
1928 file->seekg(0, std::ios_base::beg);
1929 stream = new dumbStream(file);
1930 if(stream->IsValid())
1931 return stream;
1932 delete stream;
1934 // Try libSndFile
1935 file->clear();
1936 file->seekg(0, std::ios_base::beg);
1937 stream = new sndStream(file);
1938 if(stream->IsValid())
1939 return stream;
1940 delete stream;
1942 // Try MPG123
1943 file->clear();
1944 file->seekg(0, std::ios_base::beg);
1945 stream = new mp3Stream(file);
1946 if(stream->IsValid())
1947 return stream;
1948 delete stream;
1950 // Try Timidity
1951 file->clear();
1952 file->seekg(0, std::ios_base::beg);
1953 stream = new midiStream(file);
1954 if(stream->IsValid())
1955 return stream;
1956 delete stream;
1958 SetError("Unsupported type");
1959 delete file;
1961 else
1963 SetError("Failed to open file");
1964 delete file;
1967 while(i != InstalledCallbacks.end())
1969 stream = new customStream(fdata, i->second);
1970 if(stream->IsValid())
1971 return stream;
1972 delete stream;
1973 i++;
1976 return new nullStream;
1979 alureStream *create_stream(const char *fname)
1980 { return get_stream_decoder(fname); }
1981 alureStream *create_stream(const MemDataInfo &memData)
1982 { return get_stream_decoder(memData); }
1984 alureStream *create_stream(ALvoid *userdata, ALenum format, ALuint rate, const UserCallbacks &cb)
1985 { return new customStream(userdata, format, rate, cb); }