4 * Copyright (c) 2011 by Chris Robinson <chris.kcat@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 /* This file contains routines to help with some menial OpenAL-related tasks,
26 * such as opening a device and setting up a context, closing the device and
27 * destroying its context, converting between frame counts and byte lengths,
28 * finding an appropriate buffer format, and getting readable strings for
29 * channel configs and sample types. */
37 #include "alhelpers.h"
40 /* InitAL opens the default device and sets up a context using default
41 * attributes, making the program ready to call OpenAL functions. */
47 /* Open and initialize a device with default settings */
48 device
= alcOpenDevice(NULL
);
51 fprintf(stderr
, "Could not open a device!\n");
55 ctx
= alcCreateContext(device
, NULL
);
56 if(ctx
== NULL
|| alcMakeContextCurrent(ctx
) == ALC_FALSE
)
59 alcDestroyContext(ctx
);
60 alcCloseDevice(device
);
61 fprintf(stderr
, "Could not set a context!\n");
65 printf("Opened \"%s\"\n", alcGetString(device
, ALC_DEVICE_SPECIFIER
));
69 /* CloseAL closes the device belonging to the current context, and destroys the
76 ctx
= alcGetCurrentContext();
80 device
= alcGetContextsDevice(ctx
);
82 alcMakeContextCurrent(NULL
);
83 alcDestroyContext(ctx
);
84 alcCloseDevice(device
);
88 /* GetFormat retrieves a compatible buffer format given the channel config and
89 * sample type. If an alIsBufferFormatSupportedSOFT-compatible function is
90 * provided, it will be called to find the closest-matching format from
91 * AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be
93 ALenum
GetFormat(ALenum channels
, ALenum type
, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT
)
95 ALenum format
= AL_NONE
;
97 /* If using AL_SOFT_buffer_samples, try looking through its formats */
98 if(palIsBufferFormatSupportedSOFT
)
100 /* AL_SOFT_buffer_samples is more lenient with matching formats. The
101 * specified sample type does not need to match the returned format,
102 * but it is nice to try to get something close. */
103 if(type
== AL_UNSIGNED_BYTE_SOFT
|| type
== AL_BYTE_SOFT
)
105 if(channels
== AL_MONO_SOFT
) format
= AL_MONO8_SOFT
;
106 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO8_SOFT
;
107 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD8_SOFT
;
108 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_8_SOFT
;
109 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_8_SOFT
;
110 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_8_SOFT
;
112 else if(type
== AL_UNSIGNED_SHORT_SOFT
|| type
== AL_SHORT_SOFT
)
114 if(channels
== AL_MONO_SOFT
) format
= AL_MONO16_SOFT
;
115 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO16_SOFT
;
116 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD16_SOFT
;
117 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_16_SOFT
;
118 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_16_SOFT
;
119 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_16_SOFT
;
121 else if(type
== AL_UNSIGNED_BYTE3_SOFT
|| type
== AL_BYTE3_SOFT
||
122 type
== AL_UNSIGNED_INT_SOFT
|| type
== AL_INT_SOFT
||
123 type
== AL_FLOAT_SOFT
|| type
== AL_DOUBLE_SOFT
)
125 if(channels
== AL_MONO_SOFT
) format
= AL_MONO32F_SOFT
;
126 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO32F_SOFT
;
127 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD32F_SOFT
;
128 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_32F_SOFT
;
129 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_32F_SOFT
;
130 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_32F_SOFT
;
133 if(format
!= AL_NONE
&& !palIsBufferFormatSupportedSOFT(format
))
136 /* A matching format was not found or supported. Try 32-bit float. */
137 if(format
== AL_NONE
)
139 if(channels
== AL_MONO_SOFT
) format
= AL_MONO32F_SOFT
;
140 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO32F_SOFT
;
141 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD32F_SOFT
;
142 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_32F_SOFT
;
143 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_32F_SOFT
;
144 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_32F_SOFT
;
146 if(format
!= AL_NONE
&& !palIsBufferFormatSupportedSOFT(format
))
149 /* 32-bit float not supported. Try 16-bit int. */
150 if(format
== AL_NONE
)
152 if(channels
== AL_MONO_SOFT
) format
= AL_MONO16_SOFT
;
153 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO16_SOFT
;
154 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD16_SOFT
;
155 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_16_SOFT
;
156 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_16_SOFT
;
157 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_16_SOFT
;
159 if(format
!= AL_NONE
&& !palIsBufferFormatSupportedSOFT(format
))
162 /* 16-bit int not supported. Try 8-bit int. */
163 if(format
== AL_NONE
)
165 if(channels
== AL_MONO_SOFT
) format
= AL_MONO8_SOFT
;
166 else if(channels
== AL_STEREO_SOFT
) format
= AL_STEREO8_SOFT
;
167 else if(channels
== AL_QUAD_SOFT
) format
= AL_QUAD8_SOFT
;
168 else if(channels
== AL_5POINT1_SOFT
) format
= AL_5POINT1_8_SOFT
;
169 else if(channels
== AL_6POINT1_SOFT
) format
= AL_6POINT1_8_SOFT
;
170 else if(channels
== AL_7POINT1_SOFT
) format
= AL_7POINT1_8_SOFT
;
172 if(format
!= AL_NONE
&& !palIsBufferFormatSupportedSOFT(format
))
179 /* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1,
180 * and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and
181 * AL_EXT_DOUBLE for 64-bit float samples. */
182 if(type
== AL_UNSIGNED_BYTE_SOFT
)
184 if(channels
== AL_MONO_SOFT
)
185 format
= AL_FORMAT_MONO8
;
186 else if(channels
== AL_STEREO_SOFT
)
187 format
= AL_FORMAT_STEREO8
;
188 else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
190 if(channels
== AL_QUAD_SOFT
)
191 format
= alGetEnumValue("AL_FORMAT_QUAD8");
192 else if(channels
== AL_5POINT1_SOFT
)
193 format
= alGetEnumValue("AL_FORMAT_51CHN8");
194 else if(channels
== AL_6POINT1_SOFT
)
195 format
= alGetEnumValue("AL_FORMAT_61CHN8");
196 else if(channels
== AL_7POINT1_SOFT
)
197 format
= alGetEnumValue("AL_FORMAT_71CHN8");
200 else if(type
== AL_SHORT_SOFT
)
202 if(channels
== AL_MONO_SOFT
)
203 format
= AL_FORMAT_MONO16
;
204 else if(channels
== AL_STEREO_SOFT
)
205 format
= AL_FORMAT_STEREO16
;
206 else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
208 if(channels
== AL_QUAD_SOFT
)
209 format
= alGetEnumValue("AL_FORMAT_QUAD16");
210 else if(channels
== AL_5POINT1_SOFT
)
211 format
= alGetEnumValue("AL_FORMAT_51CHN16");
212 else if(channels
== AL_6POINT1_SOFT
)
213 format
= alGetEnumValue("AL_FORMAT_61CHN16");
214 else if(channels
== AL_7POINT1_SOFT
)
215 format
= alGetEnumValue("AL_FORMAT_71CHN16");
218 else if(type
== AL_FLOAT_SOFT
&& alIsExtensionPresent("AL_EXT_FLOAT32"))
220 if(channels
== AL_MONO_SOFT
)
221 format
= alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
222 else if(channels
== AL_STEREO_SOFT
)
223 format
= alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
224 else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
226 if(channels
== AL_QUAD_SOFT
)
227 format
= alGetEnumValue("AL_FORMAT_QUAD32");
228 else if(channels
== AL_5POINT1_SOFT
)
229 format
= alGetEnumValue("AL_FORMAT_51CHN32");
230 else if(channels
== AL_6POINT1_SOFT
)
231 format
= alGetEnumValue("AL_FORMAT_61CHN32");
232 else if(channels
== AL_7POINT1_SOFT
)
233 format
= alGetEnumValue("AL_FORMAT_71CHN32");
236 else if(type
== AL_DOUBLE_SOFT
&& alIsExtensionPresent("AL_EXT_DOUBLE"))
238 if(channels
== AL_MONO_SOFT
)
239 format
= alGetEnumValue("AL_FORMAT_MONO_DOUBLE");
240 else if(channels
== AL_STEREO_SOFT
)
241 format
= alGetEnumValue("AL_FORMAT_STEREO_DOUBLE");
244 /* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as
245 * opposed to 0. Correct it. */
253 void AL_APIENTRY
wrap_BufferSamples(ALuint buffer
, ALuint samplerate
,
254 ALenum internalformat
, ALsizei samples
,
255 ALenum channels
, ALenum type
,
258 alBufferData(buffer
, internalformat
, data
,
259 FramesToBytes(samples
, channels
, type
),
264 const char *ChannelsName(ALenum chans
)
268 case AL_MONO_SOFT
: return "Mono";
269 case AL_STEREO_SOFT
: return "Stereo";
270 case AL_REAR_SOFT
: return "Rear";
271 case AL_QUAD_SOFT
: return "Quadraphonic";
272 case AL_5POINT1_SOFT
: return "5.1 Surround";
273 case AL_6POINT1_SOFT
: return "6.1 Surround";
274 case AL_7POINT1_SOFT
: return "7.1 Surround";
276 return "Unknown Channels";
279 const char *TypeName(ALenum type
)
283 case AL_BYTE_SOFT
: return "S8";
284 case AL_UNSIGNED_BYTE_SOFT
: return "U8";
285 case AL_SHORT_SOFT
: return "S16";
286 case AL_UNSIGNED_SHORT_SOFT
: return "U16";
287 case AL_INT_SOFT
: return "S32";
288 case AL_UNSIGNED_INT_SOFT
: return "U32";
289 case AL_FLOAT_SOFT
: return "Float32";
290 case AL_DOUBLE_SOFT
: return "Float64";
292 return "Unknown Type";
296 ALsizei
FramesToBytes(ALsizei size
, ALenum channels
, ALenum type
)
300 case AL_MONO_SOFT
: size
*= 1; break;
301 case AL_STEREO_SOFT
: size
*= 2; break;
302 case AL_REAR_SOFT
: size
*= 2; break;
303 case AL_QUAD_SOFT
: size
*= 4; break;
304 case AL_5POINT1_SOFT
: size
*= 6; break;
305 case AL_6POINT1_SOFT
: size
*= 7; break;
306 case AL_7POINT1_SOFT
: size
*= 8; break;
311 case AL_BYTE_SOFT
: size
*= sizeof(ALbyte
); break;
312 case AL_UNSIGNED_BYTE_SOFT
: size
*= sizeof(ALubyte
); break;
313 case AL_SHORT_SOFT
: size
*= sizeof(ALshort
); break;
314 case AL_UNSIGNED_SHORT_SOFT
: size
*= sizeof(ALushort
); break;
315 case AL_INT_SOFT
: size
*= sizeof(ALint
); break;
316 case AL_UNSIGNED_INT_SOFT
: size
*= sizeof(ALuint
); break;
317 case AL_FLOAT_SOFT
: size
*= sizeof(ALfloat
); break;
318 case AL_DOUBLE_SOFT
: size
*= sizeof(ALdouble
); break;
324 ALsizei
BytesToFrames(ALsizei size
, ALenum channels
, ALenum type
)
326 return size
/ FramesToBytes(1, channels
, type
);