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
24 #include "alcontext.h"
27 #include "alListener.h"
30 #define DO_UPDATEPROPS() do { \
31 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
32 UpdateListenerProps(context); \
34 ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\
38 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
43 context
= GetContextRef();
46 listener
= &context
->Listener
;
47 almtx_lock(&context
->PropLock
);
51 if(!(value
>= 0.0f
&& isfinite(value
)))
52 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener gain out of range");
53 listener
->Gain
= value
;
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
);
64 ATOMIC_STORE(&context
->PropsClean
, AL_FALSE
, almemory_order_release
);
68 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float property");
72 almtx_unlock(&context
->PropLock
);
73 ALCcontext_DecRef(context
);
77 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
82 context
= GetContextRef();
85 listener
= &context
->Listener
;
86 almtx_lock(&context
->PropLock
);
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
;
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
;
108 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-float property");
112 almtx_unlock(&context
->PropLock
);
113 ALCcontext_DecRef(context
);
117 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
119 ALlistener
*listener
;
127 case AL_METERS_PER_UNIT
:
128 alListenerf(param
, values
[0]);
133 alListener3f(param
, values
[0], values
[1], values
[2]);
138 context
= GetContextRef();
141 listener
= &context
->Listener
;
142 almtx_lock(&context
->PropLock
);
143 if(!values
) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "NULL pointer");
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");
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 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float-vector property");
165 almtx_unlock(&context
->PropLock
);
166 ALCcontext_DecRef(context
);
170 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
174 context
= GetContextRef();
177 almtx_lock(&context
->PropLock
);
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
)
197 alListener3f(param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
201 context
= GetContextRef();
204 almtx_lock(&context
->PropLock
);
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
)
227 alListener3f(param
, (ALfloat
)values
[0], (ALfloat
)values
[1], (ALfloat
)values
[2]);
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
);
242 context
= GetContextRef();
245 almtx_lock(&context
->PropLock
);
247 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
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
)
263 context
= GetContextRef();
266 almtx_lock(&context
->PropLock
);
268 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
272 *value
= context
->Listener
.Gain
;
275 case AL_METERS_PER_UNIT
:
276 *value
= context
->MetersPerUnit
;
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
)
292 context
= GetContextRef();
295 almtx_lock(&context
->PropLock
);
296 if(!value1
|| !value2
|| !value3
)
297 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
301 *value1
= context
->Listener
.Position
[0];
302 *value2
= context
->Listener
.Position
[1];
303 *value3
= context
->Listener
.Position
[2];
307 *value1
= context
->Listener
.Velocity
[0];
308 *value2
= context
->Listener
.Velocity
[1];
309 *value3
= context
->Listener
.Velocity
[2];
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
)
328 case AL_METERS_PER_UNIT
:
329 alGetListenerf(param
, values
);
334 alGetListener3f(param
, values
+0, values
+1, values
+2);
338 context
= GetContextRef();
341 almtx_lock(&context
->PropLock
);
343 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
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];
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
)
369 context
= GetContextRef();
372 almtx_lock(&context
->PropLock
);
374 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
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
)
390 context
= GetContextRef();
393 almtx_lock(&context
->PropLock
);
394 if(!value1
|| !value2
|| !value3
)
395 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
399 *value1
= (ALint
)context
->Listener
.Position
[0];
400 *value2
= (ALint
)context
->Listener
.Position
[1];
401 *value3
= (ALint
)context
->Listener
.Position
[2];
405 *value1
= (ALint
)context
->Listener
.Velocity
[0];
406 *value2
= (ALint
)context
->Listener
.Velocity
[1];
407 *value3
= (ALint
)context
->Listener
.Velocity
[2];
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
)
427 alGetListener3i(param
, values
+0, values
+1, values
+2);
431 context
= GetContextRef();
434 almtx_lock(&context
->PropLock
);
436 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
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];
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
);
466 props
= static_cast<ALlistenerProps
*>(al_calloc(16, sizeof(*props
)));
469 struct ALlistenerProps
*next
;
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
);
498 /* If there was an unused update container, put it back in the
501 AtomicReplaceHead(context
->FreeListenerProps
, props
);