Fix the reverb panning behavior to better fit the spec
[openal-soft.git] / OpenAL32 / alListener.c
blobf1ac3ff4a43888a16d777eb9591354b2272ff24e
1 /**
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
21 #include "config.h"
23 #include "alMain.h"
24 #include "alu.h"
25 #include "alError.h"
26 #include "alListener.h"
27 #include "alSource.h"
29 #define DO_UPDATEPROPS() do { \
30 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
31 UpdateListenerProps(context); \
32 else \
33 ATOMIC_FLAG_CLEAR(&listener->PropsClean, almemory_order_release); \
34 } while(0)
37 AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
39 ALlistener *listener;
40 ALCcontext *context;
42 context = GetContextRef();
43 if(!context) return;
45 listener = context->Listener;
46 almtx_lock(&context->PropLock);
47 switch(param)
49 case AL_GAIN:
50 if(!(value >= 0.0f && isfinite(value)))
51 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range");
52 listener->Gain = value;
53 DO_UPDATEPROPS();
54 break;
56 case AL_METERS_PER_UNIT:
57 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
58 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range");
59 context->MetersPerUnit = value;
60 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
61 UpdateContextProps(context);
62 else
63 ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release);
64 break;
66 default:
67 alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
70 done:
71 almtx_unlock(&context->PropLock);
72 ALCcontext_DecRef(context);
76 AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
78 ALlistener *listener;
79 ALCcontext *context;
81 context = GetContextRef();
82 if(!context) return;
84 listener = context->Listener;
85 almtx_lock(&context->PropLock);
86 switch(param)
88 case AL_POSITION:
89 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
90 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range");
91 listener->Position[0] = value1;
92 listener->Position[1] = value2;
93 listener->Position[2] = value3;
94 DO_UPDATEPROPS();
95 break;
97 case AL_VELOCITY:
98 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
99 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range");
100 listener->Velocity[0] = value1;
101 listener->Velocity[1] = value2;
102 listener->Velocity[2] = value3;
103 DO_UPDATEPROPS();
104 break;
106 default:
107 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
110 done:
111 almtx_unlock(&context->PropLock);
112 ALCcontext_DecRef(context);
116 AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
118 ALlistener *listener;
119 ALCcontext *context;
121 if(values)
123 switch(param)
125 case AL_GAIN:
126 case AL_METERS_PER_UNIT:
127 alListenerf(param, values[0]);
128 return;
130 case AL_POSITION:
131 case AL_VELOCITY:
132 alListener3f(param, values[0], values[1], values[2]);
133 return;
137 context = GetContextRef();
138 if(!context) return;
140 listener = context->Listener;
141 almtx_lock(&context->PropLock);
142 if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
143 switch(param)
145 case AL_ORIENTATION:
146 if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
147 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
148 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range");
149 /* AT then UP */
150 listener->Forward[0] = values[0];
151 listener->Forward[1] = values[1];
152 listener->Forward[2] = values[2];
153 listener->Up[0] = values[3];
154 listener->Up[1] = values[4];
155 listener->Up[2] = values[5];
156 DO_UPDATEPROPS();
157 break;
159 default:
160 alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
163 done:
164 almtx_unlock(&context->PropLock);
165 ALCcontext_DecRef(context);
169 AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
171 ALCcontext *context;
173 context = GetContextRef();
174 if(!context) return;
176 almtx_lock(&context->PropLock);
177 switch(param)
179 default:
180 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
182 almtx_unlock(&context->PropLock);
184 ALCcontext_DecRef(context);
188 AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
190 ALCcontext *context;
192 switch(param)
194 case AL_POSITION:
195 case AL_VELOCITY:
196 alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
197 return;
200 context = GetContextRef();
201 if(!context) return;
203 almtx_lock(&context->PropLock);
204 switch(param)
206 default:
207 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
209 almtx_unlock(&context->PropLock);
211 ALCcontext_DecRef(context);
215 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
217 ALCcontext *context;
219 if(values)
221 ALfloat fvals[6];
222 switch(param)
224 case AL_POSITION:
225 case AL_VELOCITY:
226 alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
227 return;
229 case AL_ORIENTATION:
230 fvals[0] = (ALfloat)values[0];
231 fvals[1] = (ALfloat)values[1];
232 fvals[2] = (ALfloat)values[2];
233 fvals[3] = (ALfloat)values[3];
234 fvals[4] = (ALfloat)values[4];
235 fvals[5] = (ALfloat)values[5];
236 alListenerfv(param, fvals);
237 return;
241 context = GetContextRef();
242 if(!context) return;
244 almtx_lock(&context->PropLock);
245 if(!values)
246 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
247 else switch(param)
249 default:
250 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
252 almtx_unlock(&context->PropLock);
254 ALCcontext_DecRef(context);
258 AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
260 ALCcontext *context;
262 context = GetContextRef();
263 if(!context) return;
265 almtx_lock(&context->PropLock);
266 if(!value)
267 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
268 else switch(param)
270 case AL_GAIN:
271 *value = context->Listener->Gain;
272 break;
274 case AL_METERS_PER_UNIT:
275 *value = context->MetersPerUnit;
276 break;
278 default:
279 alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
281 almtx_unlock(&context->PropLock);
283 ALCcontext_DecRef(context);
287 AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
289 ALCcontext *context;
291 context = GetContextRef();
292 if(!context) return;
294 almtx_lock(&context->PropLock);
295 if(!value1 || !value2 || !value3)
296 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
297 else switch(param)
299 case AL_POSITION:
300 *value1 = context->Listener->Position[0];
301 *value2 = context->Listener->Position[1];
302 *value3 = context->Listener->Position[2];
303 break;
305 case AL_VELOCITY:
306 *value1 = context->Listener->Velocity[0];
307 *value2 = context->Listener->Velocity[1];
308 *value3 = context->Listener->Velocity[2];
309 break;
311 default:
312 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
314 almtx_unlock(&context->PropLock);
316 ALCcontext_DecRef(context);
320 AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
322 ALCcontext *context;
324 switch(param)
326 case AL_GAIN:
327 case AL_METERS_PER_UNIT:
328 alGetListenerf(param, values);
329 return;
331 case AL_POSITION:
332 case AL_VELOCITY:
333 alGetListener3f(param, values+0, values+1, values+2);
334 return;
337 context = GetContextRef();
338 if(!context) return;
340 almtx_lock(&context->PropLock);
341 if(!values)
342 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
343 else switch(param)
345 case AL_ORIENTATION:
346 // AT then UP
347 values[0] = context->Listener->Forward[0];
348 values[1] = context->Listener->Forward[1];
349 values[2] = context->Listener->Forward[2];
350 values[3] = context->Listener->Up[0];
351 values[4] = context->Listener->Up[1];
352 values[5] = context->Listener->Up[2];
353 break;
355 default:
356 alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
358 almtx_unlock(&context->PropLock);
360 ALCcontext_DecRef(context);
364 AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
366 ALCcontext *context;
368 context = GetContextRef();
369 if(!context) return;
371 almtx_lock(&context->PropLock);
372 if(!value)
373 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
374 else switch(param)
376 default:
377 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
379 almtx_unlock(&context->PropLock);
381 ALCcontext_DecRef(context);
385 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
387 ALCcontext *context;
389 context = GetContextRef();
390 if(!context) return;
392 almtx_lock(&context->PropLock);
393 if(!value1 || !value2 || !value3)
394 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
395 else switch(param)
397 case AL_POSITION:
398 *value1 = (ALint)context->Listener->Position[0];
399 *value2 = (ALint)context->Listener->Position[1];
400 *value3 = (ALint)context->Listener->Position[2];
401 break;
403 case AL_VELOCITY:
404 *value1 = (ALint)context->Listener->Velocity[0];
405 *value2 = (ALint)context->Listener->Velocity[1];
406 *value3 = (ALint)context->Listener->Velocity[2];
407 break;
409 default:
410 alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
412 almtx_unlock(&context->PropLock);
414 ALCcontext_DecRef(context);
418 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
420 ALCcontext *context;
422 switch(param)
424 case AL_POSITION:
425 case AL_VELOCITY:
426 alGetListener3i(param, values+0, values+1, values+2);
427 return;
430 context = GetContextRef();
431 if(!context) return;
433 almtx_lock(&context->PropLock);
434 if(!values)
435 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
436 else switch(param)
438 case AL_ORIENTATION:
439 // AT then UP
440 values[0] = (ALint)context->Listener->Forward[0];
441 values[1] = (ALint)context->Listener->Forward[1];
442 values[2] = (ALint)context->Listener->Forward[2];
443 values[3] = (ALint)context->Listener->Up[0];
444 values[4] = (ALint)context->Listener->Up[1];
445 values[5] = (ALint)context->Listener->Up[2];
446 break;
448 default:
449 alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
451 almtx_unlock(&context->PropLock);
453 ALCcontext_DecRef(context);
457 void UpdateListenerProps(ALCcontext *context)
459 ALlistener *listener = context->Listener;
460 struct ALlistenerProps *props;
462 /* Get an unused proprty container, or allocate a new one as needed. */
463 props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire);
464 if(!props)
465 props = al_calloc(16, sizeof(*props));
466 else
468 struct ALlistenerProps *next;
469 do {
470 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
471 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next,
472 almemory_order_seq_cst, almemory_order_acquire) == 0);
475 /* Copy in current property values. */
476 props->Position[0] = listener->Position[0];
477 props->Position[1] = listener->Position[1];
478 props->Position[2] = listener->Position[2];
480 props->Velocity[0] = listener->Velocity[0];
481 props->Velocity[1] = listener->Velocity[1];
482 props->Velocity[2] = listener->Velocity[2];
484 props->Forward[0] = listener->Forward[0];
485 props->Forward[1] = listener->Forward[1];
486 props->Forward[2] = listener->Forward[2];
487 props->Up[0] = listener->Up[0];
488 props->Up[1] = listener->Up[1];
489 props->Up[2] = listener->Up[2];
491 props->Gain = listener->Gain;
493 /* Set the new container for updating internal parameters. */
494 props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel);
495 if(props)
497 /* If there was an unused update container, put it back in the
498 * freelist.
500 ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props);