Don't try to use the non-standard alloca.h
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob9f554cb037b133cb15ba9ec4437bd10d7955429c
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
26 #include "AL/al.h"
27 #include "AL/alc.h"
28 #include "alMain.h"
29 #include "alAuxEffectSlot.h"
30 #include "alThunk.h"
31 #include "alError.h"
32 #include "alSource.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, const_vector_ALeffectslotPtr slots);
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)
47 return getFactory();
48 return NULL;
52 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
54 ALCcontext *context;
55 vector_ALeffectslotPtr slotvec;
56 ALsizei cur;
57 ALenum err;
59 context = GetContextRef();
60 if(!context) return;
62 VECTOR_INIT(slotvec);
64 if(!(n >= 0))
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)
75 al_free(slot);
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);
87 al_free(slot);
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, slotvec);
98 if(err != AL_NO_ERROR)
100 alDeleteAuxiliaryEffectSlots(cur, effectslots);
101 SET_ERROR_AND_GOTO(context, err, done);
104 done:
105 VECTOR_DEINIT(slotvec);
107 ALCcontext_DecRef(context);
110 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
112 ALCcontext *context;
113 ALeffectslot *slot;
114 ALsizei i;
116 context = GetContextRef();
117 if(!context) return;
119 if(!(n >= 0))
120 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
121 for(i = 0;i < n;i++)
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
130 for(i = 0;i < n;i++)
132 if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
133 continue;
134 FreeThunkEntry(slot->id);
136 RemoveEffectSlotArray(context, slot);
137 DELETE_OBJ(slot->EffectState);
139 memset(slot, 0, sizeof(*slot));
140 al_free(slot);
143 done:
144 ALCcontext_DecRef(context);
147 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
149 ALCcontext *context;
150 ALboolean ret;
152 context = GetContextRef();
153 if(!context) return AL_FALSE;
155 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
157 ALCcontext_DecRef(context);
159 return ret;
162 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
164 ALCdevice *device;
165 ALCcontext *context;
166 ALeffectslot *slot;
167 ALeffect *effect = NULL;
168 ALenum err;
170 context = GetContextRef();
171 if(!context) return;
173 device = context->Device;
174 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
175 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
176 switch(param)
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 context->UpdateSources = AL_TRUE;
187 break;
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 context->UpdateSources = AL_TRUE;
195 break;
197 default:
198 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
201 done:
202 ALCcontext_DecRef(context);
205 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
207 ALCcontext *context;
209 switch(param)
211 case AL_EFFECTSLOT_EFFECT:
212 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
213 alAuxiliaryEffectSloti(effectslot, param, values[0]);
214 return;
217 context = GetContextRef();
218 if(!context) return;
220 if(LookupEffectSlot(context, effectslot) == NULL)
221 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
222 switch(param)
224 default:
225 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
228 done:
229 ALCcontext_DecRef(context);
232 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
234 ALCcontext *context;
235 ALeffectslot *slot;
237 context = GetContextRef();
238 if(!context) return;
240 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
241 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
242 switch(param)
244 case AL_EFFECTSLOT_GAIN:
245 if(!(value >= 0.0f && value <= 1.0f))
246 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
248 slot->Gain = value;
249 slot->NeedsUpdate = AL_TRUE;
250 break;
252 default:
253 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
256 done:
257 ALCcontext_DecRef(context);
260 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
262 ALCcontext *context;
264 switch(param)
266 case AL_EFFECTSLOT_GAIN:
267 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
268 return;
271 context = GetContextRef();
272 if(!context) return;
274 if(LookupEffectSlot(context, effectslot) == NULL)
275 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
276 switch(param)
278 default:
279 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
282 done:
283 ALCcontext_DecRef(context);
286 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
288 ALCcontext *context;
289 ALeffectslot *slot;
291 context = GetContextRef();
292 if(!context) return;
294 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
295 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
296 switch(param)
298 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
299 *value = slot->AuxSendAuto;
300 break;
302 default:
303 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
306 done:
307 ALCcontext_DecRef(context);
310 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
312 ALCcontext *context;
314 switch(param)
316 case AL_EFFECTSLOT_EFFECT:
317 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
318 alGetAuxiliaryEffectSloti(effectslot, param, values);
319 return;
322 context = GetContextRef();
323 if(!context) return;
325 if(LookupEffectSlot(context, effectslot) == NULL)
326 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
327 switch(param)
329 default:
330 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
333 done:
334 ALCcontext_DecRef(context);
337 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
339 ALCcontext *context;
340 ALeffectslot *slot;
342 context = GetContextRef();
343 if(!context) return;
345 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
346 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
347 switch(param)
349 case AL_EFFECTSLOT_GAIN:
350 *value = slot->Gain;
351 break;
353 default:
354 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
357 done:
358 ALCcontext_DecRef(context);
361 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
363 ALCcontext *context;
365 switch(param)
367 case AL_EFFECTSLOT_GAIN:
368 alGetAuxiliaryEffectSlotf(effectslot, param, values);
369 return;
372 context = GetContextRef();
373 if(!context) return;
375 if(LookupEffectSlot(context, effectslot) == NULL)
376 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
377 switch(param)
379 default:
380 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
383 done:
384 ALCcontext_DecRef(context);
388 static ALenum AddEffectSlotArray(ALCcontext *context, const_vector_ALeffectslotPtr slots)
390 ALenum err = AL_NO_ERROR;
392 LockContext(context);
393 if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots),
394 VECTOR_ITER_BEGIN(slots), VECTOR_ITER_END(slots)))
395 err = AL_OUT_OF_MEMORY;
396 UnlockContext(context);
398 return err;
401 static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
403 ALeffectslot **slotlist, **slotlistend;
405 LockContext(context);
406 slotlist = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
407 slotlistend = VECTOR_ITER_END(context->ActiveAuxSlots);
408 while(slotlist != slotlistend)
410 if(*slotlist == slot)
412 *slotlist = VECTOR_BACK(context->ActiveAuxSlots);
413 VECTOR_POP_BACK(context->ActiveAuxSlots);
414 break;
416 slotlist++;
418 UnlockContext(context);
422 void InitEffectFactoryMap(void)
424 InitUIntMap(&EffectStateFactoryMap, ~0);
426 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
427 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
428 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
429 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_AUTOWAH, ALautowahStateFactory_getFactory);
430 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
431 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
432 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
433 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
434 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
435 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
436 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
437 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
438 InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
441 void DeinitEffectFactoryMap(void)
443 ResetUIntMap(&EffectStateFactoryMap);
447 ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
449 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
450 ALeffectStateFactory *factory;
452 if(newtype != EffectSlot->EffectType)
454 ALeffectState *State;
455 FPUCtl oldMode;
457 factory = getFactoryByType(newtype);
458 if(!factory)
460 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
461 return AL_INVALID_ENUM;
463 State = V0(factory,create)();
464 if(!State)
465 return AL_OUT_OF_MEMORY;
467 SetMixerFPUMode(&oldMode);
469 ALCdevice_Lock(Device);
470 if(V(State,deviceUpdate)(Device) == AL_FALSE)
472 ALCdevice_Unlock(Device);
473 RestoreFPUMode(&oldMode);
474 DELETE_OBJ(State);
475 return AL_OUT_OF_MEMORY;
478 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
479 if(!effect)
481 memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
482 EffectSlot->EffectType = AL_EFFECT_NULL;
484 else
486 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
487 EffectSlot->EffectType = effect->type;
490 /* FIXME: This should be done asynchronously, but since the EffectState
491 * object was changed, it needs an update before its Process method can
492 * be called. */
493 EffectSlot->NeedsUpdate = AL_FALSE;
494 V(EffectSlot->EffectState,update)(Device, EffectSlot);
495 ALCdevice_Unlock(Device);
497 RestoreFPUMode(&oldMode);
499 DELETE_OBJ(State);
500 State = NULL;
502 else
504 if(effect)
506 ALCdevice_Lock(Device);
507 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
508 ALCdevice_Unlock(Device);
509 EffectSlot->NeedsUpdate = AL_TRUE;
513 return AL_NO_ERROR;
517 ALenum InitEffectSlot(ALeffectslot *slot)
519 ALeffectStateFactory *factory;
520 ALuint i, c;
522 slot->EffectType = AL_EFFECT_NULL;
524 factory = getFactoryByType(AL_EFFECT_NULL);
525 if(!(slot->EffectState=V0(factory,create)()))
526 return AL_OUT_OF_MEMORY;
528 slot->Gain = 1.0;
529 slot->AuxSendAuto = AL_TRUE;
530 slot->NeedsUpdate = AL_FALSE;
531 for(c = 0;c < 1;c++)
533 for(i = 0;i < BUFFERSIZE;i++)
534 slot->WetBuffer[c][i] = 0.0f;
536 InitRef(&slot->ref, 0);
538 return AL_NO_ERROR;
541 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
543 ALsizei pos;
544 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
546 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
547 Context->EffectSlotMap.array[pos].value = NULL;
549 DELETE_OBJ(temp->EffectState);
551 FreeThunkEntry(temp->id);
552 memset(temp, 0, sizeof(ALeffectslot));
553 al_free(temp);