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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
29 #include "alAuxEffectSlot.h"
35 extern inline struct ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
);
36 extern inline struct ALeffectslot
*RemoveEffectSlot(ALCcontext
*context
, ALuint id
);
38 static ALenum
AddEffectSlotArray(ALCcontext
*Context
, ALeffectslot
**start
, ALsizei count
);
39 static void RemoveEffectSlotArray(ALCcontext
*Context
, const ALeffectslot
*slot
);
42 static UIntMap EffectStateFactoryMap
;
43 static inline ALeffectStateFactory
*getFactoryByType(ALenum type
)
45 ALeffectStateFactory
* (*getFactory
)(void) = LookupUIntMapKey(&EffectStateFactoryMap
, type
);
46 if(getFactory
!= NULL
)
52 AL_API ALvoid AL_APIENTRY
alGenAuxiliaryEffectSlots(ALsizei n
, ALuint
*effectslots
)
55 VECTOR(ALeffectslot
*) slotvec
;
59 context
= GetContextRef();
65 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
66 if(!VECTOR_RESERVE(slotvec
, n
))
67 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
69 for(cur
= 0;cur
< n
;cur
++)
71 ALeffectslot
*slot
= al_calloc(16, sizeof(ALeffectslot
));
72 err
= AL_OUT_OF_MEMORY
;
73 if(!slot
|| (err
=InitEffectSlot(slot
)) != AL_NO_ERROR
)
76 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
77 SET_ERROR_AND_GOTO(context
, err
, done
);
80 err
= NewThunkEntry(&slot
->id
);
81 if(err
== AL_NO_ERROR
)
82 err
= InsertUIntMapEntry(&context
->EffectSlotMap
, slot
->id
, slot
);
83 if(err
!= AL_NO_ERROR
)
85 FreeThunkEntry(slot
->id
);
86 DELETE_OBJ(slot
->EffectState
);
89 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
90 SET_ERROR_AND_GOTO(context
, err
, done
);
93 VECTOR_PUSH_BACK(slotvec
, slot
);
95 effectslots
[cur
] = slot
->id
;
97 err
= AddEffectSlotArray(context
, VECTOR_ITER_BEGIN(slotvec
), n
);
98 if(err
!= AL_NO_ERROR
)
100 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
101 SET_ERROR_AND_GOTO(context
, err
, done
);
105 VECTOR_DEINIT(slotvec
);
107 ALCcontext_DecRef(context
);
110 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
116 context
= GetContextRef();
120 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
123 if((slot
=LookupEffectSlot(context
, effectslots
[i
])) == NULL
)
124 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
125 if(ReadRef(&slot
->ref
) != 0)
126 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
129 // All effectslots are valid
132 if((slot
=RemoveEffectSlot(context
, effectslots
[i
])) == NULL
)
134 FreeThunkEntry(slot
->id
);
136 RemoveEffectSlotArray(context
, slot
);
137 DELETE_OBJ(slot
->EffectState
);
139 memset(slot
, 0, sizeof(*slot
));
144 ALCcontext_DecRef(context
);
147 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
152 context
= GetContextRef();
153 if(!context
) return AL_FALSE
;
155 ret
= (LookupEffectSlot(context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
157 ALCcontext_DecRef(context
);
162 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
167 ALeffect
*effect
= NULL
;
170 context
= GetContextRef();
173 device
= context
->Device
;
174 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
175 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
178 case AL_EFFECTSLOT_EFFECT
:
179 effect
= (value
? LookupEffect(device
, value
) : NULL
);
180 if(!(value
== 0 || effect
!= NULL
))
181 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
183 err
= InitializeEffect(device
, slot
, effect
);
184 if(err
!= AL_NO_ERROR
)
185 SET_ERROR_AND_GOTO(context
, err
, done
);
186 ATOMIC_STORE(context
->UpdateSources
, AL_TRUE
);
189 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
190 if(!(value
== AL_TRUE
|| value
== AL_FALSE
))
191 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
193 slot
->AuxSendAuto
= value
;
194 ATOMIC_STORE(context
->UpdateSources
, AL_TRUE
);
198 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
202 ALCcontext_DecRef(context
);
205 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
211 case AL_EFFECTSLOT_EFFECT
:
212 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
213 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
217 context
= GetContextRef();
220 if(LookupEffectSlot(context
, effectslot
) == NULL
)
221 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
225 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
229 ALCcontext_DecRef(context
);
232 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
237 context
= GetContextRef();
240 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
241 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
244 case AL_EFFECTSLOT_GAIN
:
245 if(!(value
>= 0.0f
&& value
<= 1.0f
))
246 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
249 slot
->NeedsUpdate
= AL_TRUE
;
253 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
257 ALCcontext_DecRef(context
);
260 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
266 case AL_EFFECTSLOT_GAIN
:
267 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
271 context
= GetContextRef();
274 if(LookupEffectSlot(context
, effectslot
) == NULL
)
275 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
279 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
283 ALCcontext_DecRef(context
);
286 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
291 context
= GetContextRef();
294 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
295 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
298 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
299 *value
= slot
->AuxSendAuto
;
303 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
307 ALCcontext_DecRef(context
);
310 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
316 case AL_EFFECTSLOT_EFFECT
:
317 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
318 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
322 context
= GetContextRef();
325 if(LookupEffectSlot(context
, effectslot
) == NULL
)
326 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
330 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
334 ALCcontext_DecRef(context
);
337 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
342 context
= GetContextRef();
345 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
346 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
349 case AL_EFFECTSLOT_GAIN
:
354 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
358 ALCcontext_DecRef(context
);
361 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
367 case AL_EFFECTSLOT_GAIN
:
368 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
372 context
= GetContextRef();
375 if(LookupEffectSlot(context
, effectslot
) == NULL
)
376 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
380 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
384 ALCcontext_DecRef(context
);
388 static ALenum
AddEffectSlotArray(ALCcontext
*context
, ALeffectslot
**start
, ALsizei count
)
390 ALenum err
= AL_NO_ERROR
;
392 LockContext(context
);
393 if(!VECTOR_INSERT(context
->ActiveAuxSlots
, VECTOR_ITER_END(context
->ActiveAuxSlots
), start
, start
+count
))
394 err
= AL_OUT_OF_MEMORY
;
395 UnlockContext(context
);
400 static void RemoveEffectSlotArray(ALCcontext
*context
, const ALeffectslot
*slot
)
404 LockContext(context
);
405 #define MATCH_SLOT(_i) (slot == *(_i))
406 VECTOR_FIND_IF(iter
, ALeffectslot
*, context
->ActiveAuxSlots
, MATCH_SLOT
);
407 if(iter
!= VECTOR_ITER_END(context
->ActiveAuxSlots
))
409 *iter
= VECTOR_BACK(context
->ActiveAuxSlots
);
410 VECTOR_POP_BACK(context
->ActiveAuxSlots
);
413 UnlockContext(context
);
417 void InitEffectFactoryMap(void)
419 InitUIntMap(&EffectStateFactoryMap
, ~0);
421 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_NULL
, ALnullStateFactory_getFactory
);
422 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EAXREVERB
, ALreverbStateFactory_getFactory
);
423 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_REVERB
, ALreverbStateFactory_getFactory
);
424 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_AUTOWAH
, ALautowahStateFactory_getFactory
);
425 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_CHORUS
, ALchorusStateFactory_getFactory
);
426 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_COMPRESSOR
, ALcompressorStateFactory_getFactory
);
427 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DISTORTION
, ALdistortionStateFactory_getFactory
);
428 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_ECHO
, ALechoStateFactory_getFactory
);
429 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EQUALIZER
, ALequalizerStateFactory_getFactory
);
430 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_FLANGER
, ALflangerStateFactory_getFactory
);
431 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_RING_MODULATOR
, ALmodulatorStateFactory_getFactory
);
432 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_DIALOGUE
, ALdedicatedStateFactory_getFactory
);
433 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
, ALdedicatedStateFactory_getFactory
);
436 void DeinitEffectFactoryMap(void)
438 ResetUIntMap(&EffectStateFactoryMap
);
442 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
444 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
445 ALeffectStateFactory
*factory
;
447 if(newtype
!= EffectSlot
->EffectType
)
449 ALeffectState
*State
;
452 factory
= getFactoryByType(newtype
);
455 ERR("Failed to find factory for effect type 0x%04x\n", newtype
);
456 return AL_INVALID_ENUM
;
458 State
= V0(factory
,create
)();
460 return AL_OUT_OF_MEMORY
;
462 SetMixerFPUMode(&oldMode
);
464 ALCdevice_Lock(Device
);
465 if(V(State
,deviceUpdate
)(Device
) == AL_FALSE
)
467 ALCdevice_Unlock(Device
);
468 RestoreFPUMode(&oldMode
);
470 return AL_OUT_OF_MEMORY
;
473 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
476 memset(&EffectSlot
->EffectProps
, 0, sizeof(EffectSlot
->EffectProps
));
477 EffectSlot
->EffectType
= AL_EFFECT_NULL
;
481 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
482 EffectSlot
->EffectType
= effect
->type
;
485 /* FIXME: This should be done asynchronously, but since the EffectState
486 * object was changed, it needs an update before its Process method can
488 EffectSlot
->NeedsUpdate
= AL_FALSE
;
489 V(EffectSlot
->EffectState
,update
)(Device
, EffectSlot
);
490 ALCdevice_Unlock(Device
);
492 RestoreFPUMode(&oldMode
);
501 ALCdevice_Lock(Device
);
502 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
503 ALCdevice_Unlock(Device
);
504 EffectSlot
->NeedsUpdate
= AL_TRUE
;
512 ALenum
InitEffectSlot(ALeffectslot
*slot
)
514 ALeffectStateFactory
*factory
;
517 slot
->EffectType
= AL_EFFECT_NULL
;
519 factory
= getFactoryByType(AL_EFFECT_NULL
);
520 if(!(slot
->EffectState
=V0(factory
,create
)()))
521 return AL_OUT_OF_MEMORY
;
524 slot
->AuxSendAuto
= AL_TRUE
;
525 slot
->NeedsUpdate
= AL_FALSE
;
528 for(i
= 0;i
< BUFFERSIZE
;i
++)
529 slot
->WetBuffer
[c
][i
] = 0.0f
;
531 InitRef(&slot
->ref
, 0);
536 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
539 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
541 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
542 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
544 DELETE_OBJ(temp
->EffectState
);
546 FreeThunkEntry(temp
->id
);
547 memset(temp
, 0, sizeof(ALeffectslot
));