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 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
)
55 AL_API ALvoid AL_APIENTRY
alGenAuxiliaryEffectSlots(ALsizei n
, ALuint
*effectslots
)
58 VECTOR(ALeffectslot
*) slotvec
;
62 context
= GetContextRef();
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
)
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 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
);
110 VECTOR_DEINIT(slotvec
);
112 ALCcontext_DecRef(context
);
115 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
121 context
= GetContextRef();
125 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
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
137 if((slot
=RemoveEffectSlot(context
, effectslots
[i
])) == NULL
)
139 FreeThunkEntry(slot
->id
);
141 RemoveEffectSlotArray(context
, slot
);
142 DeinitEffectSlot(slot
);
144 memset(slot
, 0, sizeof(*slot
));
149 ALCcontext_DecRef(context
);
152 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
157 context
= GetContextRef();
158 if(!context
) return AL_FALSE
;
160 ret
= (LookupEffectSlot(context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
162 ALCcontext_DecRef(context
);
167 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
172 ALeffect
*effect
= NULL
;
175 context
= GetContextRef();
178 WriteLock(&context
->PropLock
);
179 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
180 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
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
);
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
, AL_FALSE
);
208 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
212 WriteUnlock(&context
->PropLock
);
213 ALCcontext_DecRef(context
);
216 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
222 case AL_EFFECTSLOT_EFFECT
:
223 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
224 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
228 context
= GetContextRef();
231 if(LookupEffectSlot(context
, effectslot
) == NULL
)
232 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
236 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
240 ALCcontext_DecRef(context
);
243 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
248 context
= GetContextRef();
251 WriteLock(&context
->PropLock
);
252 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
253 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
256 case AL_EFFECTSLOT_GAIN
:
257 if(!(value
>= 0.0f
&& value
<= 1.0f
))
258 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
263 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
265 UpdateEffectSlotProps(slot
, AL_FALSE
);
268 WriteUnlock(&context
->PropLock
);
269 ALCcontext_DecRef(context
);
272 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
278 case AL_EFFECTSLOT_GAIN
:
279 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
283 context
= GetContextRef();
286 if(LookupEffectSlot(context
, effectslot
) == NULL
)
287 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
291 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
295 ALCcontext_DecRef(context
);
298 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
303 context
= GetContextRef();
306 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
307 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
310 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
311 *value
= slot
->AuxSendAuto
;
315 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
319 ALCcontext_DecRef(context
);
322 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
328 case AL_EFFECTSLOT_EFFECT
:
329 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
330 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
334 context
= GetContextRef();
337 if(LookupEffectSlot(context
, effectslot
) == NULL
)
338 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
342 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
346 ALCcontext_DecRef(context
);
349 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
354 context
= GetContextRef();
357 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
358 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
361 case AL_EFFECTSLOT_GAIN
:
366 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
370 ALCcontext_DecRef(context
);
373 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
379 case AL_EFFECTSLOT_GAIN
:
380 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
384 context
= GetContextRef();
387 if(LookupEffectSlot(context
, effectslot
) == NULL
)
388 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
392 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
396 ALCcontext_DecRef(context
);
400 static ALenum
AddEffectSlotArray(ALCcontext
*context
, ALeffectslot
**start
, ALsizei count
)
402 ALenum err
= AL_NO_ERROR
;
404 LockContext(context
);
405 if(!VECTOR_INSERT(context
->ActiveAuxSlots
, VECTOR_END(context
->ActiveAuxSlots
), start
, start
+count
))
406 err
= AL_OUT_OF_MEMORY
;
407 UnlockContext(context
);
412 static void RemoveEffectSlotArray(ALCcontext
*context
, const ALeffectslot
*slot
)
416 LockContext(context
);
417 #define MATCH_SLOT(_i) (slot == *(_i))
418 VECTOR_FIND_IF(iter
, ALeffectslot
*, context
->ActiveAuxSlots
, MATCH_SLOT
);
419 if(iter
!= VECTOR_END(context
->ActiveAuxSlots
))
421 *iter
= VECTOR_BACK(context
->ActiveAuxSlots
);
422 VECTOR_POP_BACK(context
->ActiveAuxSlots
);
425 UnlockContext(context
);
429 void InitEffectFactoryMap(void)
431 InitUIntMap(&EffectStateFactoryMap
, ~0);
433 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_NULL
, ALnullStateFactory_getFactory
);
434 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EAXREVERB
, ALreverbStateFactory_getFactory
);
435 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_REVERB
, ALreverbStateFactory_getFactory
);
436 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_AUTOWAH
, ALautowahStateFactory_getFactory
);
437 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_CHORUS
, ALchorusStateFactory_getFactory
);
438 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_COMPRESSOR
, ALcompressorStateFactory_getFactory
);
439 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DISTORTION
, ALdistortionStateFactory_getFactory
);
440 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_ECHO
, ALechoStateFactory_getFactory
);
441 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EQUALIZER
, ALequalizerStateFactory_getFactory
);
442 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_FLANGER
, ALflangerStateFactory_getFactory
);
443 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_RING_MODULATOR
, ALmodulatorStateFactory_getFactory
);
444 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_DIALOGUE
, ALdedicatedStateFactory_getFactory
);
445 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
, ALdedicatedStateFactory_getFactory
);
448 void DeinitEffectFactoryMap(void)
450 ResetUIntMap(&EffectStateFactoryMap
);
454 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
456 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
457 ALeffectStateFactory
*factory
;
459 if(newtype
!= EffectSlot
->Effect
.Type
)
461 ALeffectState
*State
;
464 factory
= getFactoryByType(newtype
);
467 ERR("Failed to find factory for effect type 0x%04x\n", newtype
);
468 return AL_INVALID_ENUM
;
470 State
= V0(factory
,create
)();
472 return AL_OUT_OF_MEMORY
;
474 SetMixerFPUMode(&oldMode
);
475 /* FIXME: This just needs to prevent the device from being reset during
476 * the state's device update, so the list lock in ALc.c should do here.
478 ALCdevice_Lock(Device
);
479 State
->OutBuffer
= Device
->Dry
.Buffer
;
480 State
->OutChannels
= Device
->Dry
.NumChannels
;
481 if(V(State
,deviceUpdate
)(Device
) == AL_FALSE
)
483 ALCdevice_Unlock(Device
);
484 RestoreFPUMode(&oldMode
);
486 return AL_OUT_OF_MEMORY
;
488 ALCdevice_Unlock(Device
);
489 RestoreFPUMode(&oldMode
);
493 EffectSlot
->Effect
.Type
= AL_EFFECT_NULL
;
494 memset(&EffectSlot
->Effect
.Props
, 0, sizeof(EffectSlot
->Effect
.Props
));
498 EffectSlot
->Effect
.Type
= effect
->type
;
499 memcpy(&EffectSlot
->Effect
.Props
, &effect
->Props
, sizeof(EffectSlot
->Effect
.Props
));
502 EffectSlot
->Effect
.State
= State
;
503 UpdateEffectSlotProps(EffectSlot
, AL_TRUE
);
507 memcpy(&EffectSlot
->Effect
.Props
, &effect
->Props
, sizeof(EffectSlot
->Effect
.Props
));
508 UpdateEffectSlotProps(EffectSlot
, AL_FALSE
);
515 void ALeffectState_Destruct(ALeffectState
*UNUSED(state
))
520 ALenum
InitEffectSlot(ALeffectslot
*slot
)
522 ALeffectStateFactory
*factory
;
524 slot
->Effect
.Type
= AL_EFFECT_NULL
;
526 factory
= getFactoryByType(AL_EFFECT_NULL
);
527 if(!(slot
->Effect
.State
=V0(factory
,create
)()))
528 return AL_OUT_OF_MEMORY
;
531 slot
->AuxSendAuto
= AL_TRUE
;
532 InitRef(&slot
->ref
, 0);
534 ATOMIC_INIT(&slot
->Update
, NULL
);
535 ATOMIC_INIT(&slot
->FreeList
, NULL
);
537 slot
->Params
.Gain
= 1.0f
;
538 slot
->Params
.AuxSendAuto
= AL_TRUE
;
539 slot
->Params
.EffectState
= slot
->Effect
.State
;
540 slot
->Params
.RoomRolloff
= 0.0f
;
541 slot
->Params
.DecayTime
= 0.0f
;
542 slot
->Params
.AirAbsorptionGainHF
= 1.0f
;
547 void DeinitEffectSlot(ALeffectslot
*slot
)
549 struct ALeffectslotProps
*props
;
552 props
= ATOMIC_LOAD(&slot
->Update
);
555 ALeffectState
*state
;
556 state
= ATOMIC_LOAD(&props
->State
, almemory_order_relaxed
);
558 TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props
);
561 props
= ATOMIC_LOAD(&slot
->FreeList
, almemory_order_relaxed
);
564 struct ALeffectslotProps
*next
;
565 ALeffectState
*state
;
566 state
= ATOMIC_LOAD(&props
->State
, almemory_order_relaxed
);
567 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
573 TRACE("Freed "SZFMT
" AuxiliaryEffectSlot property object%s\n", count
, (count
==1)?"":"s");
575 DELETE_OBJ(slot
->Params
.EffectState
);
578 void UpdateEffectSlotProps(ALeffectslot
*slot
, ALboolean withstate
)
580 struct ALeffectslotProps
*props
;
581 ALeffectState
*oldstate
;
583 /* Get an unused property container, or allocate a new one as needed. */
584 props
= ATOMIC_LOAD(&slot
->FreeList
, almemory_order_acquire
);
586 props
= al_calloc(16, sizeof(*props
));
589 struct ALeffectslotProps
*next
;
591 next
= ATOMIC_LOAD(&props
->next
, almemory_order_relaxed
);
592 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps
*,
593 &slot
->FreeList
, &props
, next
, almemory_order_seq_cst
,
594 almemory_order_consume
) == 0);
597 /* Copy in current property values. */
598 ATOMIC_STORE(&props
->Gain
, slot
->Gain
, almemory_order_relaxed
);
599 ATOMIC_STORE(&props
->AuxSendAuto
, slot
->AuxSendAuto
, almemory_order_relaxed
);
601 ATOMIC_STORE(&props
->Type
, slot
->Effect
.Type
, almemory_order_relaxed
);
602 memcpy(&props
->Props
, &slot
->Effect
.Props
, sizeof(props
->Props
));
603 /* Swap out any stale effect state object there may be in the container, to
606 ATOMIC_STORE(&props
->UpdateState
, withstate
, almemory_order_relaxed
);
607 oldstate
= ATOMIC_EXCHANGE(ALeffectState
*, &props
->State
,
608 withstate
? slot
->Effect
.State
: NULL
, almemory_order_relaxed
611 /* Set the new container for updating internal parameters. */
612 props
= ATOMIC_EXCHANGE(struct ALeffectslotProps
*, &slot
->Update
, props
,
613 almemory_order_acq_rel
);
616 /* If there was an unused update container, put it back in the
619 struct ALeffectslotProps
*first
= ATOMIC_LOAD(&slot
->FreeList
);
621 ATOMIC_STORE(&props
->next
, first
, almemory_order_relaxed
);
622 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps
*,
623 &slot
->FreeList
, &first
, props
) == 0);
626 DELETE_OBJ(oldstate
);
629 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
632 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
634 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
635 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
637 DeinitEffectSlot(temp
);
639 FreeThunkEntry(temp
->id
);
640 memset(temp
, 0, sizeof(ALeffectslot
));