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
32 #include "alcontext.h"
36 #include "opthelpers.h"
39 #define DO_UPDATEPROPS() do { \
40 if(!context->mDeferUpdates.load(std::memory_order_acquire)) \
41 UpdateListenerProps(context.get()); \
43 listener.PropsClean.clear(std::memory_order_release); \
47 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
50 ContextRef context
{GetContextRef()};
51 if UNLIKELY(!context
) return;
53 ALlistener
&listener
= context
->mListener
;
54 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
58 if(!(value
>= 0.0f
&& std::isfinite(value
)))
59 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Listener gain out of range");
60 listener
.Gain
= value
;
64 case AL_METERS_PER_UNIT
:
65 if(!(value
>= AL_MIN_METERS_PER_UNIT
&& value
<= AL_MAX_METERS_PER_UNIT
))
66 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Listener meters per unit out of range");
67 listener
.mMetersPerUnit
= value
;
72 context
->setError(AL_INVALID_ENUM
, "Invalid listener float property");
77 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
80 ContextRef context
{GetContextRef()};
81 if UNLIKELY(!context
) return;
83 ALlistener
&listener
= context
->mListener
;
84 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
88 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
89 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Listener position out of range");
90 listener
.Position
[0] = value1
;
91 listener
.Position
[1] = value2
;
92 listener
.Position
[2] = value3
;
97 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
98 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Listener velocity out of range");
99 listener
.Velocity
[0] = value1
;
100 listener
.Velocity
[1] = value2
;
101 listener
.Velocity
[2] = value3
;
106 context
->setError(AL_INVALID_ENUM
, "Invalid listener 3-float property");
111 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
119 case AL_METERS_PER_UNIT
:
120 alListenerf(param
, values
[0]);
125 alListener3f(param
, values
[0], values
[1], values
[2]);
130 ContextRef context
{GetContextRef()};
131 if UNLIKELY(!context
) return;
133 ALlistener
&listener
= context
->mListener
;
134 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
135 if(!values
) SETERR_RETURN(context
, AL_INVALID_VALUE
,, "NULL pointer");
139 if(!(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
140 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5])))
141 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Listener orientation out of range");
143 listener
.OrientAt
[0] = values
[0];
144 listener
.OrientAt
[1] = values
[1];
145 listener
.OrientAt
[2] = values
[2];
146 listener
.OrientUp
[0] = values
[3];
147 listener
.OrientUp
[1] = values
[4];
148 listener
.OrientUp
[2] = values
[5];
153 context
->setError(AL_INVALID_ENUM
, "Invalid listener float-vector property");
159 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
/*value*/)
162 ContextRef context
{GetContextRef()};
163 if UNLIKELY(!context
) return;
165 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
169 context
->setError(AL_INVALID_ENUM
, "Invalid listener integer property");
174 AL_API
void AL_APIENTRY
alListener3i(ALenum param
, ALint value1
, ALint value2
, ALint value3
)
181 alListener3f(param
, static_cast<ALfloat
>(value1
), static_cast<ALfloat
>(value2
), static_cast<ALfloat
>(value3
));
185 ContextRef context
{GetContextRef()};
186 if UNLIKELY(!context
) return;
188 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
192 context
->setError(AL_INVALID_ENUM
, "Invalid listener 3-integer property");
197 AL_API
void AL_APIENTRY
alListeneriv(ALenum param
, const ALint
*values
)
207 alListener3f(param
, static_cast<ALfloat
>(values
[0]), static_cast<ALfloat
>(values
[1]), static_cast<ALfloat
>(values
[2]));
211 fvals
[0] = static_cast<ALfloat
>(values
[0]);
212 fvals
[1] = static_cast<ALfloat
>(values
[1]);
213 fvals
[2] = static_cast<ALfloat
>(values
[2]);
214 fvals
[3] = static_cast<ALfloat
>(values
[3]);
215 fvals
[4] = static_cast<ALfloat
>(values
[4]);
216 fvals
[5] = static_cast<ALfloat
>(values
[5]);
217 alListenerfv(param
, fvals
);
222 ContextRef context
{GetContextRef()};
223 if UNLIKELY(!context
) return;
225 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
227 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
231 context
->setError(AL_INVALID_ENUM
, "Invalid listener integer-vector property");
237 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
240 ContextRef context
{GetContextRef()};
241 if UNLIKELY(!context
) return;
243 ALlistener
&listener
= context
->mListener
;
244 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
246 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
250 *value
= listener
.Gain
;
253 case AL_METERS_PER_UNIT
:
254 *value
= listener
.mMetersPerUnit
;
258 context
->setError(AL_INVALID_ENUM
, "Invalid listener float property");
263 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
266 ContextRef context
{GetContextRef()};
267 if UNLIKELY(!context
) return;
269 ALlistener
&listener
= context
->mListener
;
270 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
271 if(!value1
|| !value2
|| !value3
)
272 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
276 *value1
= listener
.Position
[0];
277 *value2
= listener
.Position
[1];
278 *value3
= listener
.Position
[2];
282 *value1
= listener
.Velocity
[0];
283 *value2
= listener
.Velocity
[1];
284 *value3
= listener
.Velocity
[2];
288 context
->setError(AL_INVALID_ENUM
, "Invalid listener 3-float property");
293 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
299 case AL_METERS_PER_UNIT
:
300 alGetListenerf(param
, values
);
305 alGetListener3f(param
, values
+0, values
+1, values
+2);
309 ContextRef context
{GetContextRef()};
310 if UNLIKELY(!context
) return;
312 ALlistener
&listener
= context
->mListener
;
313 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
315 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
320 values
[0] = listener
.OrientAt
[0];
321 values
[1] = listener
.OrientAt
[1];
322 values
[2] = listener
.OrientAt
[2];
323 values
[3] = listener
.OrientUp
[0];
324 values
[4] = listener
.OrientUp
[1];
325 values
[5] = listener
.OrientUp
[2];
329 context
->setError(AL_INVALID_ENUM
, "Invalid listener float-vector property");
335 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
338 ContextRef context
{GetContextRef()};
339 if UNLIKELY(!context
) return;
341 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
343 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
347 context
->setError(AL_INVALID_ENUM
, "Invalid listener integer property");
352 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
355 ContextRef context
{GetContextRef()};
356 if UNLIKELY(!context
) return;
358 ALlistener
&listener
= context
->mListener
;
359 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
360 if(!value1
|| !value2
|| !value3
)
361 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
365 *value1
= static_cast<ALint
>(listener
.Position
[0]);
366 *value2
= static_cast<ALint
>(listener
.Position
[1]);
367 *value3
= static_cast<ALint
>(listener
.Position
[2]);
371 *value1
= static_cast<ALint
>(listener
.Velocity
[0]);
372 *value2
= static_cast<ALint
>(listener
.Velocity
[1]);
373 *value3
= static_cast<ALint
>(listener
.Velocity
[2]);
377 context
->setError(AL_INVALID_ENUM
, "Invalid listener 3-integer property");
382 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
389 alGetListener3i(param
, values
+0, values
+1, values
+2);
393 ContextRef context
{GetContextRef()};
394 if UNLIKELY(!context
) return;
396 ALlistener
&listener
= context
->mListener
;
397 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
399 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
404 values
[0] = static_cast<ALint
>(listener
.OrientAt
[0]);
405 values
[1] = static_cast<ALint
>(listener
.OrientAt
[1]);
406 values
[2] = static_cast<ALint
>(listener
.OrientAt
[2]);
407 values
[3] = static_cast<ALint
>(listener
.OrientUp
[0]);
408 values
[4] = static_cast<ALint
>(listener
.OrientUp
[1]);
409 values
[5] = static_cast<ALint
>(listener
.OrientUp
[2]);
413 context
->setError(AL_INVALID_ENUM
, "Invalid listener integer-vector property");
419 void UpdateListenerProps(ALCcontext
*context
)
421 /* Get an unused proprty container, or allocate a new one as needed. */
422 ALlistenerProps
*props
{context
->mFreeListenerProps
.load(std::memory_order_acquire
)};
424 props
= new ALlistenerProps
{};
427 ALlistenerProps
*next
;
429 next
= props
->next
.load(std::memory_order_relaxed
);
430 } while(context
->mFreeListenerProps
.compare_exchange_weak(props
, next
,
431 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
434 /* Copy in current property values. */
435 ALlistener
&listener
= context
->mListener
;
436 props
->Position
= listener
.Position
;
437 props
->Velocity
= listener
.Velocity
;
438 props
->OrientAt
= listener
.OrientAt
;
439 props
->OrientUp
= listener
.OrientUp
;
440 props
->Gain
= listener
.Gain
;
441 props
->MetersPerUnit
= listener
.mMetersPerUnit
;
443 /* Set the new container for updating internal parameters. */
444 props
= listener
.Params
.Update
.exchange(props
, std::memory_order_acq_rel
);
447 /* If there was an unused update container, put it back in the
450 AtomicReplaceHead(context
->mFreeListenerProps
, props
);