Remove the atomic exchange macros
[openal-soft.git] / OpenAL32 / alListener.cpp
blobbf1ac3f924247c9cbadf3d6eb196cdb11fe8d554
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 "alMain.h"
24 #include "alcontext.h"
25 #include "alu.h"
26 #include "alError.h"
27 #include "alListener.h"
28 #include "alSource.h"
30 #define DO_UPDATEPROPS() do { \
31 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
32 UpdateListenerProps(context); \
33 else \
34 ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\
35 } while(0)
38 AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
40 ALlistener *listener;
41 ALCcontext *context;
43 context = GetContextRef();
44 if(!context) return;
46 listener = &context->Listener;
47 almtx_lock(&context->PropLock);
48 switch(param)
50 case AL_GAIN:
51 if(!(value >= 0.0f && isfinite(value)))
52 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range");
53 listener->Gain = value;
54 DO_UPDATEPROPS();
55 break;
57 case AL_METERS_PER_UNIT:
58 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
59 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range");
60 context->MetersPerUnit = value;
61 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
62 UpdateContextProps(context);
63 else
64 ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release);
65 break;
67 default:
68 alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
71 done:
72 almtx_unlock(&context->PropLock);
73 ALCcontext_DecRef(context);
77 AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
79 ALlistener *listener;
80 ALCcontext *context;
82 context = GetContextRef();
83 if(!context) return;
85 listener = &context->Listener;
86 almtx_lock(&context->PropLock);
87 switch(param)
89 case AL_POSITION:
90 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
91 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range");
92 listener->Position[0] = value1;
93 listener->Position[1] = value2;
94 listener->Position[2] = value3;
95 DO_UPDATEPROPS();
96 break;
98 case AL_VELOCITY:
99 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
100 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range");
101 listener->Velocity[0] = value1;
102 listener->Velocity[1] = value2;
103 listener->Velocity[2] = value3;
104 DO_UPDATEPROPS();
105 break;
107 default:
108 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
111 done:
112 almtx_unlock(&context->PropLock);
113 ALCcontext_DecRef(context);
117 AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
119 ALlistener *listener;
120 ALCcontext *context;
122 if(values)
124 switch(param)
126 case AL_GAIN:
127 case AL_METERS_PER_UNIT:
128 alListenerf(param, values[0]);
129 return;
131 case AL_POSITION:
132 case AL_VELOCITY:
133 alListener3f(param, values[0], values[1], values[2]);
134 return;
138 context = GetContextRef();
139 if(!context) return;
141 listener = &context->Listener;
142 almtx_lock(&context->PropLock);
143 if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
144 switch(param)
146 case AL_ORIENTATION:
147 if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
148 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
149 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range");
150 /* AT then UP */
151 listener->Forward[0] = values[0];
152 listener->Forward[1] = values[1];
153 listener->Forward[2] = values[2];
154 listener->Up[0] = values[3];
155 listener->Up[1] = values[4];
156 listener->Up[2] = values[5];
157 DO_UPDATEPROPS();
158 break;
160 default:
161 alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
164 done:
165 almtx_unlock(&context->PropLock);
166 ALCcontext_DecRef(context);
170 AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
172 ALCcontext *context;
174 context = GetContextRef();
175 if(!context) return;
177 almtx_lock(&context->PropLock);
178 switch(param)
180 default:
181 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
183 almtx_unlock(&context->PropLock);
185 ALCcontext_DecRef(context);
189 AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
191 ALCcontext *context;
193 switch(param)
195 case AL_POSITION:
196 case AL_VELOCITY:
197 alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
198 return;
201 context = GetContextRef();
202 if(!context) return;
204 almtx_lock(&context->PropLock);
205 switch(param)
207 default:
208 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
210 almtx_unlock(&context->PropLock);
212 ALCcontext_DecRef(context);
216 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
218 ALCcontext *context;
220 if(values)
222 ALfloat fvals[6];
223 switch(param)
225 case AL_POSITION:
226 case AL_VELOCITY:
227 alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
228 return;
230 case AL_ORIENTATION:
231 fvals[0] = (ALfloat)values[0];
232 fvals[1] = (ALfloat)values[1];
233 fvals[2] = (ALfloat)values[2];
234 fvals[3] = (ALfloat)values[3];
235 fvals[4] = (ALfloat)values[4];
236 fvals[5] = (ALfloat)values[5];
237 alListenerfv(param, fvals);
238 return;
242 context = GetContextRef();
243 if(!context) return;
245 almtx_lock(&context->PropLock);
246 if(!values)
247 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
248 else switch(param)
250 default:
251 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
253 almtx_unlock(&context->PropLock);
255 ALCcontext_DecRef(context);
259 AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
261 ALCcontext *context;
263 context = GetContextRef();
264 if(!context) return;
266 almtx_lock(&context->PropLock);
267 if(!value)
268 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
269 else switch(param)
271 case AL_GAIN:
272 *value = context->Listener.Gain;
273 break;
275 case AL_METERS_PER_UNIT:
276 *value = context->MetersPerUnit;
277 break;
279 default:
280 alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
282 almtx_unlock(&context->PropLock);
284 ALCcontext_DecRef(context);
288 AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
290 ALCcontext *context;
292 context = GetContextRef();
293 if(!context) return;
295 almtx_lock(&context->PropLock);
296 if(!value1 || !value2 || !value3)
297 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
298 else switch(param)
300 case AL_POSITION:
301 *value1 = context->Listener.Position[0];
302 *value2 = context->Listener.Position[1];
303 *value3 = context->Listener.Position[2];
304 break;
306 case AL_VELOCITY:
307 *value1 = context->Listener.Velocity[0];
308 *value2 = context->Listener.Velocity[1];
309 *value3 = context->Listener.Velocity[2];
310 break;
312 default:
313 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
315 almtx_unlock(&context->PropLock);
317 ALCcontext_DecRef(context);
321 AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
323 ALCcontext *context;
325 switch(param)
327 case AL_GAIN:
328 case AL_METERS_PER_UNIT:
329 alGetListenerf(param, values);
330 return;
332 case AL_POSITION:
333 case AL_VELOCITY:
334 alGetListener3f(param, values+0, values+1, values+2);
335 return;
338 context = GetContextRef();
339 if(!context) return;
341 almtx_lock(&context->PropLock);
342 if(!values)
343 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
344 else switch(param)
346 case AL_ORIENTATION:
347 // AT then UP
348 values[0] = context->Listener.Forward[0];
349 values[1] = context->Listener.Forward[1];
350 values[2] = context->Listener.Forward[2];
351 values[3] = context->Listener.Up[0];
352 values[4] = context->Listener.Up[1];
353 values[5] = context->Listener.Up[2];
354 break;
356 default:
357 alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
359 almtx_unlock(&context->PropLock);
361 ALCcontext_DecRef(context);
365 AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
367 ALCcontext *context;
369 context = GetContextRef();
370 if(!context) return;
372 almtx_lock(&context->PropLock);
373 if(!value)
374 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
375 else switch(param)
377 default:
378 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
380 almtx_unlock(&context->PropLock);
382 ALCcontext_DecRef(context);
386 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
388 ALCcontext *context;
390 context = GetContextRef();
391 if(!context) return;
393 almtx_lock(&context->PropLock);
394 if(!value1 || !value2 || !value3)
395 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
396 else switch(param)
398 case AL_POSITION:
399 *value1 = (ALint)context->Listener.Position[0];
400 *value2 = (ALint)context->Listener.Position[1];
401 *value3 = (ALint)context->Listener.Position[2];
402 break;
404 case AL_VELOCITY:
405 *value1 = (ALint)context->Listener.Velocity[0];
406 *value2 = (ALint)context->Listener.Velocity[1];
407 *value3 = (ALint)context->Listener.Velocity[2];
408 break;
410 default:
411 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
413 almtx_unlock(&context->PropLock);
415 ALCcontext_DecRef(context);
419 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
421 ALCcontext *context;
423 switch(param)
425 case AL_POSITION:
426 case AL_VELOCITY:
427 alGetListener3i(param, values+0, values+1, values+2);
428 return;
431 context = GetContextRef();
432 if(!context) return;
434 almtx_lock(&context->PropLock);
435 if(!values)
436 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
437 else switch(param)
439 case AL_ORIENTATION:
440 // AT then UP
441 values[0] = (ALint)context->Listener.Forward[0];
442 values[1] = (ALint)context->Listener.Forward[1];
443 values[2] = (ALint)context->Listener.Forward[2];
444 values[3] = (ALint)context->Listener.Up[0];
445 values[4] = (ALint)context->Listener.Up[1];
446 values[5] = (ALint)context->Listener.Up[2];
447 break;
449 default:
450 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
452 almtx_unlock(&context->PropLock);
454 ALCcontext_DecRef(context);
458 void UpdateListenerProps(ALCcontext *context)
460 ALlistener *listener{&context->Listener};
461 struct ALlistenerProps *props;
463 /* Get an unused proprty container, or allocate a new one as needed. */
464 props = context->FreeListenerProps.load(std::memory_order_acquire);
465 if(!props)
466 props = static_cast<ALlistenerProps*>(al_calloc(16, sizeof(*props)));
467 else
469 struct ALlistenerProps *next;
470 do {
471 next = props->next.load(std::memory_order_relaxed);
472 } while(context->FreeListenerProps.compare_exchange_weak(props, next,
473 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
476 /* Copy in current property values. */
477 props->Position[0] = listener->Position[0];
478 props->Position[1] = listener->Position[1];
479 props->Position[2] = listener->Position[2];
481 props->Velocity[0] = listener->Velocity[0];
482 props->Velocity[1] = listener->Velocity[1];
483 props->Velocity[2] = listener->Velocity[2];
485 props->Forward[0] = listener->Forward[0];
486 props->Forward[1] = listener->Forward[1];
487 props->Forward[2] = listener->Forward[2];
488 props->Up[0] = listener->Up[0];
489 props->Up[1] = listener->Up[1];
490 props->Up[2] = listener->Up[2];
492 props->Gain = listener->Gain;
494 /* Set the new container for updating internal parameters. */
495 props = listener->Update.exchange(props, std::memory_order_acq_rel);
496 if(props)
498 /* If there was an unused update container, put it back in the
499 * freelist.
501 AtomicReplaceHead(context->FreeListenerProps, props);