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
26 #include "alListener.h"
29 #define DO_UPDATEPROPS() do { \
30 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
31 UpdateListenerProps(context); \
33 ATOMIC_FLAG_CLEAR(&listener->PropsClean, almemory_order_release); \
37 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
42 context
= GetContextRef();
45 listener
= context
->Listener
;
46 WriteLock(&context
->PropLock
);
50 if(!(value
>= 0.0f
&& isfinite(value
)))
51 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
52 listener
->Gain
= value
;
56 case AL_METERS_PER_UNIT
:
57 if(!(value
>= AL_MIN_METERS_PER_UNIT
&& value
<= AL_MAX_METERS_PER_UNIT
))
58 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
59 context
->MetersPerUnit
= value
;
60 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
61 UpdateContextProps(context
);
63 ATOMIC_FLAG_CLEAR(&context
->PropsClean
, almemory_order_release
);
67 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
71 WriteUnlock(&context
->PropLock
);
72 ALCcontext_DecRef(context
);
76 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
81 context
= GetContextRef();
84 listener
= context
->Listener
;
85 WriteLock(&context
->PropLock
);
89 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
90 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
91 listener
->Position
[0] = value1
;
92 listener
->Position
[1] = value2
;
93 listener
->Position
[2] = value3
;
98 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
99 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
100 listener
->Velocity
[0] = value1
;
101 listener
->Velocity
[1] = value2
;
102 listener
->Velocity
[2] = value3
;
107 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
111 WriteUnlock(&context
->PropLock
);
112 ALCcontext_DecRef(context
);
116 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
118 ALlistener
*listener
;
126 case AL_METERS_PER_UNIT
:
127 alListenerf(param
, values
[0]);
132 alListener3f(param
, values
[0], values
[1], values
[2]);
137 context
= GetContextRef();
140 listener
= context
->Listener
;
141 WriteLock(&context
->PropLock
);
143 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
147 if(!(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
148 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5])))
149 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
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];
161 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
165 WriteUnlock(&context
->PropLock
);
166 ALCcontext_DecRef(context
);
170 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
174 context
= GetContextRef();
177 WriteLock(&context
->PropLock
);
181 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
185 WriteUnlock(&context
->PropLock
);
186 ALCcontext_DecRef(context
);
190 AL_API
void AL_APIENTRY
alListener3i(ALenum param
, ALint value1
, ALint value2
, ALint value3
)
198 alListener3f(param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
202 context
= GetContextRef();
205 WriteLock(&context
->PropLock
);
209 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
213 WriteUnlock(&context
->PropLock
);
214 ALCcontext_DecRef(context
);
218 AL_API
void AL_APIENTRY
alListeneriv(ALenum param
, const ALint
*values
)
229 alListener3f(param
, (ALfloat
)values
[0], (ALfloat
)values
[1], (ALfloat
)values
[2]);
233 fvals
[0] = (ALfloat
)values
[0];
234 fvals
[1] = (ALfloat
)values
[1];
235 fvals
[2] = (ALfloat
)values
[2];
236 fvals
[3] = (ALfloat
)values
[3];
237 fvals
[4] = (ALfloat
)values
[4];
238 fvals
[5] = (ALfloat
)values
[5];
239 alListenerfv(param
, fvals
);
244 context
= GetContextRef();
247 WriteLock(&context
->PropLock
);
249 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
253 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
257 WriteUnlock(&context
->PropLock
);
258 ALCcontext_DecRef(context
);
262 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
266 context
= GetContextRef();
269 ReadLock(&context
->PropLock
);
271 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
275 *value
= context
->Listener
->Gain
;
278 case AL_METERS_PER_UNIT
:
279 *value
= context
->MetersPerUnit
;
283 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
287 ReadUnlock(&context
->PropLock
);
288 ALCcontext_DecRef(context
);
292 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
296 context
= GetContextRef();
299 ReadLock(&context
->PropLock
);
300 if(!(value1
&& value2
&& value3
))
301 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
305 *value1
= context
->Listener
->Position
[0];
306 *value2
= context
->Listener
->Position
[1];
307 *value3
= context
->Listener
->Position
[2];
311 *value1
= context
->Listener
->Velocity
[0];
312 *value2
= context
->Listener
->Velocity
[1];
313 *value3
= context
->Listener
->Velocity
[2];
317 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
321 ReadUnlock(&context
->PropLock
);
322 ALCcontext_DecRef(context
);
326 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
333 case AL_METERS_PER_UNIT
:
334 alGetListenerf(param
, values
);
339 alGetListener3f(param
, values
+0, values
+1, values
+2);
343 context
= GetContextRef();
346 ReadLock(&context
->PropLock
);
348 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
353 values
[0] = context
->Listener
->Forward
[0];
354 values
[1] = context
->Listener
->Forward
[1];
355 values
[2] = context
->Listener
->Forward
[2];
356 values
[3] = context
->Listener
->Up
[0];
357 values
[4] = context
->Listener
->Up
[1];
358 values
[5] = context
->Listener
->Up
[2];
362 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
366 ReadUnlock(&context
->PropLock
);
367 ALCcontext_DecRef(context
);
371 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
375 context
= GetContextRef();
378 ReadLock(&context
->PropLock
);
380 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
384 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
388 ReadUnlock(&context
->PropLock
);
389 ALCcontext_DecRef(context
);
393 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
397 context
= GetContextRef();
400 ReadLock(&context
->PropLock
);
401 if(!(value1
&& value2
&& value3
))
402 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
406 *value1
= (ALint
)context
->Listener
->Position
[0];
407 *value2
= (ALint
)context
->Listener
->Position
[1];
408 *value3
= (ALint
)context
->Listener
->Position
[2];
412 *value1
= (ALint
)context
->Listener
->Velocity
[0];
413 *value2
= (ALint
)context
->Listener
->Velocity
[1];
414 *value3
= (ALint
)context
->Listener
->Velocity
[2];
418 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
422 ReadUnlock(&context
->PropLock
);
423 ALCcontext_DecRef(context
);
427 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
435 alGetListener3i(param
, values
+0, values
+1, values
+2);
439 context
= GetContextRef();
442 ReadLock(&context
->PropLock
);
444 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
449 values
[0] = (ALint
)context
->Listener
->Forward
[0];
450 values
[1] = (ALint
)context
->Listener
->Forward
[1];
451 values
[2] = (ALint
)context
->Listener
->Forward
[2];
452 values
[3] = (ALint
)context
->Listener
->Up
[0];
453 values
[4] = (ALint
)context
->Listener
->Up
[1];
454 values
[5] = (ALint
)context
->Listener
->Up
[2];
458 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
462 ReadUnlock(&context
->PropLock
);
463 ALCcontext_DecRef(context
);
467 void UpdateListenerProps(ALCcontext
*context
)
469 ALlistener
*listener
= context
->Listener
;
470 struct ALlistenerProps
*props
;
472 /* Get an unused proprty container, or allocate a new one as needed. */
473 props
= ATOMIC_LOAD(&listener
->FreeList
, almemory_order_acquire
);
475 props
= al_calloc(16, sizeof(*props
));
478 struct ALlistenerProps
*next
;
480 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
481 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&listener
->FreeList
, &props
, next
,
482 almemory_order_seq_cst
, almemory_order_acquire
) == 0);
485 /* Copy in current property values. */
486 props
->Position
[0] = listener
->Position
[0];
487 props
->Position
[1] = listener
->Position
[1];
488 props
->Position
[2] = listener
->Position
[2];
490 props
->Velocity
[0] = listener
->Velocity
[0];
491 props
->Velocity
[1] = listener
->Velocity
[1];
492 props
->Velocity
[2] = listener
->Velocity
[2];
494 props
->Forward
[0] = listener
->Forward
[0];
495 props
->Forward
[1] = listener
->Forward
[1];
496 props
->Forward
[2] = listener
->Forward
[2];
497 props
->Up
[0] = listener
->Up
[0];
498 props
->Up
[1] = listener
->Up
[1];
499 props
->Up
[2] = listener
->Up
[2];
501 props
->Gain
= listener
->Gain
;
503 /* Set the new container for updating internal parameters. */
504 props
= ATOMIC_EXCHANGE_PTR(&listener
->Update
, props
, almemory_order_acq_rel
);
507 /* If there was an unused update container, put it back in the
510 ATOMIC_REPLACE_HEAD(struct ALlistenerProps
*, &listener
->FreeList
, props
);