2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
34 struct wavStream
: public alureStream
{
45 static void Init() { }
46 static void Deinit() { }
48 virtual bool IsValid()
49 { return (dataStart
> 0 && format
!= AL_NONE
); }
51 virtual bool GetFormat(ALenum
*fmt
, ALuint
*frequency
, ALuint
*blockalign
)
54 *frequency
= samplerate
;
55 *blockalign
= blockAlign
;
59 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
61 std::streamsize rem
= ((remLen
>= bytes
) ? bytes
: remLen
) / blockAlign
;
62 fstream
->read(reinterpret_cast<char*>(data
), rem
*blockAlign
);
64 std::streamsize got
= fstream
->gcount();
65 got
-= got
%blockAlign
;
68 if(BigEndian
&& sampleSize
== 16)
70 for(std::streamsize i
= 0;i
< got
;i
+=2)
71 swap(data
[i
], data
[i
+1]);
73 else if(BigEndian
&& sampleSize
== 32)
75 for(std::streamsize i
= 0;i
< got
;i
+=4)
77 swap(data
[i
+0], data
[i
+3]);
78 swap(data
[i
+1], data
[i
+2]);
81 else if(BigEndian
&& sampleSize
== 64)
83 for(std::streamsize i
= 0;i
< got
;i
+=8)
85 swap(data
[i
+0], data
[i
+7]);
86 swap(data
[i
+1], data
[i
+6]);
87 swap(data
[i
+2], data
[i
+5]);
88 swap(data
[i
+3], data
[i
+4]);
98 if(fstream
->seekg(dataStart
))
104 SetError("Seek failed");
108 wavStream(std::istream
*_fstream
)
109 : alureStream(_fstream
), format(0), dataStart(0)
114 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
115 memcmp(buffer
, "RIFF", 4) != 0 || memcmp(buffer
+8, "WAVE", 4) != 0)
118 while(!dataStart
|| format
== AL_NONE
)
121 if(!fstream
->read(tag
, 4))
124 /* read chunk length */
125 length
= read_le32(fstream
);
127 if(memcmp(tag
, "fmt ", 4) == 0 && length
>= 16)
129 /* Data type (should be 1 for PCM data, 3 for float PCM data,
130 * 7 for muLaw, and 17 for IMA4 data) */
131 int type
= read_le16(fstream
);
132 if(type
!= 0x0001 && type
!= 0x0003 && type
!= 0x0007 &&
136 /* mono or stereo data */
137 int channels
= read_le16(fstream
);
139 /* sample frequency */
140 samplerate
= read_le32(fstream
);
142 /* skip average bytes per second */
145 /* bytes per block */
146 blockAlign
= read_le16(fstream
);
150 /* bits per sample */
151 sampleSize
= read_le16(fstream
);
155 /* Look for any extra data and try to find the format */
156 ALuint extrabytes
= 0;
159 extrabytes
= read_le16(fstream
);
162 extrabytes
= std::min
<ALuint
>(extrabytes
, length
);
165 format
= GetSampleFormat(channels
, sampleSize
, false);
166 else if(type
== 0x0003)
167 format
= GetSampleFormat(channels
, sampleSize
, true);
168 else if(type
== 0x0007)
173 format
= AL_FORMAT_MONO_MULAW
;
174 else if(channels
== 2)
175 format
= AL_FORMAT_STEREO_MULAW
;
176 else if(channels
== 4)
177 format
= AL_FORMAT_QUAD_MULAW
;
178 else if(channels
== 6)
179 format
= AL_FORMAT_51CHN_MULAW
;
180 else if(channels
== 7)
181 format
= AL_FORMAT_61CHN_MULAW
;
182 else if(channels
== 8)
183 format
= AL_FORMAT_71CHN_MULAW
;
186 else if(type
== 0x0011 && extrabytes
>= 2)
188 int samples
= read_le16(fstream
);
191 /* AL_EXT_IMA4 only supports 36 bytes-per-channel block
192 * alignment, which has 65 uncompressed sample frames */
193 if(blockAlign
== 36*channels
&& samples
== 65*channels
&&
194 alIsExtensionPresent("AL_EXT_IMA4"))
197 format
= AL_FORMAT_MONO_IMA4
;
198 else if(channels
== 2)
199 format
= AL_FORMAT_STEREO_IMA4
;
203 else if(memcmp(tag
, "data", 4) == 0)
205 dataStart
= fstream
->tellg();
206 dataLen
= remLen
= length
;
209 fstream
->seekg(length
, std::ios_base::cur
);
212 if(dataStart
> 0 && format
!= AL_NONE
)
213 fstream
->seekg(dataStart
);
219 // Priority = 10, prefer this decoder over external ones
220 static DecoderDecl
<wavStream
,10> wavStream_decoder
;
221 Decoder
&alure_init_wav(void)
222 { return wavStream_decoder
; }