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(!context->DeferUpdates.load(std::memory_order_acquire)) \
34 UpdateListenerProps(context.get()); \
36 listener.PropsClean.clear(std::memory_order_release); \
40 AL_API ALvoid AL_APIENTRY
alListenerf(ALenum param
, ALfloat value
)
42 ContextRef context
{GetContextRef()};
43 if(UNLIKELY(!context
)) return;
45 ALlistener
&listener
= context
->Listener
;
46 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
50 if(!(value
>= 0.0f
&& std::isfinite(value
)))
51 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "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_RETURN(context
.get(), AL_INVALID_VALUE
,,
59 "Listener meters per unit out of range");
60 context
->MetersPerUnit
= value
;
61 if(!context
->DeferUpdates
.load(std::memory_order_acquire
))
62 UpdateContextProps(context
.get());
64 context
->PropsClean
.clear(std::memory_order_release
);
68 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener float property");
73 AL_API ALvoid AL_APIENTRY
alListener3f(ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
75 ContextRef context
{GetContextRef()};
76 if(UNLIKELY(!context
)) return;
78 ALlistener
&listener
= context
->Listener
;
79 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
83 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
84 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Listener position out of range");
85 listener
.Position
[0] = value1
;
86 listener
.Position
[1] = value2
;
87 listener
.Position
[2] = value3
;
92 if(!(std::isfinite(value1
) && std::isfinite(value2
) && std::isfinite(value3
)))
93 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Listener velocity out of range");
94 listener
.Velocity
[0] = value1
;
95 listener
.Velocity
[1] = value2
;
96 listener
.Velocity
[2] = value3
;
101 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener 3-float property");
106 AL_API ALvoid AL_APIENTRY
alListenerfv(ALenum param
, const ALfloat
*values
)
113 case AL_METERS_PER_UNIT
:
114 alListenerf(param
, values
[0]);
119 alListener3f(param
, values
[0], values
[1], values
[2]);
124 ContextRef context
{GetContextRef()};
125 if(UNLIKELY(!context
)) return;
127 ALlistener
&listener
= context
->Listener
;
128 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
129 if(!values
) SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "NULL pointer");
133 if(!(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
134 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5])))
135 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Listener orientation out of range");
137 listener
.Forward
[0] = values
[0];
138 listener
.Forward
[1] = values
[1];
139 listener
.Forward
[2] = values
[2];
140 listener
.Up
[0] = values
[3];
141 listener
.Up
[1] = values
[4];
142 listener
.Up
[2] = values
[5];
147 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener float-vector property");
152 AL_API ALvoid AL_APIENTRY
alListeneri(ALenum param
, ALint
UNUSED(value
))
154 ContextRef context
{GetContextRef()};
155 if(UNLIKELY(!context
)) return;
157 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
161 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener integer property");
166 AL_API
void AL_APIENTRY
alListener3i(ALenum param
, ALint value1
, ALint value2
, ALint value3
)
172 alListener3f(param
, (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
);
176 ContextRef context
{GetContextRef()};
177 if(UNLIKELY(!context
)) return;
179 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
183 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener 3-integer property");
188 AL_API
void AL_APIENTRY
alListeneriv(ALenum param
, const ALint
*values
)
197 alListener3f(param
, (ALfloat
)values
[0], (ALfloat
)values
[1], (ALfloat
)values
[2]);
201 fvals
[0] = (ALfloat
)values
[0];
202 fvals
[1] = (ALfloat
)values
[1];
203 fvals
[2] = (ALfloat
)values
[2];
204 fvals
[3] = (ALfloat
)values
[3];
205 fvals
[4] = (ALfloat
)values
[4];
206 fvals
[5] = (ALfloat
)values
[5];
207 alListenerfv(param
, fvals
);
212 ContextRef context
{GetContextRef()};
213 if(UNLIKELY(!context
)) return;
215 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
217 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
221 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener integer-vector property");
226 AL_API ALvoid AL_APIENTRY
alGetListenerf(ALenum param
, ALfloat
*value
)
228 ContextRef context
{GetContextRef()};
229 if(UNLIKELY(!context
)) return;
231 ALlistener
&listener
= context
->Listener
;
232 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
234 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
238 *value
= listener
.Gain
;
241 case AL_METERS_PER_UNIT
:
242 *value
= context
->MetersPerUnit
;
246 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener float property");
251 AL_API ALvoid AL_APIENTRY
alGetListener3f(ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
253 ContextRef context
{GetContextRef()};
254 if(UNLIKELY(!context
)) return;
256 ALlistener
&listener
= context
->Listener
;
257 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
258 if(!value1
|| !value2
|| !value3
)
259 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
263 *value1
= listener
.Position
[0];
264 *value2
= listener
.Position
[1];
265 *value3
= listener
.Position
[2];
269 *value1
= listener
.Velocity
[0];
270 *value2
= listener
.Velocity
[1];
271 *value3
= listener
.Velocity
[2];
275 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener 3-float property");
280 AL_API ALvoid AL_APIENTRY
alGetListenerfv(ALenum param
, ALfloat
*values
)
285 case AL_METERS_PER_UNIT
:
286 alGetListenerf(param
, values
);
291 alGetListener3f(param
, values
+0, values
+1, values
+2);
295 ContextRef context
{GetContextRef()};
296 if(UNLIKELY(!context
)) return;
298 ALlistener
&listener
= context
->Listener
;
299 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
301 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
306 values
[0] = listener
.Forward
[0];
307 values
[1] = listener
.Forward
[1];
308 values
[2] = listener
.Forward
[2];
309 values
[3] = listener
.Up
[0];
310 values
[4] = listener
.Up
[1];
311 values
[5] = listener
.Up
[2];
315 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener float-vector property");
320 AL_API ALvoid AL_APIENTRY
alGetListeneri(ALenum param
, ALint
*value
)
322 ContextRef context
{GetContextRef()};
323 if(UNLIKELY(!context
)) return;
325 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
327 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
331 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener integer property");
336 AL_API
void AL_APIENTRY
alGetListener3i(ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
338 ContextRef context
{GetContextRef()};
339 if(UNLIKELY(!context
)) return;
341 ALlistener
&listener
= context
->Listener
;
342 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
343 if(!value1
|| !value2
|| !value3
)
344 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
348 *value1
= (ALint
)listener
.Position
[0];
349 *value2
= (ALint
)listener
.Position
[1];
350 *value3
= (ALint
)listener
.Position
[2];
354 *value1
= (ALint
)listener
.Velocity
[0];
355 *value2
= (ALint
)listener
.Velocity
[1];
356 *value3
= (ALint
)listener
.Velocity
[2];
360 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener 3-integer property");
365 AL_API
void AL_APIENTRY
alGetListeneriv(ALenum param
, ALint
* values
)
371 alGetListener3i(param
, values
+0, values
+1, values
+2);
375 ContextRef context
{GetContextRef()};
376 if(UNLIKELY(!context
)) return;
378 ALlistener
&listener
= context
->Listener
;
379 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
381 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
386 values
[0] = (ALint
)listener
.Forward
[0];
387 values
[1] = (ALint
)listener
.Forward
[1];
388 values
[2] = (ALint
)listener
.Forward
[2];
389 values
[3] = (ALint
)listener
.Up
[0];
390 values
[4] = (ALint
)listener
.Up
[1];
391 values
[5] = (ALint
)listener
.Up
[2];
395 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid listener integer-vector property");
400 void UpdateListenerProps(ALCcontext
*context
)
402 /* Get an unused proprty container, or allocate a new one as needed. */
403 ALlistenerProps
*props
{context
->FreeListenerProps
.load(std::memory_order_acquire
)};
405 props
= static_cast<ALlistenerProps
*>(al_calloc(16, sizeof(*props
)));
408 struct ALlistenerProps
*next
;
410 next
= props
->next
.load(std::memory_order_relaxed
);
411 } while(context
->FreeListenerProps
.compare_exchange_weak(props
, next
,
412 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
415 /* Copy in current property values. */
416 ALlistener
&listener
= context
->Listener
;
417 props
->Position
[0] = listener
.Position
[0];
418 props
->Position
[1] = listener
.Position
[1];
419 props
->Position
[2] = listener
.Position
[2];
421 props
->Velocity
[0] = listener
.Velocity
[0];
422 props
->Velocity
[1] = listener
.Velocity
[1];
423 props
->Velocity
[2] = listener
.Velocity
[2];
425 props
->Forward
[0] = listener
.Forward
[0];
426 props
->Forward
[1] = listener
.Forward
[1];
427 props
->Forward
[2] = listener
.Forward
[2];
428 props
->Up
[0] = listener
.Up
[0];
429 props
->Up
[1] = listener
.Up
[1];
430 props
->Up
[2] = listener
.Up
[2];
432 props
->Gain
= listener
.Gain
;
434 /* Set the new container for updating internal parameters. */
435 props
= listener
.Update
.exchange(props
, std::memory_order_acq_rel
);
438 /* If there was an unused update container, put it back in the
441 AtomicReplaceHead(context
->FreeListenerProps
, props
);