Avoid a few more explicit loops
[openal-soft.git] / OpenAL32 / alListener.cpp
blobc86c837451b5a37bf129eb3c9b4e61874177be01
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2000 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <cmath>
25 #include "alMain.h"
26 #include "alcontext.h"
27 #include "alu.h"
28 #include "alError.h"
29 #include "alListener.h"
30 #include "alSource.h"
32 #define DO_UPDATEPROPS() do { \
33 if(!context->DeferUpdates.load(std::memory_order_acquire)) \
34 UpdateListenerProps(context.get()); \
35 else \
36 listener.PropsClean.clear(std::memory_order_release); \
37 } while(0)
40 AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
42 ContextRef context{GetContextRef()};
43 if(UNLIKELY(!context)) return;
45 ALlistener &listener = context->Listener;
46 std::lock_guard<std::mutex> _{context->PropLock};
47 switch(param)
49 case AL_GAIN:
50 if(!(value >= 0.0f && std::isfinite(value)))
51 SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range");
52 listener.Gain = value;
53 DO_UPDATEPROPS();
54 break;
56 case AL_METERS_PER_UNIT:
57 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
58 SETERR_RETURN(context.get(), AL_INVALID_VALUE,,
59 "Listener meters per unit out of range");
60 context->MetersPerUnit = value;
61 if(!context->DeferUpdates.load(std::memory_order_acquire))
62 UpdateContextProps(context.get());
63 else
64 context->PropsClean.clear(std::memory_order_release);
65 break;
67 default:
68 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property");
73 AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
75 ContextRef context{GetContextRef()};
76 if(UNLIKELY(!context)) return;
78 ALlistener &listener = context->Listener;
79 std::lock_guard<std::mutex> _{context->PropLock};
80 switch(param)
82 case AL_POSITION:
83 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
84 SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range");
85 listener.Position[0] = value1;
86 listener.Position[1] = value2;
87 listener.Position[2] = value3;
88 DO_UPDATEPROPS();
89 break;
91 case AL_VELOCITY:
92 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
93 SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range");
94 listener.Velocity[0] = value1;
95 listener.Velocity[1] = value2;
96 listener.Velocity[2] = value3;
97 DO_UPDATEPROPS();
98 break;
100 default:
101 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property");
106 AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
108 if(values)
110 switch(param)
112 case AL_GAIN:
113 case AL_METERS_PER_UNIT:
114 alListenerf(param, values[0]);
115 return;
117 case AL_POSITION:
118 case AL_VELOCITY:
119 alListener3f(param, values[0], values[1], values[2]);
120 return;
124 ContextRef context{GetContextRef()};
125 if(UNLIKELY(!context)) return;
127 ALlistener &listener = context->Listener;
128 std::lock_guard<std::mutex> _{context->PropLock};
129 if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer");
130 switch(param)
132 case AL_ORIENTATION:
133 if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
134 std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])))
135 SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range");
136 /* AT then UP */
137 listener.Forward[0] = values[0];
138 listener.Forward[1] = values[1];
139 listener.Forward[2] = values[2];
140 listener.Up[0] = values[3];
141 listener.Up[1] = values[4];
142 listener.Up[2] = values[5];
143 DO_UPDATEPROPS();
144 break;
146 default:
147 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property");
152 AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
154 ContextRef context{GetContextRef()};
155 if(UNLIKELY(!context)) return;
157 std::lock_guard<std::mutex> _{context->PropLock};
158 switch(param)
160 default:
161 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property");
166 AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
168 switch(param)
170 case AL_POSITION:
171 case AL_VELOCITY:
172 alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
173 return;
176 ContextRef context{GetContextRef()};
177 if(UNLIKELY(!context)) return;
179 std::lock_guard<std::mutex> _{context->PropLock};
180 switch(param)
182 default:
183 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property");
188 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
190 if(values)
192 ALfloat fvals[6];
193 switch(param)
195 case AL_POSITION:
196 case AL_VELOCITY:
197 alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
198 return;
200 case AL_ORIENTATION:
201 fvals[0] = (ALfloat)values[0];
202 fvals[1] = (ALfloat)values[1];
203 fvals[2] = (ALfloat)values[2];
204 fvals[3] = (ALfloat)values[3];
205 fvals[4] = (ALfloat)values[4];
206 fvals[5] = (ALfloat)values[5];
207 alListenerfv(param, fvals);
208 return;
212 ContextRef context{GetContextRef()};
213 if(UNLIKELY(!context)) return;
215 std::lock_guard<std::mutex> _{context->PropLock};
216 if(!values)
217 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
218 else switch(param)
220 default:
221 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property");
226 AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
228 ContextRef context{GetContextRef()};
229 if(UNLIKELY(!context)) return;
231 ALlistener &listener = context->Listener;
232 std::lock_guard<std::mutex> _{context->PropLock};
233 if(!value)
234 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
235 else switch(param)
237 case AL_GAIN:
238 *value = listener.Gain;
239 break;
241 case AL_METERS_PER_UNIT:
242 *value = context->MetersPerUnit;
243 break;
245 default:
246 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property");
251 AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
253 ContextRef context{GetContextRef()};
254 if(UNLIKELY(!context)) return;
256 ALlistener &listener = context->Listener;
257 std::lock_guard<std::mutex> _{context->PropLock};
258 if(!value1 || !value2 || !value3)
259 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
260 else switch(param)
262 case AL_POSITION:
263 *value1 = listener.Position[0];
264 *value2 = listener.Position[1];
265 *value3 = listener.Position[2];
266 break;
268 case AL_VELOCITY:
269 *value1 = listener.Velocity[0];
270 *value2 = listener.Velocity[1];
271 *value3 = listener.Velocity[2];
272 break;
274 default:
275 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property");
280 AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
282 switch(param)
284 case AL_GAIN:
285 case AL_METERS_PER_UNIT:
286 alGetListenerf(param, values);
287 return;
289 case AL_POSITION:
290 case AL_VELOCITY:
291 alGetListener3f(param, values+0, values+1, values+2);
292 return;
295 ContextRef context{GetContextRef()};
296 if(UNLIKELY(!context)) return;
298 ALlistener &listener = context->Listener;
299 std::lock_guard<std::mutex> _{context->PropLock};
300 if(!values)
301 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
302 else switch(param)
304 case AL_ORIENTATION:
305 // AT then UP
306 values[0] = listener.Forward[0];
307 values[1] = listener.Forward[1];
308 values[2] = listener.Forward[2];
309 values[3] = listener.Up[0];
310 values[4] = listener.Up[1];
311 values[5] = listener.Up[2];
312 break;
314 default:
315 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property");
320 AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
322 ContextRef context{GetContextRef()};
323 if(UNLIKELY(!context)) return;
325 std::lock_guard<std::mutex> _{context->PropLock};
326 if(!value)
327 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
328 else switch(param)
330 default:
331 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property");
336 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
338 ContextRef context{GetContextRef()};
339 if(UNLIKELY(!context)) return;
341 ALlistener &listener = context->Listener;
342 std::lock_guard<std::mutex> _{context->PropLock};
343 if(!value1 || !value2 || !value3)
344 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
345 else switch(param)
347 case AL_POSITION:
348 *value1 = (ALint)listener.Position[0];
349 *value2 = (ALint)listener.Position[1];
350 *value3 = (ALint)listener.Position[2];
351 break;
353 case AL_VELOCITY:
354 *value1 = (ALint)listener.Velocity[0];
355 *value2 = (ALint)listener.Velocity[1];
356 *value3 = (ALint)listener.Velocity[2];
357 break;
359 default:
360 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property");
365 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
367 switch(param)
369 case AL_POSITION:
370 case AL_VELOCITY:
371 alGetListener3i(param, values+0, values+1, values+2);
372 return;
375 ContextRef context{GetContextRef()};
376 if(UNLIKELY(!context)) return;
378 ALlistener &listener = context->Listener;
379 std::lock_guard<std::mutex> _{context->PropLock};
380 if(!values)
381 alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
382 else switch(param)
384 case AL_ORIENTATION:
385 // AT then UP
386 values[0] = (ALint)listener.Forward[0];
387 values[1] = (ALint)listener.Forward[1];
388 values[2] = (ALint)listener.Forward[2];
389 values[3] = (ALint)listener.Up[0];
390 values[4] = (ALint)listener.Up[1];
391 values[5] = (ALint)listener.Up[2];
392 break;
394 default:
395 alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property");
400 void UpdateListenerProps(ALCcontext *context)
402 /* Get an unused proprty container, or allocate a new one as needed. */
403 ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)};
404 if(!props)
405 props = static_cast<ALlistenerProps*>(al_calloc(16, sizeof(*props)));
406 else
408 struct ALlistenerProps *next;
409 do {
410 next = props->next.load(std::memory_order_relaxed);
411 } while(context->FreeListenerProps.compare_exchange_weak(props, next,
412 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
415 /* Copy in current property values. */
416 ALlistener &listener = context->Listener;
417 props->Position[0] = listener.Position[0];
418 props->Position[1] = listener.Position[1];
419 props->Position[2] = listener.Position[2];
421 props->Velocity[0] = listener.Velocity[0];
422 props->Velocity[1] = listener.Velocity[1];
423 props->Velocity[2] = listener.Velocity[2];
425 props->Forward[0] = listener.Forward[0];
426 props->Forward[1] = listener.Forward[1];
427 props->Forward[2] = listener.Forward[2];
428 props->Up[0] = listener.Up[0];
429 props->Up[1] = listener.Up[1];
430 props->Up[2] = listener.Up[2];
432 props->Gain = listener.Gain;
434 /* Set the new container for updating internal parameters. */
435 props = listener.Update.exchange(props, std::memory_order_acq_rel);
436 if(props)
438 /* If there was an unused update container, put it back in the
439 * freelist.
441 AtomicReplaceHead(context->FreeListenerProps, props);