Get it rid of an unused macro
[alure.git] / src / codec_wav.cpp
blob6849abcbddfc45e9a271bb4fd929f50bc34ae50c
1 /*
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
21 * IN THE SOFTWARE.
24 #include "config.h"
26 #include "main.h"
28 #include <string.h>
29 #include <assert.h>
31 #include <istream>
34 struct wavStream : public alureStream {
35 private:
36 ALenum format;
37 int samplerate;
38 int blockAlign;
39 int sampleSize;
40 long dataStart;
41 long dataLen;
42 size_t remLen;
44 public:
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)
53 *fmt = format;
54 *frequency = samplerate;
55 *blockalign = blockAlign;
56 return true;
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;
66 remLen -= got;
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]);
92 return got;
95 virtual bool Rewind()
97 fstream->clear();
98 if(fstream->seekg(dataStart))
100 remLen = dataLen;
101 return true;
104 SetError("Seek failed");
105 return false;
108 wavStream(std::istream *_fstream)
109 : alureStream(_fstream), format(0), dataStart(0)
111 ALubyte buffer[25];
112 ALuint length;
114 if(!fstream->read(reinterpret_cast<char*>(buffer), 12) ||
115 memcmp(buffer, "RIFF", 4) != 0 || memcmp(buffer+8, "WAVE", 4) != 0)
116 return;
118 while(!dataStart || format == AL_NONE)
120 char tag[4];
121 if(!fstream->read(tag, 4))
122 break;
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 &&
133 type != 0x0011)
134 break;
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 */
143 fstream->ignore(4);
145 /* bytes per block */
146 blockAlign = read_le16(fstream);
147 if(blockAlign == 0)
148 break;
150 /* bits per sample */
151 sampleSize = read_le16(fstream);
153 length -= 16;
155 /* Look for any extra data and try to find the format */
156 ALuint extrabytes = 0;
157 if(length >= 2)
159 extrabytes = read_le16(fstream);
160 length -= 2;
162 extrabytes = std::min<ALuint>(extrabytes, length);
164 if(type == 0x0001)
165 format = GetSampleFormat(channels, sampleSize, false);
166 else if(type == 0x0003)
167 format = GetSampleFormat(channels, sampleSize, true);
168 else if(type == 0x0007)
170 if(sampleSize == 8)
172 if(channels == 1)
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);
189 length -= 2;
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"))
196 if(channels == 1)
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);
216 virtual ~wavStream()
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; }