Apply a distance decay on the source send for the reverb's DecayLFRatio
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob301244a0f8c02f6e74e46ab560d4dbb8716a60c0
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 "alError.h"
31 #include "alListener.h"
32 #include "alSource.h"
34 #include "fpu_modes.h"
35 #include "almalloc.h"
38 extern inline void LockEffectSlotList(ALCcontext *context);
39 extern inline void UnlockEffectSlotList(ALCcontext *context);
41 static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
42 static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
44 static const struct {
45 ALenum Type;
46 EffectStateFactory* (*GetFactory)(void);
47 } FactoryList[] = {
48 { AL_EFFECT_NULL, NullStateFactory_getFactory },
49 { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory },
50 { AL_EFFECT_REVERB, ReverbStateFactory_getFactory },
51 { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory },
52 { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory },
53 { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory },
54 { AL_EFFECT_ECHO, EchoStateFactory_getFactory },
55 { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory },
56 { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory },
57 { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory },
58 { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory },
59 { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory }
62 static inline EffectStateFactory *getFactoryByType(ALenum type)
64 size_t i;
65 for(i = 0;i < COUNTOF(FactoryList);i++)
67 if(FactoryList[i].Type == type)
68 return FactoryList[i].GetFactory();
70 return NULL;
73 static void ALeffectState_IncRef(ALeffectState *state);
76 static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
78 id--;
79 if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList)))
80 return NULL;
81 return VECTOR_ELEM(context->EffectSlotList, id);
84 static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
86 EffectSubList *sublist;
87 ALuint lidx = (id-1) >> 6;
88 ALsizei slidx = (id-1) & 0x3f;
90 if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList)))
91 return NULL;
92 sublist = &VECTOR_ELEM(device->EffectList, lidx);
93 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
94 return NULL;
95 return sublist->Effects + slidx;
99 #define DO_UPDATEPROPS() do { \
100 if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
101 UpdateEffectSlotProps(slot, context); \
102 else \
103 ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
104 } while(0)
107 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
109 ALCdevice *device;
110 ALCcontext *context;
111 ALsizei cur;
113 context = GetContextRef();
114 if(!context) return;
116 if(!(n >= 0))
117 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
118 if(n == 0) goto done;
120 LockEffectSlotList(context);
121 device = context->Device;
122 if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n)
124 UnlockEffectSlotList(context);
125 SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit",
126 device->AuxiliaryEffectSlotMax);
128 for(cur = 0;cur < n;cur++)
130 ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
131 ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
132 ALeffectslot *slot = NULL;
133 ALenum err = AL_OUT_OF_MEMORY;
135 for(;iter != end;iter++)
137 if(!*iter)
138 break;
140 if(iter == end)
142 VECTOR_PUSH_BACK(context->EffectSlotList, NULL);
143 iter = &VECTOR_BACK(context->EffectSlotList);
145 slot = al_calloc(16, sizeof(ALeffectslot));
146 if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
148 al_free(slot);
149 UnlockEffectSlotList(context);
151 alDeleteAuxiliaryEffectSlots(cur, effectslots);
152 SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
154 aluInitEffectPanning(slot);
156 slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
157 *iter = slot;
159 effectslots[cur] = slot->id;
161 AddActiveEffectSlots(effectslots, n, context);
162 UnlockEffectSlotList(context);
164 done:
165 ALCcontext_DecRef(context);
168 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
170 ALCcontext *context;
171 ALeffectslot *slot;
172 ALsizei i;
174 context = GetContextRef();
175 if(!context) return;
177 LockEffectSlotList(context);
178 if(!(n >= 0))
179 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n);
180 if(n == 0) goto done;
182 for(i = 0;i < n;i++)
184 if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
185 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u",
186 effectslots[i]);
187 if(ReadRef(&slot->ref) != 0)
188 SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u",
189 effectslots[i]);
192 // All effectslots are valid
193 RemoveActiveEffectSlots(effectslots, n, context);
194 for(i = 0;i < n;i++)
196 if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
197 continue;
198 VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL;
200 DeinitEffectSlot(slot);
202 memset(slot, 0, sizeof(*slot));
203 al_free(slot);
206 done:
207 UnlockEffectSlotList(context);
208 ALCcontext_DecRef(context);
211 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
213 ALCcontext *context;
214 ALboolean ret;
216 context = GetContextRef();
217 if(!context) return AL_FALSE;
219 LockEffectSlotList(context);
220 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
221 UnlockEffectSlotList(context);
223 ALCcontext_DecRef(context);
225 return ret;
228 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
230 ALCdevice *device;
231 ALCcontext *context;
232 ALeffectslot *slot;
233 ALeffect *effect = NULL;
234 ALenum err;
236 context = GetContextRef();
237 if(!context) return;
239 almtx_lock(&context->PropLock);
240 LockEffectSlotList(context);
241 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
242 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
243 switch(param)
245 case AL_EFFECTSLOT_EFFECT:
246 device = context->Device;
248 LockEffectList(device);
249 effect = (value ? LookupEffect(device, value) : NULL);
250 if(!(value == 0 || effect != NULL))
252 UnlockEffectList(device);
253 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value);
255 err = InitializeEffect(context, slot, effect);
256 UnlockEffectList(device);
258 if(err != AL_NO_ERROR)
259 SETERR_GOTO(context, err, done, "Effect initialization failed");
260 break;
262 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
263 if(!(value == AL_TRUE || value == AL_FALSE))
264 SETERR_GOTO(context, AL_INVALID_VALUE, done,
265 "Effect slot auxiliary send auto out of range");
266 slot->AuxSendAuto = value;
267 break;
269 default:
270 SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x",
271 param);
273 DO_UPDATEPROPS();
275 done:
276 UnlockEffectSlotList(context);
277 almtx_unlock(&context->PropLock);
278 ALCcontext_DecRef(context);
281 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
283 ALCcontext *context;
285 switch(param)
287 case AL_EFFECTSLOT_EFFECT:
288 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
289 alAuxiliaryEffectSloti(effectslot, param, values[0]);
290 return;
293 context = GetContextRef();
294 if(!context) return;
296 LockEffectSlotList(context);
297 if(LookupEffectSlot(context, effectslot) == NULL)
298 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
299 switch(param)
301 default:
302 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
303 param);
306 done:
307 UnlockEffectSlotList(context);
308 ALCcontext_DecRef(context);
311 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
313 ALCcontext *context;
314 ALeffectslot *slot;
316 context = GetContextRef();
317 if(!context) return;
319 almtx_lock(&context->PropLock);
320 LockEffectSlotList(context);
321 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
322 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
323 switch(param)
325 case AL_EFFECTSLOT_GAIN:
326 if(!(value >= 0.0f && value <= 1.0f))
327 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range");
328 slot->Gain = value;
329 break;
331 default:
332 SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x",
333 param);
335 DO_UPDATEPROPS();
337 done:
338 UnlockEffectSlotList(context);
339 almtx_unlock(&context->PropLock);
340 ALCcontext_DecRef(context);
343 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
345 ALCcontext *context;
347 switch(param)
349 case AL_EFFECTSLOT_GAIN:
350 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
351 return;
354 context = GetContextRef();
355 if(!context) return;
357 LockEffectSlotList(context);
358 if(LookupEffectSlot(context, effectslot) == NULL)
359 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
360 switch(param)
362 default:
363 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
364 param);
367 done:
368 UnlockEffectSlotList(context);
369 ALCcontext_DecRef(context);
372 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
374 ALCcontext *context;
375 ALeffectslot *slot;
377 context = GetContextRef();
378 if(!context) return;
380 LockEffectSlotList(context);
381 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
382 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
383 switch(param)
385 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
386 *value = slot->AuxSendAuto;
387 break;
389 default:
390 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param);
393 done:
394 UnlockEffectSlotList(context);
395 ALCcontext_DecRef(context);
398 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
400 ALCcontext *context;
402 switch(param)
404 case AL_EFFECTSLOT_EFFECT:
405 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
406 alGetAuxiliaryEffectSloti(effectslot, param, values);
407 return;
410 context = GetContextRef();
411 if(!context) return;
413 LockEffectSlotList(context);
414 if(LookupEffectSlot(context, effectslot) == NULL)
415 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
416 switch(param)
418 default:
419 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
420 param);
423 done:
424 UnlockEffectSlotList(context);
425 ALCcontext_DecRef(context);
428 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
430 ALCcontext *context;
431 ALeffectslot *slot;
433 context = GetContextRef();
434 if(!context) return;
436 LockEffectSlotList(context);
437 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
438 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
439 switch(param)
441 case AL_EFFECTSLOT_GAIN:
442 *value = slot->Gain;
443 break;
445 default:
446 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param);
449 done:
450 UnlockEffectSlotList(context);
451 ALCcontext_DecRef(context);
454 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
456 ALCcontext *context;
458 switch(param)
460 case AL_EFFECTSLOT_GAIN:
461 alGetAuxiliaryEffectSlotf(effectslot, param, values);
462 return;
465 context = GetContextRef();
466 if(!context) return;
468 LockEffectSlotList(context);
469 if(LookupEffectSlot(context, effectslot) == NULL)
470 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
471 switch(param)
473 default:
474 alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
475 param);
478 done:
479 UnlockEffectSlotList(context);
480 ALCcontext_DecRef(context);
484 ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
486 ALCdevice *Device = Context->Device;
487 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
488 struct ALeffectslotProps *props;
489 ALeffectState *State;
491 if(newtype != EffectSlot->Effect.Type)
493 EffectStateFactory *factory;
495 factory = getFactoryByType(newtype);
496 if(!factory)
498 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
499 return AL_INVALID_ENUM;
501 State = EffectStateFactory_create(factory);
502 if(!State) return AL_OUT_OF_MEMORY;
504 START_MIXER_MODE();
505 almtx_lock(&Device->BackendLock);
506 State->OutBuffer = Device->Dry.Buffer;
507 State->OutChannels = Device->Dry.NumChannels;
508 if(V(State,deviceUpdate)(Device) == AL_FALSE)
510 almtx_unlock(&Device->BackendLock);
511 LEAVE_MIXER_MODE();
512 ALeffectState_DecRef(State);
513 return AL_OUT_OF_MEMORY;
515 almtx_unlock(&Device->BackendLock);
516 END_MIXER_MODE();
518 if(!effect)
520 EffectSlot->Effect.Type = AL_EFFECT_NULL;
521 memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
523 else
525 EffectSlot->Effect.Type = effect->type;
526 EffectSlot->Effect.Props = effect->Props;
529 ALeffectState_DecRef(EffectSlot->Effect.State);
530 EffectSlot->Effect.State = State;
532 else if(effect)
533 EffectSlot->Effect.Props = effect->Props;
535 /* Remove state references from old effect slot property updates. */
536 props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
537 while(props)
539 if(props->State)
540 ALeffectState_DecRef(props->State);
541 props->State = NULL;
542 props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
545 return AL_NO_ERROR;
549 static void ALeffectState_IncRef(ALeffectState *state)
551 uint ref;
552 ref = IncrementRef(&state->Ref);
553 TRACEREF("%p increasing refcount to %u\n", state, ref);
556 void ALeffectState_DecRef(ALeffectState *state)
558 uint ref;
559 ref = DecrementRef(&state->Ref);
560 TRACEREF("%p decreasing refcount to %u\n", state, ref);
561 if(ref == 0) DELETE_OBJ(state);
565 void ALeffectState_Construct(ALeffectState *state)
567 InitRef(&state->Ref, 1);
569 state->OutBuffer = NULL;
570 state->OutChannels = 0;
573 void ALeffectState_Destruct(ALeffectState *UNUSED(state))
578 static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
580 struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
581 almemory_order_acquire);
582 struct ALeffectslotArray *newarray = NULL;
583 ALsizei newcount = curarray->count + count;
584 ALCdevice *device = context->Device;
585 ALsizei i, j;
587 /* Insert the new effect slots into the head of the array, followed by the
588 * existing ones.
590 newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
591 newarray->count = newcount;
592 for(i = 0;i < count;i++)
593 newarray->slot[i] = LookupEffectSlot(context, slotids[i]);
594 for(j = 0;i < newcount;)
595 newarray->slot[i++] = curarray->slot[j++];
596 /* Remove any duplicates (first instance of each will be kept). */
597 for(i = 1;i < newcount;i++)
599 for(j = i;j != 0;)
601 if(UNLIKELY(newarray->slot[i] == newarray->slot[--j]))
603 newcount--;
604 for(j = i;j < newcount;j++)
605 newarray->slot[j] = newarray->slot[j+1];
606 i--;
607 break;
612 /* Reallocate newarray if the new size ended up smaller from duplicate
613 * removal.
615 if(UNLIKELY(newcount < newarray->count))
617 struct ALeffectslotArray *tmpnewarray = al_calloc(DEF_ALIGN,
618 FAM_SIZE(struct ALeffectslotArray, slot, newcount));
619 memcpy(tmpnewarray, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
620 al_free(newarray);
621 newarray = tmpnewarray;
622 newarray->count = newcount;
625 curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
626 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
627 althrd_yield();
628 al_free(curarray);
631 static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context)
633 struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots,
634 almemory_order_acquire);
635 struct ALeffectslotArray *newarray = NULL;
636 ALCdevice *device = context->Device;
637 ALsizei i, j;
639 /* Don't shrink the allocated array size since we don't know how many (if
640 * any) of the effect slots to remove are in the array.
642 newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, curarray->count));
643 newarray->count = 0;
644 for(i = 0;i < curarray->count;i++)
646 /* Insert this slot into the new array only if it's not one to remove. */
647 ALeffectslot *slot = curarray->slot[i];
648 for(j = count;j != 0;)
650 if(slot->id == slotids[--j])
651 goto skip_ins;
653 newarray->slot[newarray->count++] = slot;
654 skip_ins: ;
657 /* TODO: Could reallocate newarray now that we know it's needed size. */
659 curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel);
660 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
661 althrd_yield();
662 al_free(curarray);
666 ALenum InitEffectSlot(ALeffectslot *slot)
668 EffectStateFactory *factory;
670 slot->Effect.Type = AL_EFFECT_NULL;
672 factory = getFactoryByType(AL_EFFECT_NULL);
673 slot->Effect.State = EffectStateFactory_create(factory);
674 if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
676 slot->Gain = 1.0;
677 slot->AuxSendAuto = AL_TRUE;
678 ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed);
679 InitRef(&slot->ref, 0);
681 ATOMIC_INIT(&slot->Update, NULL);
683 slot->Params.Gain = 1.0f;
684 slot->Params.AuxSendAuto = AL_TRUE;
685 ALeffectState_IncRef(slot->Effect.State);
686 slot->Params.EffectState = slot->Effect.State;
687 slot->Params.RoomRolloff = 0.0f;
688 slot->Params.DecayTime = 0.0f;
689 slot->Params.DecayLFRatio = 0.0f;
690 slot->Params.DecayHFRatio = 0.0f;
691 slot->Params.DecayHFLimit = AL_FALSE;
692 slot->Params.AirAbsorptionGainHF = 1.0f;
694 return AL_NO_ERROR;
697 void DeinitEffectSlot(ALeffectslot *slot)
699 struct ALeffectslotProps *props;
701 props = ATOMIC_LOAD_SEQ(&slot->Update);
702 if(props)
704 if(props->State) ALeffectState_DecRef(props->State);
705 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
706 al_free(props);
709 ALeffectState_DecRef(slot->Effect.State);
710 if(slot->Params.EffectState)
711 ALeffectState_DecRef(slot->Params.EffectState);
714 void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
716 struct ALeffectslotProps *props;
717 ALeffectState *oldstate;
719 /* Get an unused property container, or allocate a new one as needed. */
720 props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed);
721 if(!props)
722 props = al_calloc(16, sizeof(*props));
723 else
725 struct ALeffectslotProps *next;
726 do {
727 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
728 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
729 almemory_order_seq_cst, almemory_order_acquire) == 0);
732 /* Copy in current property values. */
733 props->Gain = slot->Gain;
734 props->AuxSendAuto = slot->AuxSendAuto;
736 props->Type = slot->Effect.Type;
737 props->Props = slot->Effect.Props;
738 /* Swap out any stale effect state object there may be in the container, to
739 * delete it.
741 ALeffectState_IncRef(slot->Effect.State);
742 oldstate = props->State;
743 props->State = slot->Effect.State;
745 /* Set the new container for updating internal parameters. */
746 props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel);
747 if(props)
749 /* If there was an unused update container, put it back in the
750 * freelist.
752 ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props);
755 if(oldstate)
756 ALeffectState_DecRef(oldstate);
759 void UpdateAllEffectSlotProps(ALCcontext *context)
761 struct ALeffectslotArray *auxslots;
762 ALsizei i;
764 LockEffectSlotList(context);
765 auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
766 for(i = 0;i < auxslots->count;i++)
768 ALeffectslot *slot = auxslots->slot[i];
769 if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
770 UpdateEffectSlotProps(slot, context);
772 UnlockEffectSlotList(context);
775 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context)
777 ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
778 ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
779 size_t leftover = 0;
781 for(;iter != end;iter++)
783 ALeffectslot *slot = *iter;
784 if(!slot) continue;
785 *iter = NULL;
787 DeinitEffectSlot(slot);
789 memset(slot, 0, sizeof(*slot));
790 al_free(slot);
791 ++leftover;
793 if(leftover > 0)
794 WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s");