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
29 #include "alAuxEffectSlot.h"
32 #include "alListener.h"
38 extern inline void LockEffectSlotsRead(ALCcontext
*context
);
39 extern inline void UnlockEffectSlotsRead(ALCcontext
*context
);
40 extern inline void LockEffectSlotsWrite(ALCcontext
*context
);
41 extern inline void UnlockEffectSlotsWrite(ALCcontext
*context
);
42 extern inline struct ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
);
43 extern inline struct ALeffectslot
*RemoveEffectSlot(ALCcontext
*context
, ALuint id
);
45 static void RemoveEffectSlotList(ALCcontext
*Context
, const ALeffectslot
*slot
);
48 static UIntMap EffectStateFactoryMap
;
49 static inline ALeffectStateFactory
*getFactoryByType(ALenum type
)
51 ALeffectStateFactory
* (*getFactory
)(void) = LookupUIntMapKey(&EffectStateFactoryMap
, type
);
52 if(getFactory
!= NULL
)
58 AL_API ALvoid AL_APIENTRY
alGenAuxiliaryEffectSlots(ALsizei n
, ALuint
*effectslots
)
61 ALeffectslot
*first
, *last
;
65 context
= GetContextRef();
69 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, 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
)
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
);
92 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
93 SET_ERROR_AND_GOTO(context
, err
, done
);
96 aluInitEffectPanning(slot
);
98 if(!first
) first
= slot
;
99 if(last
) ATOMIC_STORE(&last
->next
, slot
, almemory_order_relaxed
);
102 effectslots
[cur
] = slot
->id
;
106 ALeffectslot
*root
= ATOMIC_LOAD(&context
->ActiveAuxSlotList
);
108 ATOMIC_STORE(&last
->next
, root
, almemory_order_relaxed
);
109 } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot
*, &context
->ActiveAuxSlotList
,
114 ALCcontext_DecRef(context
);
117 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
123 context
= GetContextRef();
126 LockEffectSlotsWrite(context
);
128 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
131 if((slot
=LookupEffectSlot(context
, effectslots
[i
])) == NULL
)
132 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
133 if(ReadRef(&slot
->ref
) != 0)
134 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
137 // All effectslots are valid
140 if((slot
=RemoveEffectSlot(context
, effectslots
[i
])) == NULL
)
142 FreeThunkEntry(slot
->id
);
144 RemoveEffectSlotList(context
, slot
);
145 DeinitEffectSlot(slot
);
147 memset(slot
, 0, sizeof(*slot
));
152 UnlockEffectSlotsWrite(context
);
153 ALCcontext_DecRef(context
);
156 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
161 context
= GetContextRef();
162 if(!context
) return AL_FALSE
;
164 LockEffectSlotsRead(context
);
165 ret
= (LookupEffectSlot(context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
166 UnlockEffectSlotsRead(context
);
168 ALCcontext_DecRef(context
);
173 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
178 ALeffect
*effect
= NULL
;
181 context
= GetContextRef();
184 WriteLock(&context
->PropLock
);
185 LockEffectSlotsRead(context
);
186 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
187 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
190 case AL_EFFECTSLOT_EFFECT
:
191 device
= context
->Device
;
193 LockEffectsRead(device
);
194 effect
= (value
? LookupEffect(device
, value
) : NULL
);
195 if(!(value
== 0 || effect
!= NULL
))
197 UnlockEffectsRead(device
);
198 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
200 err
= InitializeEffect(device
, slot
, effect
);
201 UnlockEffectsRead(device
);
203 if(err
!= AL_NO_ERROR
)
204 SET_ERROR_AND_GOTO(context
, err
, done
);
207 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
208 if(!(value
== AL_TRUE
|| value
== AL_FALSE
))
209 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
210 slot
->AuxSendAuto
= value
;
211 UpdateEffectSlotProps(slot
);
212 if(!ATOMIC_LOAD(&context
->DeferUpdates
, almemory_order_acquire
))
213 UpdateAllSourceProps(context
);
217 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
221 UnlockEffectSlotsRead(context
);
222 WriteUnlock(&context
->PropLock
);
223 ALCcontext_DecRef(context
);
226 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
232 case AL_EFFECTSLOT_EFFECT
:
233 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
234 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
238 context
= GetContextRef();
241 LockEffectSlotsRead(context
);
242 if(LookupEffectSlot(context
, effectslot
) == NULL
)
243 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
247 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
251 UnlockEffectSlotsRead(context
);
252 ALCcontext_DecRef(context
);
255 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
260 context
= GetContextRef();
263 WriteLock(&context
->PropLock
);
264 LockEffectSlotsRead(context
);
265 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
266 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
269 case AL_EFFECTSLOT_GAIN
:
270 if(!(value
>= 0.0f
&& value
<= 1.0f
))
271 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
276 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
278 UpdateEffectSlotProps(slot
);
281 UnlockEffectSlotsRead(context
);
282 WriteUnlock(&context
->PropLock
);
283 ALCcontext_DecRef(context
);
286 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
292 case AL_EFFECTSLOT_GAIN
:
293 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
297 context
= GetContextRef();
300 LockEffectSlotsRead(context
);
301 if(LookupEffectSlot(context
, effectslot
) == NULL
)
302 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
306 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
310 UnlockEffectSlotsRead(context
);
311 ALCcontext_DecRef(context
);
314 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
319 context
= GetContextRef();
322 LockEffectSlotsRead(context
);
323 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
324 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
327 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
328 *value
= slot
->AuxSendAuto
;
332 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
336 UnlockEffectSlotsRead(context
);
337 ALCcontext_DecRef(context
);
340 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
346 case AL_EFFECTSLOT_EFFECT
:
347 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
348 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
352 context
= GetContextRef();
355 LockEffectSlotsRead(context
);
356 if(LookupEffectSlot(context
, effectslot
) == NULL
)
357 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
361 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
365 UnlockEffectSlotsRead(context
);
366 ALCcontext_DecRef(context
);
369 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
374 context
= GetContextRef();
377 LockEffectSlotsRead(context
);
378 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
379 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
382 case AL_EFFECTSLOT_GAIN
:
387 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
391 UnlockEffectSlotsRead(context
);
392 ALCcontext_DecRef(context
);
395 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
401 case AL_EFFECTSLOT_GAIN
:
402 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
406 context
= GetContextRef();
409 LockEffectSlotsRead(context
);
410 if(LookupEffectSlot(context
, effectslot
) == NULL
)
411 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
415 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
419 UnlockEffectSlotsRead(context
);
420 ALCcontext_DecRef(context
);
424 static void RemoveEffectSlotList(ALCcontext
*context
, const ALeffectslot
*slot
)
426 ALCdevice
*device
= context
->Device
;
427 const ALeffectslot
*root
, *next
;
430 next
= ATOMIC_LOAD(&slot
->next
);
431 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot
*, &context
->ActiveAuxSlotList
, &root
, next
))
433 const ALeffectslot
*cur
;
437 } while(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot
*, &cur
->next
, &root
, next
));
439 /* Wait for any mix that may be using these effect slots to finish. */
440 while((ReadRef(&device
->MixCount
)&1) != 0)
445 void InitEffectFactoryMap(void)
447 InitUIntMap(&EffectStateFactoryMap
, ~0);
449 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_NULL
, ALnullStateFactory_getFactory
);
450 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EAXREVERB
, ALreverbStateFactory_getFactory
);
451 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_REVERB
, ALreverbStateFactory_getFactory
);
452 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_CHORUS
, ALchorusStateFactory_getFactory
);
453 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_COMPRESSOR
, ALcompressorStateFactory_getFactory
);
454 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DISTORTION
, ALdistortionStateFactory_getFactory
);
455 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_ECHO
, ALechoStateFactory_getFactory
);
456 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EQUALIZER
, ALequalizerStateFactory_getFactory
);
457 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_FLANGER
, ALflangerStateFactory_getFactory
);
458 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_RING_MODULATOR
, ALmodulatorStateFactory_getFactory
);
459 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_DIALOGUE
, ALdedicatedStateFactory_getFactory
);
460 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
, ALdedicatedStateFactory_getFactory
);
463 void DeinitEffectFactoryMap(void)
465 ResetUIntMap(&EffectStateFactoryMap
);
469 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
471 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
472 ALeffectStateFactory
*factory
;
474 if(newtype
!= EffectSlot
->Effect
.Type
)
476 ALeffectState
*State
;
479 factory
= getFactoryByType(newtype
);
482 ERR("Failed to find factory for effect type 0x%04x\n", newtype
);
483 return AL_INVALID_ENUM
;
485 State
= V0(factory
,create
)();
486 if(!State
) return AL_OUT_OF_MEMORY
;
488 SetMixerFPUMode(&oldMode
);
489 almtx_lock(&Device
->BackendLock
);
490 State
->OutBuffer
= Device
->Dry
.Buffer
;
491 State
->OutChannels
= Device
->Dry
.NumChannels
;
492 if(V(State
,deviceUpdate
)(Device
) == AL_FALSE
)
494 almtx_unlock(&Device
->BackendLock
);
495 RestoreFPUMode(&oldMode
);
497 return AL_OUT_OF_MEMORY
;
499 almtx_unlock(&Device
->BackendLock
);
500 RestoreFPUMode(&oldMode
);
504 EffectSlot
->Effect
.Type
= AL_EFFECT_NULL
;
505 memset(&EffectSlot
->Effect
.Props
, 0, sizeof(EffectSlot
->Effect
.Props
));
509 EffectSlot
->Effect
.Type
= effect
->type
;
510 EffectSlot
->Effect
.Props
= effect
->Props
;
513 EffectSlot
->Effect
.State
= State
;
514 UpdateEffectSlotProps(EffectSlot
);
518 EffectSlot
->Effect
.Props
= effect
->Props
;
519 UpdateEffectSlotProps(EffectSlot
);
526 void ALeffectState_Destruct(ALeffectState
*UNUSED(state
))
531 ALenum
InitEffectSlot(ALeffectslot
*slot
)
533 ALeffectStateFactory
*factory
;
535 slot
->Effect
.Type
= AL_EFFECT_NULL
;
537 factory
= getFactoryByType(AL_EFFECT_NULL
);
538 if(!(slot
->Effect
.State
=V0(factory
,create
)()))
539 return AL_OUT_OF_MEMORY
;
542 slot
->AuxSendAuto
= AL_TRUE
;
543 InitRef(&slot
->ref
, 0);
545 ATOMIC_INIT(&slot
->Update
, NULL
);
546 ATOMIC_INIT(&slot
->FreeList
, NULL
);
548 slot
->Params
.Gain
= 1.0f
;
549 slot
->Params
.AuxSendAuto
= AL_TRUE
;
550 slot
->Params
.EffectState
= slot
->Effect
.State
;
551 slot
->Params
.RoomRolloff
= 0.0f
;
552 slot
->Params
.DecayTime
= 0.0f
;
553 slot
->Params
.AirAbsorptionGainHF
= 1.0f
;
555 ATOMIC_INIT(&slot
->next
, NULL
);
560 void DeinitEffectSlot(ALeffectslot
*slot
)
562 struct ALeffectslotProps
*props
;
563 ALeffectState
*state
;
566 props
= ATOMIC_LOAD(&slot
->Update
);
569 state
= ATOMIC_LOAD(&props
->State
, almemory_order_relaxed
);
570 if(state
!= slot
->Params
.EffectState
)
572 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props
);
575 props
= ATOMIC_LOAD(&slot
->FreeList
, almemory_order_relaxed
);
578 struct ALeffectslotProps
*next
;
579 state
= ATOMIC_LOAD(&props
->State
, almemory_order_relaxed
);
580 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
586 TRACE("Freed "SZFMT
" AuxiliaryEffectSlot property object%s\n", count
, (count
==1)?"":"s");
588 DELETE_OBJ(slot
->Params
.EffectState
);
591 void UpdateEffectSlotProps(ALeffectslot
*slot
)
593 struct ALeffectslotProps
*props
;
594 ALeffectState
*oldstate
;
596 props
= ATOMIC_EXCHANGE(struct ALeffectslotProps
*, &slot
->Update
, NULL
);
599 /* If there was an unapplied update, check if its state object is the
600 * same as the current in-use one, or the one that will be set. If
601 * neither, delete it.
603 oldstate
= ATOMIC_EXCHANGE(ALeffectState
*, &props
->State
, NULL
, almemory_order_relaxed
);
604 if(oldstate
!= slot
->Params
.EffectState
&& oldstate
!= slot
->Effect
.State
)
605 DELETE_OBJ(oldstate
);
609 /* Get an unused property container, or allocate a new one as needed. */
610 props
= ATOMIC_LOAD(&slot
->FreeList
, almemory_order_relaxed
);
612 props
= al_calloc(16, sizeof(*props
));
615 struct ALeffectslotProps
*next
;
617 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
618 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps
*,
619 &slot
->FreeList
, &props
, next
, almemory_order_seq_cst
,
620 almemory_order_consume
) == 0);
624 /* Copy in current property values. */
625 ATOMIC_STORE(&props
->Gain
, slot
->Gain
, almemory_order_relaxed
);
626 ATOMIC_STORE(&props
->AuxSendAuto
, slot
->AuxSendAuto
, almemory_order_relaxed
);
628 ATOMIC_STORE(&props
->Type
, slot
->Effect
.Type
, almemory_order_relaxed
);
629 props
->Props
= slot
->Effect
.Props
;
630 /* Swap out any stale effect state object there may be in the container, to
633 oldstate
= ATOMIC_EXCHANGE(ALeffectState
*, &props
->State
, slot
->Effect
.State
,
634 almemory_order_relaxed
);
636 /* Set the new container for updating internal parameters. */
637 props
= ATOMIC_EXCHANGE(struct ALeffectslotProps
*, &slot
->Update
, props
,
638 almemory_order_acq_rel
);
641 /* If there was an unused update container, put it back in the
644 struct ALeffectslotProps
*first
= ATOMIC_LOAD(&slot
->FreeList
);
646 ATOMIC_STORE(&props
->next
, first
, almemory_order_relaxed
);
647 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps
*,
648 &slot
->FreeList
, &first
, props
) == 0);
651 DELETE_OBJ(oldstate
);
654 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
657 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
659 ALeffectslot
*temp
= Context
->EffectSlotMap
.values
[pos
];
660 Context
->EffectSlotMap
.values
[pos
] = NULL
;
662 DeinitEffectSlot(temp
);
664 FreeThunkEntry(temp
->id
);
665 memset(temp
, 0, sizeof(ALeffectslot
));