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; }