Ignore the listening angle for the wet path sound cones
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob9cc8656306ddc420bd04a7af08a36dc9b40077b9
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 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 <stdlib.h>
24 #include <math.h>
26 #include "AL/al.h"
27 #include "AL/alc.h"
28 #include "alMain.h"
29 #include "alAuxEffectSlot.h"
30 #include "alThunk.h"
31 #include "alError.h"
32 #include "alListener.h"
33 #include "alSource.h"
35 #include "almalloc.h"
38 extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
39 extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
41 static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
42 static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
45 static UIntMap EffectStateFactoryMap;
46 static inline ALeffectStateFactory *getFactoryByType(ALenum type)
48 ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
49 if(getFactory != NULL)
50 return getFactory();
51 return NULL;
55 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
57 ALCcontext *context;
58 VECTOR(ALeffectslot*) slotvec;
59 ALsizei cur;
60 ALenum err;
62 context = GetContextRef();
63 if(!context) return;
65 VECTOR_INIT(slotvec);
67 if(!(n >= 0))
68 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
69 if(!VECTOR_RESERVE(slotvec, n))
70 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
72 for(cur = 0;cur < n;cur++)
74 ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
75 err = AL_OUT_OF_MEMORY;
76 if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
78 al_free(slot);
79 alDeleteAuxiliaryEffectSlots(cur, effectslots);
80 SET_ERROR_AND_GOTO(context, err, done);
83 err = NewThunkEntry(&slot->id);
84 if(err == AL_NO_ERROR)
85 err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
86 if(err != AL_NO_ERROR)
88 FreeThunkEntry(slot->id);
89 DELETE_OBJ(slot->Params.EffectState);
90 al_free(slot);
92 alDeleteAuxiliaryEffectSlots(cur, effectslots);
93 SET_ERROR_AND_GOTO(context, err, done);
96 aluInitEffectPanning(slot);
98 VECTOR_PUSH_BACK(slotvec, slot);
100 effectslots[cur] = slot->id;
102 err = AddEffectSlotArray(context, VECTOR_BEGIN(slotvec), n);
103 if(err != AL_NO_ERROR)
105 alDeleteAuxiliaryEffectSlots(cur, effectslots);
106 SET_ERROR_AND_GOTO(context, err, done);
109 done:
110 VECTOR_DEINIT(slotvec);
112 ALCcontext_DecRef(context);
115 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
117 ALCcontext *context;
118 ALeffectslot *slot;
119 ALsizei i;
121 context = GetContextRef();
122 if(!context) return;
124 if(!(n >= 0))
125 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
126 for(i = 0;i < n;i++)
128 if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
129 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
130 if(ReadRef(&slot->ref) != 0)
131 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
134 // All effectslots are valid
135 for(i = 0;i < n;i++)
137 if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
138 continue;
139 FreeThunkEntry(slot->id);
141 RemoveEffectSlotArray(context, slot);
142 DeinitEffectSlot(slot);
144 memset(slot, 0, sizeof(*slot));
145 al_free(slot);
148 done:
149 ALCcontext_DecRef(context);
152 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
154 ALCcontext *context;
155 ALboolean ret;
157 context = GetContextRef();
158 if(!context) return AL_FALSE;
160 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
162 ALCcontext_DecRef(context);
164 return ret;
167 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
169 ALCdevice *device;
170 ALCcontext *context;
171 ALeffectslot *slot;
172 ALeffect *effect = NULL;
173 ALenum err;
175 context = GetContextRef();
176 if(!context) return;
178 WriteLock(&context->PropLock);
179 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
180 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
181 switch(param)
183 case AL_EFFECTSLOT_EFFECT:
184 device = context->Device;
186 LockEffectsRead(device);
187 effect = (value ? LookupEffect(device, value) : NULL);
188 if(!(value == 0 || effect != NULL))
190 UnlockEffectsRead(device);
191 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
193 err = InitializeEffect(device, slot, effect);
194 UnlockEffectsRead(device);
196 if(err != AL_NO_ERROR)
197 SET_ERROR_AND_GOTO(context, err, done);
198 break;
200 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
201 if(!(value == AL_TRUE || value == AL_FALSE))
202 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
203 slot->AuxSendAuto = value;
204 UpdateEffectSlotProps(slot);
205 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
206 UpdateAllSourceProps(context);
207 break;
209 default:
210 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
213 done:
214 WriteUnlock(&context->PropLock);
215 ALCcontext_DecRef(context);
218 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
220 ALCcontext *context;
222 switch(param)
224 case AL_EFFECTSLOT_EFFECT:
225 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
226 alAuxiliaryEffectSloti(effectslot, param, values[0]);
227 return;
230 context = GetContextRef();
231 if(!context) return;
233 if(LookupEffectSlot(context, effectslot) == NULL)
234 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
235 switch(param)
237 default:
238 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
241 done:
242 ALCcontext_DecRef(context);
245 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
247 ALCcontext *context;
248 ALeffectslot *slot;
250 context = GetContextRef();
251 if(!context) return;
253 WriteLock(&context->PropLock);
254 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
255 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
256 switch(param)
258 case AL_EFFECTSLOT_GAIN:
259 if(!(value >= 0.0f && value <= 1.0f))
260 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
261 slot->Gain = value;
262 break;
264 default:
265 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
267 UpdateEffectSlotProps(slot);
269 done:
270 WriteUnlock(&context->PropLock);
271 ALCcontext_DecRef(context);
274 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
276 ALCcontext *context;
278 switch(param)
280 case AL_EFFECTSLOT_GAIN:
281 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
282 return;
285 context = GetContextRef();
286 if(!context) return;
288 if(LookupEffectSlot(context, effectslot) == NULL)
289 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
290 switch(param)
292 default:
293 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
296 done:
297 ALCcontext_DecRef(context);
300 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
302 ALCcontext *context;
303 ALeffectslot *slot;
305 context = GetContextRef();
306 if(!context) return;
308 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
309 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
310 switch(param)
312 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
313 *value = slot->AuxSendAuto;
314 break;
316 default:
317 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
320 done:
321 ALCcontext_DecRef(context);
324 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
326 ALCcontext *context;
328 switch(param)
330 case AL_EFFECTSLOT_EFFECT:
331 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
332 alGetAuxiliaryEffectSloti(effectslot, param, values);
333 return;
336 context = GetContextRef();
337 if(!context) return;
339 if(LookupEffectSlot(context, effectslot) == NULL)
340 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
341 switch(param)
343 default:
344 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
347 done:
348 ALCcontext_DecRef(context);
351 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
353 ALCcontext *context;
354 ALeffectslot *slot;
356 context = GetContextRef();
357 if(!context) return;
359 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
360 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
361 switch(param)
363 case AL_EFFECTSLOT_GAIN:
364 *value = slot->Gain;
365 break;
367 default:
368 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
371 done:
372 ALCcontext_DecRef(context);
375 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
377 ALCcontext *context;
379 switch(param)
381 case AL_EFFECTSLOT_GAIN:
382 alGetAuxiliaryEffectSlotf(effectslot, param, values);
383 return;
386 context = GetContextRef();
387 if(!context) return;
389 if(LookupEffectSlot(context, effectslot) == NULL)
390 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
391 switch(param)
393 default:
394 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
397 done:
398 ALCcontext_DecRef(context);
402 static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
404 ALenum err = AL_NO_ERROR;
406 LockContext(context);
407 if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_END(context->ActiveAuxSlots), start, start+count))
408 err = AL_OUT_OF_MEMORY;
409 UnlockContext(context);
411 return err;
414 static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
416 ALeffectslot **iter;
418 LockContext(context);
419 #define MATCH_SLOT(_i) (slot == *(_i))
420 VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
421 if(iter != VECTOR_END(context->ActiveAuxSlots))
423 *iter = VECTOR_BACK(context->ActiveAuxSlots);
424 VECTOR_POP_BACK(context->ActiveAuxSlots);
426 #undef MATCH_SLOT
427 UnlockContext(context);
431 void InitEffectFactoryMap(void)
433 InitUIntMap(&EffectStateFactoryMap, ~0);
435 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
436 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
437 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
438 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory);
439 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
440 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
441 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
442 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
443 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
444 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
445 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
446 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
447 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
450 void DeinitEffectFactoryMap(void)
452 ResetUIntMap(&EffectStateFactoryMap);
456 ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
458 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
459 ALeffectStateFactory *factory;
461 if(newtype != EffectSlot->Effect.Type)
463 ALeffectState *State;
464 FPUCtl oldMode;
466 factory = getFactoryByType(newtype);
467 if(!factory)
469 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
470 return AL_INVALID_ENUM;
472 State = V0(factory,create)();
473 if(!State)
474 return AL_OUT_OF_MEMORY;
476 SetMixerFPUMode(&oldMode);
477 /* FIXME: This just needs to prevent the device from being reset during
478 * the state's device update, so the list lock in ALc.c should do here.
480 ALCdevice_Lock(Device);
481 State->OutBuffer = Device->Dry.Buffer;
482 State->OutChannels = Device->Dry.NumChannels;
483 if(V(State,deviceUpdate)(Device) == AL_FALSE)
485 ALCdevice_Unlock(Device);
486 RestoreFPUMode(&oldMode);
487 DELETE_OBJ(State);
488 return AL_OUT_OF_MEMORY;
490 ALCdevice_Unlock(Device);
491 RestoreFPUMode(&oldMode);
493 if(!effect)
495 EffectSlot->Effect.Type = AL_EFFECT_NULL;
496 memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
498 else
500 EffectSlot->Effect.Type = effect->type;
501 memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props));
504 EffectSlot->Effect.State = State;
505 UpdateEffectSlotProps(EffectSlot);
507 else if(effect)
509 memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props));
510 UpdateEffectSlotProps(EffectSlot);
513 return AL_NO_ERROR;
517 void ALeffectState_Destruct(ALeffectState *UNUSED(state))
522 ALenum InitEffectSlot(ALeffectslot *slot)
524 ALeffectStateFactory *factory;
526 slot->Effect.Type = AL_EFFECT_NULL;
528 factory = getFactoryByType(AL_EFFECT_NULL);
529 if(!(slot->Effect.State=V0(factory,create)()))
530 return AL_OUT_OF_MEMORY;
532 slot->Gain = 1.0;
533 slot->AuxSendAuto = AL_TRUE;
534 InitRef(&slot->ref, 0);
536 ATOMIC_INIT(&slot->Update, NULL);
537 ATOMIC_INIT(&slot->FreeList, NULL);
539 slot->Params.Gain = 1.0f;
540 slot->Params.AuxSendAuto = AL_TRUE;
541 slot->Params.EffectState = slot->Effect.State;
542 slot->Params.RoomRolloff = 0.0f;
543 slot->Params.DecayTime = 0.0f;
544 slot->Params.AirAbsorptionGainHF = 1.0f;
546 return AL_NO_ERROR;
549 void DeinitEffectSlot(ALeffectslot *slot)
551 struct ALeffectslotProps *props;
552 ALeffectState *state;
553 size_t count = 0;
555 props = ATOMIC_LOAD(&slot->Update);
556 if(props)
558 state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
559 if(state != slot->Params.EffectState)
560 DELETE_OBJ(state);
561 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
562 al_free(props);
564 props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
565 while(props)
567 struct ALeffectslotProps *next;
568 state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
569 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
570 DELETE_OBJ(state);
571 al_free(props);
572 props = next;
573 ++count;
575 TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
577 DELETE_OBJ(slot->Params.EffectState);
580 void UpdateEffectSlotProps(ALeffectslot *slot)
582 struct ALeffectslotProps *props;
583 ALeffectState *oldstate;
585 props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL);
586 if(props)
588 /* If there was an unapplied update, check if its state object is the
589 * same as the current in-use one, or the one that will be set. If
590 * neither, delete it.
592 oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
593 if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State)
594 DELETE_OBJ(oldstate);
596 else
598 /* Get an unused property container, or allocate a new one as needed. */
599 props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
600 if(!props)
601 props = al_calloc(16, sizeof(*props));
602 else
604 struct ALeffectslotProps *next;
605 do {
606 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
607 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
608 &slot->FreeList, &props, next, almemory_order_seq_cst,
609 almemory_order_consume) == 0);
613 /* Copy in current property values. */
614 ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed);
615 ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed);
617 ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed);
618 memcpy(&props->Props, &slot->Effect.Props, sizeof(props->Props));
619 /* Swap out any stale effect state object there may be in the container, to
620 * delete it.
622 oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State,
623 almemory_order_relaxed);
625 /* Set the new container for updating internal parameters. */
626 props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props,
627 almemory_order_acq_rel);
628 if(props)
630 /* If there was an unused update container, put it back in the
631 * freelist.
633 struct ALeffectslotProps *first = ATOMIC_LOAD(&slot->FreeList);
634 do {
635 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
636 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
637 &slot->FreeList, &first, props) == 0);
640 DELETE_OBJ(oldstate);
643 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
645 ALsizei pos;
646 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
648 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
649 Context->EffectSlotMap.array[pos].value = NULL;
651 DeinitEffectSlot(temp);
653 FreeThunkEntry(temp->id);
654 memset(temp, 0, sizeof(ALeffectslot));
655 al_free(temp);