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
{
46 static void Init() { }
47 static void Deinit() { }
49 virtual bool IsValid()
50 { return (dataStart
> 0 && format
!= AL_NONE
); }
52 virtual bool GetFormat(ALenum
*fmt
, ALuint
*frequency
, ALuint
*blockalign
)
55 *frequency
= samplerate
;
56 *blockalign
= blockAlign
;
60 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
62 std::streamsize rem
= ((remLen
>= bytes
) ? bytes
: remLen
) / blockAlign
;
63 fstream
->read(reinterpret_cast<char*>(data
), rem
*blockAlign
);
65 std::streamsize got
= fstream
->gcount();
66 got
-= got
%blockAlign
;
69 if(BigEndian
&& sampleSize
== 16)
71 for(std::streamsize i
= 0;i
< got
;i
+=2)
72 swap(data
[i
], data
[i
+1]);
74 else if(BigEndian
&& sampleSize
== 32)
76 for(std::streamsize i
= 0;i
< got
;i
+=4)
78 swap(data
[i
+0], data
[i
+3]);
79 swap(data
[i
+1], data
[i
+2]);
82 else if(BigEndian
&& sampleSize
== 64)
84 for(std::streamsize i
= 0;i
< got
;i
+=8)
86 swap(data
[i
+0], data
[i
+7]);
87 swap(data
[i
+1], data
[i
+6]);
88 swap(data
[i
+2], data
[i
+5]);
89 swap(data
[i
+3], data
[i
+4]);
99 if(fstream
->seekg(dataStart
))
105 SetError("Seek failed");
109 virtual alureInt64
GetLength()
111 alureInt64 ret
= dataLen
;
112 return ret
/ channels
* 8 / sampleSize
;
115 wavStream(std::istream
*_fstream
)
116 : alureStream(_fstream
), format(0), dataStart(0)
121 if(!fstream
->read(reinterpret_cast<char*>(buffer
), 12) ||
122 memcmp(buffer
, "RIFF", 4) != 0 || memcmp(buffer
+8, "WAVE", 4) != 0)
125 while(!dataStart
|| format
== AL_NONE
)
128 if(!fstream
->read(tag
, 4))
131 /* read chunk length */
132 length
= read_le32(fstream
);
134 if(memcmp(tag
, "fmt ", 4) == 0 && length
>= 16)
136 /* Data type (should be 1 for PCM data, 3 for float PCM data,
137 * 7 for muLaw, and 17 for IMA4 data) */
138 int type
= read_le16(fstream
);
139 if(type
!= 0x0001 && type
!= 0x0003 && type
!= 0x0007 &&
143 /* mono or stereo data */
144 channels
= read_le16(fstream
);
146 /* sample frequency */
147 samplerate
= read_le32(fstream
);
149 /* skip average bytes per second */
152 /* bytes per block */
153 blockAlign
= read_le16(fstream
);
157 /* bits per sample */
158 sampleSize
= read_le16(fstream
);
162 /* Look for any extra data and try to find the format */
163 ALuint extrabytes
= 0;
166 extrabytes
= read_le16(fstream
);
169 extrabytes
= std::min
<ALuint
>(extrabytes
, length
);
172 format
= GetSampleFormat(channels
, sampleSize
, false);
173 else if(type
== 0x0003)
174 format
= GetSampleFormat(channels
, sampleSize
, true);
175 else if(type
== 0x0007)
180 format
= AL_FORMAT_MONO_MULAW
;
181 else if(channels
== 2)
182 format
= AL_FORMAT_STEREO_MULAW
;
183 else if(channels
== 4)
184 format
= AL_FORMAT_QUAD_MULAW
;
185 else if(channels
== 6)
186 format
= AL_FORMAT_51CHN_MULAW
;
187 else if(channels
== 7)
188 format
= AL_FORMAT_61CHN_MULAW
;
189 else if(channels
== 8)
190 format
= AL_FORMAT_71CHN_MULAW
;
193 else if(type
== 0x0011 && extrabytes
>= 2)
195 int samples
= read_le16(fstream
);
198 /* AL_EXT_IMA4 only supports 36 bytes-per-channel block
199 * alignment, which has 65 uncompressed sample frames */
200 if(blockAlign
== 36*channels
&& samples
== 65*channels
&&
201 alIsExtensionPresent("AL_EXT_IMA4"))
204 format
= AL_FORMAT_MONO_IMA4
;
205 else if(channels
== 2)
206 format
= AL_FORMAT_STEREO_IMA4
;
210 else if(memcmp(tag
, "data", 4) == 0)
212 dataStart
= fstream
->tellg();
213 dataLen
= remLen
= length
;
216 fstream
->seekg(length
, std::ios_base::cur
);
219 if(dataStart
> 0 && format
!= AL_NONE
)
220 fstream
->seekg(dataStart
);
226 // Priority = 10, prefer this decoder over external ones
227 static DecoderDecl
<wavStream
,10> wavStream_decoder
;
228 Decoder
&alure_init_wav(void)
229 { return wavStream_decoder
; }