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 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
33 context
= GetContextRef();
36 WriteLock(&context
->PropLock
);
40 if(!(value
>= 0.0f
&& isfinite(value
)))
41 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
42 context
->Listener
->Gain
= value
;
45 case AL_METERS_PER_UNIT
:
46 if(!(value
>= 0.0f
&& isfinite(value
)))
47 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
48 context
->Listener
->MetersPerUnit
= value
;
52 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
54 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
56 UpdateListenerProps(context
);
57 UpdateAllSourceProps(context
);
61 WriteUnlock(&context
->PropLock
);
62 ALCcontext_DecRef(context
);
66 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
70 context
= GetContextRef();
73 WriteLock(&context
->PropLock
);
77 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
78 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
79 context
->Listener
->Position
[0] = value1
;
80 context
->Listener
->Position
[1] = value2
;
81 context
->Listener
->Position
[2] = value3
;
85 if(!(isfinite(value1
) && isfinite(value2
) && isfinite(value3
)))
86 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
87 context
->Listener
->Velocity
[0] = value1
;
88 context
->Listener
->Velocity
[1] = value2
;
89 context
->Listener
->Velocity
[2] = value3
;
93 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
95 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
97 UpdateListenerProps(context
);
98 UpdateAllSourceProps(context
);
102 WriteUnlock(&context
->PropLock
);
103 ALCcontext_DecRef(context
);
107 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
116 case AL_METERS_PER_UNIT
:
117 alListenerf(param
, values
[0]);
122 alListener3f(param
, values
[0], values
[1], values
[2]);
127 context
= GetContextRef();
130 WriteLock(&context
->PropLock
);
132 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
136 if(!(isfinite(values
[0]) && isfinite(values
[1]) && isfinite(values
[2]) &&
137 isfinite(values
[3]) && isfinite(values
[4]) && isfinite(values
[5])))
138 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
140 context
->Listener
->Forward
[0] = values
[0];
141 context
->Listener
->Forward
[1] = values
[1];
142 context
->Listener
->Forward
[2] = values
[2];
143 context
->Listener
->Up
[0] = values
[3];
144 context
->Listener
->Up
[1] = values
[4];
145 context
->Listener
->Up
[2] = values
[5];
149 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
151 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
153 UpdateListenerProps(context
);
154 UpdateAllSourceProps(context
);
158 WriteUnlock(&context
->PropLock
);
159 ALCcontext_DecRef(context
);
163 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
167 context
= GetContextRef();
170 WriteLock(&context
->PropLock
);
174 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
176 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
178 UpdateListenerProps(context
);
179 UpdateAllSourceProps(context
);
183 WriteUnlock(&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 WriteLock(&context
->PropLock
);
207 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
209 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
211 UpdateListenerProps(context
);
212 UpdateAllSourceProps(context
);
216 WriteUnlock(&context
->PropLock
);
217 ALCcontext_DecRef(context
);
221 AL_API
void AL_APIENTRY
alListeneriv(ALenum param
, const ALint
*values
)
232 alListener3f(param
, (ALfloat
)values
[0], (ALfloat
)values
[1], (ALfloat
)values
[2]);
236 fvals
[0] = (ALfloat
)values
[0];
237 fvals
[1] = (ALfloat
)values
[1];
238 fvals
[2] = (ALfloat
)values
[2];
239 fvals
[3] = (ALfloat
)values
[3];
240 fvals
[4] = (ALfloat
)values
[4];
241 fvals
[5] = (ALfloat
)values
[5];
242 alListenerfv(param
, fvals
);
247 context
= GetContextRef();
250 WriteLock(&context
->PropLock
);
252 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
256 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
258 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
260 UpdateListenerProps(context
);
261 UpdateAllSourceProps(context
);
265 WriteUnlock(&context
->PropLock
);
266 ALCcontext_DecRef(context
);
270 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
274 context
= GetContextRef();
277 ReadLock(&context
->PropLock
);
279 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
283 *value
= context
->Listener
->Gain
;
286 case AL_METERS_PER_UNIT
:
287 *value
= context
->Listener
->MetersPerUnit
;
291 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
295 ReadUnlock(&context
->PropLock
);
296 ALCcontext_DecRef(context
);
300 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
304 context
= GetContextRef();
307 ReadLock(&context
->PropLock
);
308 if(!(value1
&& value2
&& value3
))
309 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
313 *value1
= context
->Listener
->Position
[0];
314 *value2
= context
->Listener
->Position
[1];
315 *value3
= context
->Listener
->Position
[2];
319 *value1
= context
->Listener
->Velocity
[0];
320 *value2
= context
->Listener
->Velocity
[1];
321 *value3
= context
->Listener
->Velocity
[2];
325 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
329 ReadUnlock(&context
->PropLock
);
330 ALCcontext_DecRef(context
);
334 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
341 case AL_METERS_PER_UNIT
:
342 alGetListenerf(param
, values
);
347 alGetListener3f(param
, values
+0, values
+1, values
+2);
351 context
= GetContextRef();
354 ReadLock(&context
->PropLock
);
356 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
361 values
[0] = context
->Listener
->Forward
[0];
362 values
[1] = context
->Listener
->Forward
[1];
363 values
[2] = context
->Listener
->Forward
[2];
364 values
[3] = context
->Listener
->Up
[0];
365 values
[4] = context
->Listener
->Up
[1];
366 values
[5] = context
->Listener
->Up
[2];
370 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
374 ReadUnlock(&context
->PropLock
);
375 ALCcontext_DecRef(context
);
379 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
383 context
= GetContextRef();
386 ReadLock(&context
->PropLock
);
388 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
392 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
396 ReadUnlock(&context
->PropLock
);
397 ALCcontext_DecRef(context
);
401 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
405 context
= GetContextRef();
408 ReadLock(&context
->PropLock
);
409 if(!(value1
&& value2
&& value3
))
410 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
414 *value1
= (ALint
)context
->Listener
->Position
[0];
415 *value2
= (ALint
)context
->Listener
->Position
[1];
416 *value3
= (ALint
)context
->Listener
->Position
[2];
420 *value1
= (ALint
)context
->Listener
->Velocity
[0];
421 *value2
= (ALint
)context
->Listener
->Velocity
[1];
422 *value3
= (ALint
)context
->Listener
->Velocity
[2];
426 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
430 ReadUnlock(&context
->PropLock
);
431 ALCcontext_DecRef(context
);
435 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
443 alGetListener3i(param
, values
+0, values
+1, values
+2);
447 context
= GetContextRef();
450 ReadLock(&context
->PropLock
);
452 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
457 values
[0] = (ALint
)context
->Listener
->Forward
[0];
458 values
[1] = (ALint
)context
->Listener
->Forward
[1];
459 values
[2] = (ALint
)context
->Listener
->Forward
[2];
460 values
[3] = (ALint
)context
->Listener
->Up
[0];
461 values
[4] = (ALint
)context
->Listener
->Up
[1];
462 values
[5] = (ALint
)context
->Listener
->Up
[2];
466 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
470 ReadUnlock(&context
->PropLock
);
471 ALCcontext_DecRef(context
);
475 void UpdateListenerProps(ALCcontext
*context
)
477 ALlistener
*listener
= context
->Listener
;
478 struct ALlistenerProps
*props
;
480 /* Get an unused proprty container, or allocate a new one as needed. */
481 props
= ATOMIC_LOAD(&listener
->FreeList
, almemory_order_acquire
);
483 props
= al_calloc(16, sizeof(*props
));
486 struct ALlistenerProps
*next
;
488 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
489 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps
*,
490 &listener
->FreeList
, &props
, next
, almemory_order_seq_cst
,
491 almemory_order_consume
) == 0);
494 /* Copy in current property values. */
495 ATOMIC_STORE(&props
->Position
[0], listener
->Position
[0], almemory_order_relaxed
);
496 ATOMIC_STORE(&props
->Position
[1], listener
->Position
[1], almemory_order_relaxed
);
497 ATOMIC_STORE(&props
->Position
[2], listener
->Position
[2], almemory_order_relaxed
);
499 ATOMIC_STORE(&props
->Velocity
[0], listener
->Velocity
[0], almemory_order_relaxed
);
500 ATOMIC_STORE(&props
->Velocity
[1], listener
->Velocity
[1], almemory_order_relaxed
);
501 ATOMIC_STORE(&props
->Velocity
[2], listener
->Velocity
[2], almemory_order_relaxed
);
503 ATOMIC_STORE(&props
->Forward
[0], listener
->Forward
[0], almemory_order_relaxed
);
504 ATOMIC_STORE(&props
->Forward
[1], listener
->Forward
[1], almemory_order_relaxed
);
505 ATOMIC_STORE(&props
->Forward
[2], listener
->Forward
[2], almemory_order_relaxed
);
506 ATOMIC_STORE(&props
->Up
[0], listener
->Up
[0], almemory_order_relaxed
);
507 ATOMIC_STORE(&props
->Up
[1], listener
->Up
[1], almemory_order_relaxed
);
508 ATOMIC_STORE(&props
->Up
[2], listener
->Up
[2], almemory_order_relaxed
);
510 ATOMIC_STORE(&props
->Gain
, listener
->Gain
, almemory_order_relaxed
);
511 ATOMIC_STORE(&props
->MetersPerUnit
, listener
->MetersPerUnit
, almemory_order_relaxed
);
513 ATOMIC_STORE(&props
->DopplerFactor
, context
->DopplerFactor
, almemory_order_relaxed
);
514 ATOMIC_STORE(&props
->DopplerVelocity
, context
->DopplerVelocity
, almemory_order_relaxed
);
515 ATOMIC_STORE(&props
->SpeedOfSound
, context
->SpeedOfSound
, almemory_order_relaxed
);
517 ATOMIC_STORE(&props
->SourceDistanceModel
, context
->SourceDistanceModel
,
518 almemory_order_relaxed
);
519 ATOMIC_STORE(&props
->DistanceModel
, context
->DistanceModel
, almemory_order_relaxed
);
521 /* Set the new container for updating internal parameters. */
522 props
= ATOMIC_EXCHANGE(struct ALlistenerProps
*, &listener
->Update
, props
, almemory_order_acq_rel
);
525 /* If there was an unused update container, put it back in the
528 struct ALlistenerProps
*first
= ATOMIC_LOAD(&listener
->FreeList
);
530 ATOMIC_STORE(&props
->next
, first
, almemory_order_relaxed
);
531 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps
*,
532 &listener
->FreeList
, &first
, props
) == 0);