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"
37 extern inline struct ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
);
38 extern inline struct ALeffectslot
*RemoveEffectSlot(ALCcontext
*context
, ALuint id
);
40 static ALenum
AddEffectSlotArray(ALCcontext
*Context
, ALeffectslot
**start
, ALsizei count
);
41 static void RemoveEffectSlotArray(ALCcontext
*Context
, const ALeffectslot
*slot
);
44 static UIntMap EffectStateFactoryMap
;
45 static inline ALeffectStateFactory
*getFactoryByType(ALenum type
)
47 ALeffectStateFactory
* (*getFactory
)(void) = LookupUIntMapKey(&EffectStateFactoryMap
, type
);
48 if(getFactory
!= NULL
)
54 AL_API ALvoid AL_APIENTRY
alGenAuxiliaryEffectSlots(ALsizei n
, ALuint
*effectslots
)
57 VECTOR(ALeffectslot
*) slotvec
;
61 context
= GetContextRef();
67 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
68 if(!VECTOR_RESERVE(slotvec
, n
))
69 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
71 for(cur
= 0;cur
< n
;cur
++)
73 ALeffectslot
*slot
= al_calloc(16, sizeof(ALeffectslot
));
74 err
= AL_OUT_OF_MEMORY
;
75 if(!slot
|| (err
=InitEffectSlot(slot
)) != AL_NO_ERROR
)
78 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
79 SET_ERROR_AND_GOTO(context
, err
, done
);
82 err
= NewThunkEntry(&slot
->id
);
83 if(err
== AL_NO_ERROR
)
84 err
= InsertUIntMapEntry(&context
->EffectSlotMap
, slot
->id
, slot
);
85 if(err
!= AL_NO_ERROR
)
87 FreeThunkEntry(slot
->id
);
88 DELETE_OBJ(slot
->EffectState
);
91 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
92 SET_ERROR_AND_GOTO(context
, err
, done
);
95 aluInitEffectPanning(slot
);
97 VECTOR_PUSH_BACK(slotvec
, slot
);
99 effectslots
[cur
] = slot
->id
;
101 err
= AddEffectSlotArray(context
, VECTOR_BEGIN(slotvec
), n
);
102 if(err
!= AL_NO_ERROR
)
104 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
105 SET_ERROR_AND_GOTO(context
, err
, done
);
109 VECTOR_DEINIT(slotvec
);
111 ALCcontext_DecRef(context
);
114 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
120 context
= GetContextRef();
124 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
127 if((slot
=LookupEffectSlot(context
, effectslots
[i
])) == NULL
)
128 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
129 if(ReadRef(&slot
->ref
) != 0)
130 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
133 // All effectslots are valid
136 if((slot
=RemoveEffectSlot(context
, effectslots
[i
])) == NULL
)
138 FreeThunkEntry(slot
->id
);
140 RemoveEffectSlotArray(context
, slot
);
141 DELETE_OBJ(slot
->EffectState
);
143 memset(slot
, 0, sizeof(*slot
));
148 ALCcontext_DecRef(context
);
151 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
156 context
= GetContextRef();
157 if(!context
) return AL_FALSE
;
159 ret
= (LookupEffectSlot(context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
161 ALCcontext_DecRef(context
);
166 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
171 ALeffect
*effect
= NULL
;
174 context
= GetContextRef();
177 device
= context
->Device
;
178 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
179 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
182 case AL_EFFECTSLOT_EFFECT
:
183 effect
= (value
? LookupEffect(device
, value
) : NULL
);
184 if(!(value
== 0 || effect
!= NULL
))
185 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
187 err
= InitializeEffect(device
, slot
, effect
);
188 if(err
!= AL_NO_ERROR
)
189 SET_ERROR_AND_GOTO(context
, err
, done
);
190 ATOMIC_STORE(&context
->UpdateSources
, AL_TRUE
);
193 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
194 if(!(value
== AL_TRUE
|| value
== AL_FALSE
))
195 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
197 slot
->AuxSendAuto
= value
;
198 ATOMIC_STORE(&context
->UpdateSources
, AL_TRUE
);
202 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
206 ALCcontext_DecRef(context
);
209 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
215 case AL_EFFECTSLOT_EFFECT
:
216 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
217 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
221 context
= GetContextRef();
224 if(LookupEffectSlot(context
, effectslot
) == NULL
)
225 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
229 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
233 ALCcontext_DecRef(context
);
236 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
241 context
= GetContextRef();
244 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
245 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
248 case AL_EFFECTSLOT_GAIN
:
249 if(!(value
>= 0.0f
&& value
<= 1.0f
))
250 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
253 ATOMIC_STORE(&slot
->NeedsUpdate
, AL_TRUE
);
257 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
261 ALCcontext_DecRef(context
);
264 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
270 case AL_EFFECTSLOT_GAIN
:
271 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
275 context
= GetContextRef();
278 if(LookupEffectSlot(context
, effectslot
) == NULL
)
279 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
283 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
287 ALCcontext_DecRef(context
);
290 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
295 context
= GetContextRef();
298 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
299 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
302 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
303 *value
= slot
->AuxSendAuto
;
307 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
311 ALCcontext_DecRef(context
);
314 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
320 case AL_EFFECTSLOT_EFFECT
:
321 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
322 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
326 context
= GetContextRef();
329 if(LookupEffectSlot(context
, effectslot
) == NULL
)
330 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
334 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
338 ALCcontext_DecRef(context
);
341 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
346 context
= GetContextRef();
349 if((slot
=LookupEffectSlot(context
, effectslot
)) == NULL
)
350 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
353 case AL_EFFECTSLOT_GAIN
:
358 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
362 ALCcontext_DecRef(context
);
365 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
371 case AL_EFFECTSLOT_GAIN
:
372 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
376 context
= GetContextRef();
379 if(LookupEffectSlot(context
, effectslot
) == NULL
)
380 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
384 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
388 ALCcontext_DecRef(context
);
392 static ALenum
AddEffectSlotArray(ALCcontext
*context
, ALeffectslot
**start
, ALsizei count
)
394 ALenum err
= AL_NO_ERROR
;
396 LockContext(context
);
397 if(!VECTOR_INSERT(context
->ActiveAuxSlots
, VECTOR_END(context
->ActiveAuxSlots
), start
, start
+count
))
398 err
= AL_OUT_OF_MEMORY
;
399 UnlockContext(context
);
404 static void RemoveEffectSlotArray(ALCcontext
*context
, const ALeffectslot
*slot
)
408 LockContext(context
);
409 #define MATCH_SLOT(_i) (slot == *(_i))
410 VECTOR_FIND_IF(iter
, ALeffectslot
*, context
->ActiveAuxSlots
, MATCH_SLOT
);
411 if(iter
!= VECTOR_END(context
->ActiveAuxSlots
))
413 *iter
= VECTOR_BACK(context
->ActiveAuxSlots
);
414 VECTOR_POP_BACK(context
->ActiveAuxSlots
);
417 UnlockContext(context
);
421 void InitEffectFactoryMap(void)
423 InitUIntMap(&EffectStateFactoryMap
, ~0);
425 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_NULL
, ALnullStateFactory_getFactory
);
426 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EAXREVERB
, ALreverbStateFactory_getFactory
);
427 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_REVERB
, ALreverbStateFactory_getFactory
);
428 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_AUTOWAH
, ALautowahStateFactory_getFactory
);
429 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_CHORUS
, ALchorusStateFactory_getFactory
);
430 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_COMPRESSOR
, ALcompressorStateFactory_getFactory
);
431 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DISTORTION
, ALdistortionStateFactory_getFactory
);
432 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_ECHO
, ALechoStateFactory_getFactory
);
433 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_EQUALIZER
, ALequalizerStateFactory_getFactory
);
434 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_FLANGER
, ALflangerStateFactory_getFactory
);
435 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_RING_MODULATOR
, ALmodulatorStateFactory_getFactory
);
436 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_DIALOGUE
, ALdedicatedStateFactory_getFactory
);
437 InsertUIntMapEntry(&EffectStateFactoryMap
, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
, ALdedicatedStateFactory_getFactory
);
440 void DeinitEffectFactoryMap(void)
442 ResetUIntMap(&EffectStateFactoryMap
);
446 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
448 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
449 ALeffectStateFactory
*factory
;
451 if(newtype
!= EffectSlot
->EffectType
)
453 ALeffectState
*State
;
456 factory
= getFactoryByType(newtype
);
459 ERR("Failed to find factory for effect type 0x%04x\n", newtype
);
460 return AL_INVALID_ENUM
;
462 State
= V0(factory
,create
)();
464 return AL_OUT_OF_MEMORY
;
466 SetMixerFPUMode(&oldMode
);
468 ALCdevice_Lock(Device
);
469 State
->OutBuffer
= Device
->Dry
.Buffer
;
470 State
->OutChannels
= Device
->Dry
.NumChannels
;
471 if(V(State
,deviceUpdate
)(Device
) == AL_FALSE
)
473 ALCdevice_Unlock(Device
);
474 RestoreFPUMode(&oldMode
);
476 return AL_OUT_OF_MEMORY
;
479 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
482 memset(&EffectSlot
->EffectProps
, 0, sizeof(EffectSlot
->EffectProps
));
483 EffectSlot
->EffectType
= AL_EFFECT_NULL
;
487 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
488 EffectSlot
->EffectType
= effect
->type
;
491 /* FIXME: This should be done asynchronously, but since the EffectState
492 * object was changed, it needs an update before its Process method can
494 ATOMIC_STORE(&EffectSlot
->NeedsUpdate
, AL_FALSE
);
495 V(EffectSlot
->EffectState
,update
)(Device
, EffectSlot
);
496 ALCdevice_Unlock(Device
);
498 RestoreFPUMode(&oldMode
);
507 ALCdevice_Lock(Device
);
508 memcpy(&EffectSlot
->EffectProps
, &effect
->Props
, sizeof(effect
->Props
));
509 ALCdevice_Unlock(Device
);
510 ATOMIC_STORE(&EffectSlot
->NeedsUpdate
, AL_TRUE
);
518 ALenum
InitEffectSlot(ALeffectslot
*slot
)
520 ALeffectStateFactory
*factory
;
523 slot
->EffectType
= AL_EFFECT_NULL
;
525 factory
= getFactoryByType(AL_EFFECT_NULL
);
526 if(!(slot
->EffectState
=V0(factory
,create
)()))
527 return AL_OUT_OF_MEMORY
;
530 slot
->AuxSendAuto
= AL_TRUE
;
531 ATOMIC_INIT(&slot
->NeedsUpdate
, AL_FALSE
);
534 for(i
= 0;i
< BUFFERSIZE
;i
++)
535 slot
->WetBuffer
[c
][i
] = 0.0f
;
537 InitRef(&slot
->ref
, 0);
542 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
545 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
547 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
548 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
550 DELETE_OBJ(temp
->EffectState
);
552 FreeThunkEntry(temp
->id
);
553 memset(temp
, 0, sizeof(ALeffectslot
));