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 "alcontext.h"
29 #include "alListener.h"
32 #define DO_UPDATEPROPS() do { \
33 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
34 UpdateListenerProps(context); \
36 ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\
40 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
45 context
= GetContextRef();
48 listener
= &context
->Listener
;
49 almtx_lock(&context
->PropLock
);
53 if(!(value
>= 0.0f
&& std::isfinite(value
)))
54 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener gain out of range");
55 listener
->Gain
= value
;
59 case AL_METERS_PER_UNIT
:
60 if(!(value
>= AL_MIN_METERS_PER_UNIT
&& value
<= AL_MAX_METERS_PER_UNIT
))
61 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener meters per unit out of range");
62 context
->MetersPerUnit
= value
;
63 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
64 UpdateContextProps(context
);
66 ATOMIC_STORE(&context
->PropsClean
, AL_FALSE
, almemory_order_release
);
70 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float property");
74 almtx_unlock(&context
->PropLock
);
75 ALCcontext_DecRef(context
);
79 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
84 context
= GetContextRef();
87 listener
= &context
->Listener
;
88 almtx_lock(&context
->PropLock
);
92 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
93 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener position out of range");
94 listener
->Position
[0] = value1
;
95 listener
->Position
[1] = value2
;
96 listener
->Position
[2] = value3
;
101 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
102 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener velocity out of range");
103 listener
->Velocity
[0] = value1
;
104 listener
->Velocity
[1] = value2
;
105 listener
->Velocity
[2] = value3
;
110 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-float property");
114 almtx_unlock(&context
->PropLock
);
115 ALCcontext_DecRef(context
);
119 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
121 ALlistener
*listener
;
129 case AL_METERS_PER_UNIT
:
130 alListenerf(param
, values
[0]);
135 alListener3f(param
, values
[0], values
[1], values
[2]);
140 context
= GetContextRef();
143 listener
= &context
->Listener
;
144 almtx_lock(&context
->PropLock
);
145 if(!values
) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "NULL pointer");
149 if(!(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
150 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5])))
151 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Listener orientation out of range");
153 listener
->Forward
[0] = values
[0];
154 listener
->Forward
[1] = values
[1];
155 listener
->Forward
[2] = values
[2];
156 listener
->Up
[0] = values
[3];
157 listener
->Up
[1] = values
[4];
158 listener
->Up
[2] = values
[5];
163 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float-vector property");
167 almtx_unlock(&context
->PropLock
);
168 ALCcontext_DecRef(context
);
172 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
176 context
= GetContextRef();
179 almtx_lock(&context
->PropLock
);
183 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer property");
185 almtx_unlock(&context
->PropLock
);
187 ALCcontext_DecRef(context
);
191 AL_API
void AL_APIENTRY
alListener3i(ALenum param
, ALint value1
, ALint value2
, ALint value3
)
199 alListener3f(param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
203 context
= GetContextRef();
206 almtx_lock(&context
->PropLock
);
210 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-integer property");
212 almtx_unlock(&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 almtx_lock(&context
->PropLock
);
249 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
253 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer-vector property");
255 almtx_unlock(&context
->PropLock
);
257 ALCcontext_DecRef(context
);
261 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
265 context
= GetContextRef();
268 almtx_lock(&context
->PropLock
);
270 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
274 *value
= context
->Listener
.Gain
;
277 case AL_METERS_PER_UNIT
:
278 *value
= context
->MetersPerUnit
;
282 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float property");
284 almtx_unlock(&context
->PropLock
);
286 ALCcontext_DecRef(context
);
290 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
294 context
= GetContextRef();
297 almtx_lock(&context
->PropLock
);
298 if(!value1
|| !value2
|| !value3
)
299 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
303 *value1
= context
->Listener
.Position
[0];
304 *value2
= context
->Listener
.Position
[1];
305 *value3
= context
->Listener
.Position
[2];
309 *value1
= context
->Listener
.Velocity
[0];
310 *value2
= context
->Listener
.Velocity
[1];
311 *value3
= context
->Listener
.Velocity
[2];
315 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-float property");
317 almtx_unlock(&context
->PropLock
);
319 ALCcontext_DecRef(context
);
323 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
330 case AL_METERS_PER_UNIT
:
331 alGetListenerf(param
, values
);
336 alGetListener3f(param
, values
+0, values
+1, values
+2);
340 context
= GetContextRef();
343 almtx_lock(&context
->PropLock
);
345 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
350 values
[0] = context
->Listener
.Forward
[0];
351 values
[1] = context
->Listener
.Forward
[1];
352 values
[2] = context
->Listener
.Forward
[2];
353 values
[3] = context
->Listener
.Up
[0];
354 values
[4] = context
->Listener
.Up
[1];
355 values
[5] = context
->Listener
.Up
[2];
359 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener float-vector property");
361 almtx_unlock(&context
->PropLock
);
363 ALCcontext_DecRef(context
);
367 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
371 context
= GetContextRef();
374 almtx_lock(&context
->PropLock
);
376 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
380 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer property");
382 almtx_unlock(&context
->PropLock
);
384 ALCcontext_DecRef(context
);
388 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
392 context
= GetContextRef();
395 almtx_lock(&context
->PropLock
);
396 if(!value1
|| !value2
|| !value3
)
397 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
401 *value1
= (ALint
)context
->Listener
.Position
[0];
402 *value2
= (ALint
)context
->Listener
.Position
[1];
403 *value3
= (ALint
)context
->Listener
.Position
[2];
407 *value1
= (ALint
)context
->Listener
.Velocity
[0];
408 *value2
= (ALint
)context
->Listener
.Velocity
[1];
409 *value3
= (ALint
)context
->Listener
.Velocity
[2];
413 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener 3-integer property");
415 almtx_unlock(&context
->PropLock
);
417 ALCcontext_DecRef(context
);
421 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
429 alGetListener3i(param
, values
+0, values
+1, values
+2);
433 context
= GetContextRef();
436 almtx_lock(&context
->PropLock
);
438 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
443 values
[0] = (ALint
)context
->Listener
.Forward
[0];
444 values
[1] = (ALint
)context
->Listener
.Forward
[1];
445 values
[2] = (ALint
)context
->Listener
.Forward
[2];
446 values
[3] = (ALint
)context
->Listener
.Up
[0];
447 values
[4] = (ALint
)context
->Listener
.Up
[1];
448 values
[5] = (ALint
)context
->Listener
.Up
[2];
452 alSetError(context
, AL_INVALID_ENUM
, "Invalid listener integer-vector property");
454 almtx_unlock(&context
->PropLock
);
456 ALCcontext_DecRef(context
);
460 void UpdateListenerProps(ALCcontext
*context
)
462 ALlistener
*listener
{&context
->Listener
};
463 struct ALlistenerProps
*props
;
465 /* Get an unused proprty container, or allocate a new one as needed. */
466 props
= context
->FreeListenerProps
.load(std::memory_order_acquire
);
468 props
= static_cast<ALlistenerProps
*>(al_calloc(16, sizeof(*props
)));
471 struct ALlistenerProps
*next
;
473 next
= props
->next
.load(std::memory_order_relaxed
);
474 } while(context
->FreeListenerProps
.compare_exchange_weak(props
, next
,
475 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
478 /* Copy in current property values. */
479 props
->Position
[0] = listener
->Position
[0];
480 props
->Position
[1] = listener
->Position
[1];
481 props
->Position
[2] = listener
->Position
[2];
483 props
->Velocity
[0] = listener
->Velocity
[0];
484 props
->Velocity
[1] = listener
->Velocity
[1];
485 props
->Velocity
[2] = listener
->Velocity
[2];
487 props
->Forward
[0] = listener
->Forward
[0];
488 props
->Forward
[1] = listener
->Forward
[1];
489 props
->Forward
[2] = listener
->Forward
[2];
490 props
->Up
[0] = listener
->Up
[0];
491 props
->Up
[1] = listener
->Up
[1];
492 props
->Up
[2] = listener
->Up
[2];
494 props
->Gain
= listener
->Gain
;
496 /* Set the new container for updating internal parameters. */
497 props
= listener
->Update
.exchange(props
, std::memory_order_acq_rel
);
500 /* If there was an unused update container, put it back in the
503 AtomicReplaceHead(context
->FreeListenerProps
, props
);