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 almtx_lock(&context
->PropLock
);
50 if(!(value
>= 0.0f
&& isfinite(value
)))
51 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener gain out of range");
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 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener meters per unit out of range");
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 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float property");
71 almtx_unlock(&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 almtx_lock(&context
->PropLock
);
89 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
90 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener position out of range");
91 listener
->Position
[0] = value1
;
92 listener
->Position
[1] = value2
;
93 listener
->Position
[2] = value3
;
98 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
99 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener velocity out of range");
100 listener
->Velocity
[0] = value1
;
101 listener
->Velocity
[1] = value2
;
102 listener
->Velocity
[2] = value3
;
107 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-float property");
111 almtx_unlock(&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 almtx_lock(&context
->PropLock
);
142 if(!values
) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "NULL pointer");
146 if(!(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
147 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5])))
148 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener orientation out of range");
150 listener
->Forward
[0] = values
[0];
151 listener
->Forward
[1] = values
[1];
152 listener
->Forward
[2] = values
[2];
153 listener
->Up
[0] = values
[3];
154 listener
->Up
[1] = values
[4];
155 listener
->Up
[2] = values
[5];
160 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float-vector property");
164 almtx_unlock(&context
->PropLock
);
165 ALCcontext_DecRef(context
);
169 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
173 context
= GetContextRef();
176 almtx_lock(&context
->PropLock
);
180 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer property");
182 almtx_unlock(&context
->PropLock
);
184 ALCcontext_DecRef(context
);
188 AL_API
void AL_APIENTRY
alListener3i(ALenum param
, ALint value1
, ALint value2
, ALint value3
)
196 alListener3f(param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
200 context
= GetContextRef();
203 almtx_lock(&context
->PropLock
);
207 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-integer property");
209 almtx_unlock(&context
->PropLock
);
211 ALCcontext_DecRef(context
);
215 AL_API
void AL_APIENTRY
alListeneriv(ALenum param
, const ALint
*values
)
226 alListener3f(param
, (ALfloat
)values
[0], (ALfloat
)values
[1], (ALfloat
)values
[2]);
230 fvals
[0] = (ALfloat
)values
[0];
231 fvals
[1] = (ALfloat
)values
[1];
232 fvals
[2] = (ALfloat
)values
[2];
233 fvals
[3] = (ALfloat
)values
[3];
234 fvals
[4] = (ALfloat
)values
[4];
235 fvals
[5] = (ALfloat
)values
[5];
236 alListenerfv(param
, fvals
);
241 context
= GetContextRef();
244 almtx_lock(&context
->PropLock
);
246 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
250 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer-vector property");
252 almtx_unlock(&context
->PropLock
);
254 ALCcontext_DecRef(context
);
258 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
262 context
= GetContextRef();
265 almtx_lock(&context
->PropLock
);
267 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
271 *value
= context
->Listener
->Gain
;
274 case AL_METERS_PER_UNIT
:
275 *value
= context
->MetersPerUnit
;
279 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float property");
281 almtx_unlock(&context
->PropLock
);
283 ALCcontext_DecRef(context
);
287 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
291 context
= GetContextRef();
294 almtx_lock(&context
->PropLock
);
295 if(!value1
|| !value2
|| !value3
)
296 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
300 *value1
= context
->Listener
->Position
[0];
301 *value2
= context
->Listener
->Position
[1];
302 *value3
= context
->Listener
->Position
[2];
306 *value1
= context
->Listener
->Velocity
[0];
307 *value2
= context
->Listener
->Velocity
[1];
308 *value3
= context
->Listener
->Velocity
[2];
312 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-float property");
314 almtx_unlock(&context
->PropLock
);
316 ALCcontext_DecRef(context
);
320 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
327 case AL_METERS_PER_UNIT
:
328 alGetListenerf(param
, values
);
333 alGetListener3f(param
, values
+0, values
+1, values
+2);
337 context
= GetContextRef();
340 almtx_lock(&context
->PropLock
);
342 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
347 values
[0] = context
->Listener
->Forward
[0];
348 values
[1] = context
->Listener
->Forward
[1];
349 values
[2] = context
->Listener
->Forward
[2];
350 values
[3] = context
->Listener
->Up
[0];
351 values
[4] = context
->Listener
->Up
[1];
352 values
[5] = context
->Listener
->Up
[2];
356 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float-vector property");
358 almtx_unlock(&context
->PropLock
);
360 ALCcontext_DecRef(context
);
364 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
368 context
= GetContextRef();
371 almtx_lock(&context
->PropLock
);
373 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
377 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer property");
379 almtx_unlock(&context
->PropLock
);
381 ALCcontext_DecRef(context
);
385 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
389 context
= GetContextRef();
392 almtx_lock(&context
->PropLock
);
393 if(!value1
|| !value2
|| !value3
)
394 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
398 *value1
= (ALint
)context
->Listener
->Position
[0];
399 *value2
= (ALint
)context
->Listener
->Position
[1];
400 *value3
= (ALint
)context
->Listener
->Position
[2];
404 *value1
= (ALint
)context
->Listener
->Velocity
[0];
405 *value2
= (ALint
)context
->Listener
->Velocity
[1];
406 *value3
= (ALint
)context
->Listener
->Velocity
[2];
410 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-integer property");
412 almtx_unlock(&context
->PropLock
);
414 ALCcontext_DecRef(context
);
418 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
426 alGetListener3i(param
, values
+0, values
+1, values
+2);
430 context
= GetContextRef();
433 almtx_lock(&context
->PropLock
);
435 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
440 values
[0] = (ALint
)context
->Listener
->Forward
[0];
441 values
[1] = (ALint
)context
->Listener
->Forward
[1];
442 values
[2] = (ALint
)context
->Listener
->Forward
[2];
443 values
[3] = (ALint
)context
->Listener
->Up
[0];
444 values
[4] = (ALint
)context
->Listener
->Up
[1];
445 values
[5] = (ALint
)context
->Listener
->Up
[2];
449 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer-vector property");
451 almtx_unlock(&context
->PropLock
);
453 ALCcontext_DecRef(context
);
457 void UpdateListenerProps(ALCcontext
*context
)
459 ALlistener
*listener
= context
->Listener
;
460 struct ALlistenerProps
*props
;
462 /* Get an unused proprty container, or allocate a new one as needed. */
463 props
= ATOMIC_LOAD(&context
->FreeListenerProps
, almemory_order_acquire
);
465 props
= al_calloc(16, sizeof(*props
));
468 struct ALlistenerProps
*next
;
470 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
471 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context
->FreeListenerProps
, &props
, next
,
472 almemory_order_seq_cst
, almemory_order_acquire
) == 0);
475 /* Copy in current property values. */
476 props
->Position
[0] = listener
->Position
[0];
477 props
->Position
[1] = listener
->Position
[1];
478 props
->Position
[2] = listener
->Position
[2];
480 props
->Velocity
[0] = listener
->Velocity
[0];
481 props
->Velocity
[1] = listener
->Velocity
[1];
482 props
->Velocity
[2] = listener
->Velocity
[2];
484 props
->Forward
[0] = listener
->Forward
[0];
485 props
->Forward
[1] = listener
->Forward
[1];
486 props
->Forward
[2] = listener
->Forward
[2];
487 props
->Up
[0] = listener
->Up
[0];
488 props
->Up
[1] = listener
->Up
[1];
489 props
->Up
[2] = listener
->Up
[2];
491 props
->Gain
= listener
->Gain
;
493 /* Set the new container for updating internal parameters. */
494 props
= ATOMIC_EXCHANGE_PTR(&listener
->Update
, props
, almemory_order_acq_rel
);
497 /* If there was an unused update container, put it back in the
500 ATOMIC_REPLACE_HEAD(struct ALlistenerProps
*, &context
->FreeListenerProps
, props
);