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"
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 aluInitEffectPanning(slot
);
95 VECTOR_PUSH_BACK(slotvec
, slot
);
97 effectslots
[cur
] = slot
->id
;
99 err
= AddEffectSlotArray(context
, VECTOR_ITER_BEGIN(slotvec
), n
);
100 if(err
!= AL_NO_ERROR
)
102 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
103 SET_ERROR_AND_GOTO(context
, err
, done
);
107 VECTOR_DEINIT(slotvec
);
109 ALCcontext_DecRef(context
);
112 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
118 context
= GetContextRef();
122 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
125 if((slot
=LookupEffectSlot(context
, effectslots
[i
])) == NULL
)
126 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
127 if(ReadRef(&slot
->ref
) != 0)
128 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
131 // All effectslots are valid
134 if((slot
=RemoveEffectSlot(context
, effectslots
[i
])) == NULL
)
136 FreeThunkEntry(slot
->id
);
138 RemoveEffectSlotArray(context
, slot
);
139 DELETE_OBJ(slot
->EffectState
);
141 memset(slot
, 0, sizeof(*slot
));
146 ALCcontext_DecRef(context
);
149 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
154 context
= GetContextRef();
155 if(!context
) return AL_FALSE
;
157 ret
= (LookupEffectSlot(context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
159 ALCcontext_DecRef(context
);
164 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
169 ALeffect
*effect
= NULL
;
172 context
= GetContextRef();
175 device
= context
->Device
;
176 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
177 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
180 case AL_EFFECTSLOT_EFFECT
:
181 effect
= (value
? LookupEffect(device
, value
) : NULL
);
182 if(!(value
== 0 || effect
!= NULL
))
183 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
185 err
= InitializeEffect(device
, slot
, effect
);
186 if(err
!= AL_NO_ERROR
)
187 SET_ERROR_AND_GOTO(context
, err
, done
);
188 ATOMIC_STORE(&context
->UpdateSources
, AL_TRUE
);
191 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
192 if(!(value
== AL_TRUE
|| value
== AL_FALSE
))
193 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
195 slot
->AuxSendAuto
= value
;
196 ATOMIC_STORE(&context
->UpdateSources
, AL_TRUE
);
200 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
204 ALCcontext_DecRef(context
);
207 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
213 case AL_EFFECTSLOT_EFFECT
:
214 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
215 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
219 context
= GetContextRef();
222 if(LookupEffectSlot(context
, effectslot
) == NULL
)
223 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
227 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
231 ALCcontext_DecRef(context
);
234 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
239 context
= GetContextRef();
242 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
243 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
246 case AL_EFFECTSLOT_GAIN
:
247 if(!(value
>= 0.0f
&& value
<= 1.0f
))
248 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
251 ATOMIC_STORE(&slot
->NeedsUpdate
, AL_TRUE
);
255 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
259 ALCcontext_DecRef(context
);
262 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
268 case AL_EFFECTSLOT_GAIN
:
269 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
273 context
= GetContextRef();
276 if(LookupEffectSlot(context
, effectslot
) == NULL
)
277 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
281 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
285 ALCcontext_DecRef(context
);
288 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
293 context
= GetContextRef();
296 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
297 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
300 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
301 *value
= slot
->AuxSendAuto
;
305 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
309 ALCcontext_DecRef(context
);
312 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
318 case AL_EFFECTSLOT_EFFECT
:
319 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
320 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
324 context
= GetContextRef();
327 if(LookupEffectSlot(context
, effectslot
) == NULL
)
328 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
332 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
336 ALCcontext_DecRef(context
);
339 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
344 context
= GetContextRef();
347 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
348 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
351 case AL_EFFECTSLOT_GAIN
:
356 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
360 ALCcontext_DecRef(context
);
363 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
369 case AL_EFFECTSLOT_GAIN
:
370 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
374 context
= GetContextRef();
377 if(LookupEffectSlot(context
, effectslot
) == NULL
)
378 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
382 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
386 ALCcontext_DecRef(context
);
390 static ALenum
AddEffectSlotArray(ALCcontext
*context
, ALeffectslot
**start
, ALsizei count
)
392 ALenum err
= AL_NO_ERROR
;
394 LockContext(context
);
395 if(!VECTOR_INSERT(context
->ActiveAuxSlots
, VECTOR_ITER_END(context
->ActiveAuxSlots
), start
, start
+count
))
396 err
= AL_OUT_OF_MEMORY
;
397 UnlockContext(context
);
402 static void RemoveEffectSlotArray(ALCcontext
*context
, const ALeffectslot
*slot
)
406 LockContext(context
);
407 #define MATCH_SLOT(_i) (slot == *(_i))
408 VECTOR_FIND_IF(iter
, ALeffectslot
*, context
->ActiveAuxSlots
, MATCH_SLOT
);
409 if(iter
!= VECTOR_ITER_END(context
->ActiveAuxSlots
))
411 *iter
= VECTOR_BACK(context
->ActiveAuxSlots
);
412 VECTOR_POP_BACK(context
->ActiveAuxSlots
);
415 UnlockContext(context
);
419 void InitEffectFactoryMap(void)
421 InitUIntMap(&EffectStateFactoryMap
, ~0);
423 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_NULL
, ALnullStateFactory_getFactory
);
424 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EAXREVERB
, ALreverbStateFactory_getFactory
);
425 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_REVERB
, ALreverbStateFactory_getFactory
);
426 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_AUTOWAH
, ALautowahStateFactory_getFactory
);
427 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_CHORUS
, ALchorusStateFactory_getFactory
);
428 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_COMPRESSOR
, ALcompressorStateFactory_getFactory
);
429 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DISTORTION
, ALdistortionStateFactory_getFactory
);
430 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_ECHO
, ALechoStateFactory_getFactory
);
431 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EQUALIZER
, ALequalizerStateFactory_getFactory
);
432 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_FLANGER
, ALflangerStateFactory_getFactory
);
433 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_RING_MODULATOR
, ALmodulatorStateFactory_getFactory
);
434 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_DIALOGUE
, ALdedicatedStateFactory_getFactory
);
435 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
, ALdedicatedStateFactory_getFactory
);
438 void DeinitEffectFactoryMap(void)
440 ResetUIntMap(&EffectStateFactoryMap
);
444 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
446 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
447 ALeffectStateFactory
*factory
;
449 if(newtype
!= EffectSlot
->EffectType
)
451 ALeffectState
*State
;
454 factory
= getFactoryByType(newtype
);
457 ERR("Failed to find factory for effect type 0x%04x\n", newtype
);
458 return AL_INVALID_ENUM
;
460 State
= V0(factory
,create
)();
462 return AL_OUT_OF_MEMORY
;
464 SetMixerFPUMode(&oldMode
);
466 ALCdevice_Lock(Device
);
467 if(V(State
,deviceUpdate
)(Device
) == AL_FALSE
)
469 ALCdevice_Unlock(Device
);
470 RestoreFPUMode(&oldMode
);
472 return AL_OUT_OF_MEMORY
;
475 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
478 memset(&EffectSlot
->EffectProps
, 0, sizeof(EffectSlot
->EffectProps
));
479 EffectSlot
->EffectType
= AL_EFFECT_NULL
;
483 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
484 EffectSlot
->EffectType
= effect
->type
;
487 /* FIXME: This should be done asynchronously, but since the EffectState
488 * object was changed, it needs an update before its Process method can
490 ATOMIC_STORE(&EffectSlot
->NeedsUpdate
, AL_FALSE
);
491 V(EffectSlot
->EffectState
,update
)(Device
, EffectSlot
);
492 ALCdevice_Unlock(Device
);
494 RestoreFPUMode(&oldMode
);
503 ALCdevice_Lock(Device
);
504 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
505 ALCdevice_Unlock(Device
);
506 ATOMIC_STORE(&EffectSlot
->NeedsUpdate
, AL_TRUE
);
514 ALenum
InitEffectSlot(ALeffectslot
*slot
)
516 ALeffectStateFactory
*factory
;
519 slot
->EffectType
= AL_EFFECT_NULL
;
521 factory
= getFactoryByType(AL_EFFECT_NULL
);
522 if(!(slot
->EffectState
=V0(factory
,create
)()))
523 return AL_OUT_OF_MEMORY
;
526 slot
->AuxSendAuto
= AL_TRUE
;
527 ATOMIC_INIT(&slot
->NeedsUpdate
, AL_FALSE
);
530 for(i
= 0;i
< BUFFERSIZE
;i
++)
531 slot
->WetBuffer
[c
][i
] = 0.0f
;
533 InitRef(&slot
->ref
, 0);
538 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
541 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
543 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
544 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
546 DELETE_OBJ(temp
->EffectState
);
548 FreeThunkEntry(temp
->id
);
549 memset(temp
, 0, sizeof(ALeffectslot
));