Limit the dry and wet path filter gains to -60dB
[openal-soft.git] / OpenAL32 / alListener.c
blobd117c0ca29f57a8820825dc1aab7751cf92b5ae9
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 "AL/alc.h"
25 #include "alError.h"
26 #include "alListener.h"
27 #include "alSource.h"
29 AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
31 ALCcontext *context;
33 context = GetContextRef();
34 if(!context) return;
36 WriteLock(&context->PropLock);
37 switch(param)
39 case AL_GAIN:
40 if(!(value >= 0.0f && isfinite(value)))
41 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
42 context->Listener->Gain = value;
43 break;
45 case AL_METERS_PER_UNIT:
46 if(!(value >= 0.0f && isfinite(value)))
47 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
48 context->Listener->MetersPerUnit = value;
49 break;
51 default:
52 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
54 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
55 UpdateListenerProps(context);
57 done:
58 WriteUnlock(&context->PropLock);
59 ALCcontext_DecRef(context);
63 AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
65 ALCcontext *context;
67 context = GetContextRef();
68 if(!context) return;
70 WriteLock(&context->PropLock);
71 switch(param)
73 case AL_POSITION:
74 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
75 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
76 context->Listener->Position[0] = value1;
77 context->Listener->Position[1] = value2;
78 context->Listener->Position[2] = value3;
79 break;
81 case AL_VELOCITY:
82 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
83 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
84 context->Listener->Velocity[0] = value1;
85 context->Listener->Velocity[1] = value2;
86 context->Listener->Velocity[2] = value3;
87 break;
89 default:
90 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
92 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
93 UpdateListenerProps(context);
95 done:
96 WriteUnlock(&context->PropLock);
97 ALCcontext_DecRef(context);
101 AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
103 ALCcontext *context;
105 if(values)
107 switch(param)
109 case AL_GAIN:
110 case AL_METERS_PER_UNIT:
111 alListenerf(param, values[0]);
112 return;
114 case AL_POSITION:
115 case AL_VELOCITY:
116 alListener3f(param, values[0], values[1], values[2]);
117 return;
121 context = GetContextRef();
122 if(!context) return;
124 WriteLock(&context->PropLock);
125 if(!(values))
126 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
127 switch(param)
129 case AL_ORIENTATION:
130 if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
131 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
132 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
133 /* AT then UP */
134 context->Listener->Forward[0] = values[0];
135 context->Listener->Forward[1] = values[1];
136 context->Listener->Forward[2] = values[2];
137 context->Listener->Up[0] = values[3];
138 context->Listener->Up[1] = values[4];
139 context->Listener->Up[2] = values[5];
140 break;
142 default:
143 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
145 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
146 UpdateListenerProps(context);
148 done:
149 WriteUnlock(&context->PropLock);
150 ALCcontext_DecRef(context);
154 AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
156 ALCcontext *context;
158 context = GetContextRef();
159 if(!context) return;
161 WriteLock(&context->PropLock);
162 switch(param)
164 default:
165 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
167 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
168 UpdateListenerProps(context);
170 done:
171 WriteUnlock(&context->PropLock);
172 ALCcontext_DecRef(context);
176 AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
178 ALCcontext *context;
180 switch(param)
182 case AL_POSITION:
183 case AL_VELOCITY:
184 alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
185 return;
188 context = GetContextRef();
189 if(!context) return;
191 WriteLock(&context->PropLock);
192 switch(param)
194 default:
195 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
197 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
198 UpdateListenerProps(context);
200 done:
201 WriteUnlock(&context->PropLock);
202 ALCcontext_DecRef(context);
206 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
208 ALCcontext *context;
210 if(values)
212 ALfloat fvals[6];
213 switch(param)
215 case AL_POSITION:
216 case AL_VELOCITY:
217 alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
218 return;
220 case AL_ORIENTATION:
221 fvals[0] = (ALfloat)values[0];
222 fvals[1] = (ALfloat)values[1];
223 fvals[2] = (ALfloat)values[2];
224 fvals[3] = (ALfloat)values[3];
225 fvals[4] = (ALfloat)values[4];
226 fvals[5] = (ALfloat)values[5];
227 alListenerfv(param, fvals);
228 return;
232 context = GetContextRef();
233 if(!context) return;
235 WriteLock(&context->PropLock);
236 if(!(values))
237 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
238 switch(param)
240 default:
241 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
243 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
244 UpdateListenerProps(context);
246 done:
247 WriteUnlock(&context->PropLock);
248 ALCcontext_DecRef(context);
252 AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
254 ALCcontext *context;
256 context = GetContextRef();
257 if(!context) return;
259 ReadLock(&context->PropLock);
260 if(!(value))
261 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
262 switch(param)
264 case AL_GAIN:
265 *value = context->Listener->Gain;
266 break;
268 case AL_METERS_PER_UNIT:
269 *value = context->Listener->MetersPerUnit;
270 break;
272 default:
273 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
276 done:
277 ReadUnlock(&context->PropLock);
278 ALCcontext_DecRef(context);
282 AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
284 ALCcontext *context;
286 context = GetContextRef();
287 if(!context) return;
289 ReadLock(&context->PropLock);
290 if(!(value1 && value2 && value3))
291 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
292 switch(param)
294 case AL_POSITION:
295 *value1 = context->Listener->Position[0];
296 *value2 = context->Listener->Position[1];
297 *value3 = context->Listener->Position[2];
298 break;
300 case AL_VELOCITY:
301 *value1 = context->Listener->Velocity[0];
302 *value2 = context->Listener->Velocity[1];
303 *value3 = context->Listener->Velocity[2];
304 break;
306 default:
307 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
310 done:
311 ReadUnlock(&context->PropLock);
312 ALCcontext_DecRef(context);
316 AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
318 ALCcontext *context;
320 switch(param)
322 case AL_GAIN:
323 case AL_METERS_PER_UNIT:
324 alGetListenerf(param, values);
325 return;
327 case AL_POSITION:
328 case AL_VELOCITY:
329 alGetListener3f(param, values+0, values+1, values+2);
330 return;
333 context = GetContextRef();
334 if(!context) return;
336 ReadLock(&context->PropLock);
337 if(!(values))
338 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
339 switch(param)
341 case AL_ORIENTATION:
342 // AT then UP
343 values[0] = context->Listener->Forward[0];
344 values[1] = context->Listener->Forward[1];
345 values[2] = context->Listener->Forward[2];
346 values[3] = context->Listener->Up[0];
347 values[4] = context->Listener->Up[1];
348 values[5] = context->Listener->Up[2];
349 break;
351 default:
352 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
355 done:
356 ReadUnlock(&context->PropLock);
357 ALCcontext_DecRef(context);
361 AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
363 ALCcontext *context;
365 context = GetContextRef();
366 if(!context) return;
368 ReadLock(&context->PropLock);
369 if(!(value))
370 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
371 switch(param)
373 default:
374 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
377 done:
378 ReadUnlock(&context->PropLock);
379 ALCcontext_DecRef(context);
383 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
385 ALCcontext *context;
387 context = GetContextRef();
388 if(!context) return;
390 ReadLock(&context->PropLock);
391 if(!(value1 && value2 && value3))
392 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
393 switch (param)
395 case AL_POSITION:
396 *value1 = (ALint)context->Listener->Position[0];
397 *value2 = (ALint)context->Listener->Position[1];
398 *value3 = (ALint)context->Listener->Position[2];
399 break;
401 case AL_VELOCITY:
402 *value1 = (ALint)context->Listener->Velocity[0];
403 *value2 = (ALint)context->Listener->Velocity[1];
404 *value3 = (ALint)context->Listener->Velocity[2];
405 break;
407 default:
408 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
411 done:
412 ReadUnlock(&context->PropLock);
413 ALCcontext_DecRef(context);
417 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
419 ALCcontext *context;
421 switch(param)
423 case AL_POSITION:
424 case AL_VELOCITY:
425 alGetListener3i(param, values+0, values+1, values+2);
426 return;
429 context = GetContextRef();
430 if(!context) return;
432 ReadLock(&context->PropLock);
433 if(!(values))
434 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
435 switch(param)
437 case AL_ORIENTATION:
438 // AT then UP
439 values[0] = (ALint)context->Listener->Forward[0];
440 values[1] = (ALint)context->Listener->Forward[1];
441 values[2] = (ALint)context->Listener->Forward[2];
442 values[3] = (ALint)context->Listener->Up[0];
443 values[4] = (ALint)context->Listener->Up[1];
444 values[5] = (ALint)context->Listener->Up[2];
445 break;
447 default:
448 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
451 done:
452 ReadUnlock(&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(&listener->FreeList, 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(&listener->FreeList, &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;
492 props->MetersPerUnit = listener->MetersPerUnit;
494 props->DopplerFactor = context->DopplerFactor;
495 props->DopplerVelocity = context->DopplerVelocity;
496 props->SpeedOfSound = context->SpeedOfSound;
498 props->SourceDistanceModel = context->SourceDistanceModel;
499 props->DistanceModel = context->DistanceModel;;
501 /* Set the new container for updating internal parameters. */
502 props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel);
503 if(props)
505 /* If there was an unused update container, put it back in the
506 * freelist.
508 ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &listener->FreeList, props);