Use floats for the listener transforms
[openal-soft.git] / OpenAL32 / alListener.c
blobc59d644b4e4efdbfe9753d1bb6a8a81eaa31142c
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))
56 UpdateListenerProps(context);
57 UpdateAllSourceProps(context);
60 done:
61 WriteUnlock(&context->PropLock);
62 ALCcontext_DecRef(context);
66 AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
68 ALCcontext *context;
70 context = GetContextRef();
71 if(!context) return;
73 WriteLock(&context->PropLock);
74 switch(param)
76 case AL_POSITION:
77 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
78 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
79 context->Listener->Position[0] = value1;
80 context->Listener->Position[1] = value2;
81 context->Listener->Position[2] = value3;
82 break;
84 case AL_VELOCITY:
85 if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
86 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
87 context->Listener->Velocity[0] = value1;
88 context->Listener->Velocity[1] = value2;
89 context->Listener->Velocity[2] = value3;
90 break;
92 default:
93 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
95 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
97 UpdateListenerProps(context);
98 UpdateAllSourceProps(context);
101 done:
102 WriteUnlock(&context->PropLock);
103 ALCcontext_DecRef(context);
107 AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
109 ALCcontext *context;
111 if(values)
113 switch(param)
115 case AL_GAIN:
116 case AL_METERS_PER_UNIT:
117 alListenerf(param, values[0]);
118 return;
120 case AL_POSITION:
121 case AL_VELOCITY:
122 alListener3f(param, values[0], values[1], values[2]);
123 return;
127 context = GetContextRef();
128 if(!context) return;
130 WriteLock(&context->PropLock);
131 if(!(values))
132 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
133 switch(param)
135 case AL_ORIENTATION:
136 if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
137 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
138 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
139 /* AT then UP */
140 context->Listener->Forward[0] = values[0];
141 context->Listener->Forward[1] = values[1];
142 context->Listener->Forward[2] = values[2];
143 context->Listener->Up[0] = values[3];
144 context->Listener->Up[1] = values[4];
145 context->Listener->Up[2] = values[5];
146 break;
148 default:
149 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
151 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
153 UpdateListenerProps(context);
154 UpdateAllSourceProps(context);
157 done:
158 WriteUnlock(&context->PropLock);
159 ALCcontext_DecRef(context);
163 AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
165 ALCcontext *context;
167 context = GetContextRef();
168 if(!context) return;
170 WriteLock(&context->PropLock);
171 switch(param)
173 default:
174 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
176 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
178 UpdateListenerProps(context);
179 UpdateAllSourceProps(context);
182 done:
183 WriteUnlock(&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 WriteLock(&context->PropLock);
204 switch(param)
206 default:
207 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
209 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
211 UpdateListenerProps(context);
212 UpdateAllSourceProps(context);
215 done:
216 WriteUnlock(&context->PropLock);
217 ALCcontext_DecRef(context);
221 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
223 ALCcontext *context;
225 if(values)
227 ALfloat fvals[6];
228 switch(param)
230 case AL_POSITION:
231 case AL_VELOCITY:
232 alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
233 return;
235 case AL_ORIENTATION:
236 fvals[0] = (ALfloat)values[0];
237 fvals[1] = (ALfloat)values[1];
238 fvals[2] = (ALfloat)values[2];
239 fvals[3] = (ALfloat)values[3];
240 fvals[4] = (ALfloat)values[4];
241 fvals[5] = (ALfloat)values[5];
242 alListenerfv(param, fvals);
243 return;
247 context = GetContextRef();
248 if(!context) return;
250 WriteLock(&context->PropLock);
251 if(!(values))
252 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
253 switch(param)
255 default:
256 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
258 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
260 UpdateListenerProps(context);
261 UpdateAllSourceProps(context);
264 done:
265 WriteUnlock(&context->PropLock);
266 ALCcontext_DecRef(context);
270 AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
272 ALCcontext *context;
274 context = GetContextRef();
275 if(!context) return;
277 ReadLock(&context->PropLock);
278 if(!(value))
279 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
280 switch(param)
282 case AL_GAIN:
283 *value = context->Listener->Gain;
284 break;
286 case AL_METERS_PER_UNIT:
287 *value = context->Listener->MetersPerUnit;
288 break;
290 default:
291 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
294 done:
295 ReadUnlock(&context->PropLock);
296 ALCcontext_DecRef(context);
300 AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
302 ALCcontext *context;
304 context = GetContextRef();
305 if(!context) return;
307 ReadLock(&context->PropLock);
308 if(!(value1 && value2 && value3))
309 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
310 switch(param)
312 case AL_POSITION:
313 *value1 = context->Listener->Position[0];
314 *value2 = context->Listener->Position[1];
315 *value3 = context->Listener->Position[2];
316 break;
318 case AL_VELOCITY:
319 *value1 = context->Listener->Velocity[0];
320 *value2 = context->Listener->Velocity[1];
321 *value3 = context->Listener->Velocity[2];
322 break;
324 default:
325 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
328 done:
329 ReadUnlock(&context->PropLock);
330 ALCcontext_DecRef(context);
334 AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
336 ALCcontext *context;
338 switch(param)
340 case AL_GAIN:
341 case AL_METERS_PER_UNIT:
342 alGetListenerf(param, values);
343 return;
345 case AL_POSITION:
346 case AL_VELOCITY:
347 alGetListener3f(param, values+0, values+1, values+2);
348 return;
351 context = GetContextRef();
352 if(!context) return;
354 ReadLock(&context->PropLock);
355 if(!(values))
356 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
357 switch(param)
359 case AL_ORIENTATION:
360 // AT then UP
361 values[0] = context->Listener->Forward[0];
362 values[1] = context->Listener->Forward[1];
363 values[2] = context->Listener->Forward[2];
364 values[3] = context->Listener->Up[0];
365 values[4] = context->Listener->Up[1];
366 values[5] = context->Listener->Up[2];
367 break;
369 default:
370 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
373 done:
374 ReadUnlock(&context->PropLock);
375 ALCcontext_DecRef(context);
379 AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
381 ALCcontext *context;
383 context = GetContextRef();
384 if(!context) return;
386 ReadLock(&context->PropLock);
387 if(!(value))
388 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
389 switch(param)
391 default:
392 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
395 done:
396 ReadUnlock(&context->PropLock);
397 ALCcontext_DecRef(context);
401 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
403 ALCcontext *context;
405 context = GetContextRef();
406 if(!context) return;
408 ReadLock(&context->PropLock);
409 if(!(value1 && value2 && value3))
410 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
411 switch (param)
413 case AL_POSITION:
414 *value1 = (ALint)context->Listener->Position[0];
415 *value2 = (ALint)context->Listener->Position[1];
416 *value3 = (ALint)context->Listener->Position[2];
417 break;
419 case AL_VELOCITY:
420 *value1 = (ALint)context->Listener->Velocity[0];
421 *value2 = (ALint)context->Listener->Velocity[1];
422 *value3 = (ALint)context->Listener->Velocity[2];
423 break;
425 default:
426 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
429 done:
430 ReadUnlock(&context->PropLock);
431 ALCcontext_DecRef(context);
435 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
437 ALCcontext *context;
439 switch(param)
441 case AL_POSITION:
442 case AL_VELOCITY:
443 alGetListener3i(param, values+0, values+1, values+2);
444 return;
447 context = GetContextRef();
448 if(!context) return;
450 ReadLock(&context->PropLock);
451 if(!(values))
452 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
453 switch(param)
455 case AL_ORIENTATION:
456 // AT then UP
457 values[0] = (ALint)context->Listener->Forward[0];
458 values[1] = (ALint)context->Listener->Forward[1];
459 values[2] = (ALint)context->Listener->Forward[2];
460 values[3] = (ALint)context->Listener->Up[0];
461 values[4] = (ALint)context->Listener->Up[1];
462 values[5] = (ALint)context->Listener->Up[2];
463 break;
465 default:
466 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
469 done:
470 ReadUnlock(&context->PropLock);
471 ALCcontext_DecRef(context);
475 void UpdateListenerProps(ALCcontext *context)
477 ALlistener *listener = context->Listener;
478 struct ALlistenerProps *props;
480 /* Get an unused proprty container, or allocate a new one as needed. */
481 props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire);
482 if(!props)
483 props = al_calloc(16, sizeof(*props));
484 else
486 struct ALlistenerProps *next;
487 do {
488 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
489 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
490 &listener->FreeList, &props, next, almemory_order_seq_cst,
491 almemory_order_consume) == 0);
494 /* Copy in current property values. */
495 ATOMIC_STORE(&props->Position[0], listener->Position[0], almemory_order_relaxed);
496 ATOMIC_STORE(&props->Position[1], listener->Position[1], almemory_order_relaxed);
497 ATOMIC_STORE(&props->Position[2], listener->Position[2], almemory_order_relaxed);
499 ATOMIC_STORE(&props->Velocity[0], listener->Velocity[0], almemory_order_relaxed);
500 ATOMIC_STORE(&props->Velocity[1], listener->Velocity[1], almemory_order_relaxed);
501 ATOMIC_STORE(&props->Velocity[2], listener->Velocity[2], almemory_order_relaxed);
503 ATOMIC_STORE(&props->Forward[0], listener->Forward[0], almemory_order_relaxed);
504 ATOMIC_STORE(&props->Forward[1], listener->Forward[1], almemory_order_relaxed);
505 ATOMIC_STORE(&props->Forward[2], listener->Forward[2], almemory_order_relaxed);
506 ATOMIC_STORE(&props->Up[0], listener->Up[0], almemory_order_relaxed);
507 ATOMIC_STORE(&props->Up[1], listener->Up[1], almemory_order_relaxed);
508 ATOMIC_STORE(&props->Up[2], listener->Up[2], almemory_order_relaxed);
510 ATOMIC_STORE(&props->Gain, listener->Gain, almemory_order_relaxed);
511 ATOMIC_STORE(&props->MetersPerUnit, listener->MetersPerUnit, almemory_order_relaxed);
513 ATOMIC_STORE(&props->DopplerFactor, context->DopplerFactor, almemory_order_relaxed);
514 ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed);
515 ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed);
517 ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel,
518 almemory_order_relaxed);
519 ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed);
521 /* Set the new container for updating internal parameters. */
522 props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel);
523 if(props)
525 /* If there was an unused update container, put it back in the
526 * freelist.
528 struct ALlistenerProps *first = ATOMIC_LOAD(&listener->FreeList);
529 do {
530 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
531 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*,
532 &listener->FreeList, &first, props) == 0);