Add a generic vector interface and use it for the active effect slots
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blobdcd64fc8561de1f00f656df20077d10db358a25a
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, ALsizei count, const ALuint *slots);
39 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, 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 ALsizei cur;
56 ALenum err;
58 context = GetContextRef();
59 if(!context) return;
61 if(!(n >= 0))
62 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
63 for(cur = 0;cur < n;cur++)
65 ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
66 err = AL_OUT_OF_MEMORY;
67 if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
69 al_free(slot);
70 alDeleteAuxiliaryEffectSlots(cur, effectslots);
71 SET_ERROR_AND_GOTO(context, err, done);
74 err = NewThunkEntry(&slot->id);
75 if(err == AL_NO_ERROR)
76 err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
77 if(err != AL_NO_ERROR)
79 FreeThunkEntry(slot->id);
80 DELETE_OBJ(slot->EffectState);
81 al_free(slot);
83 alDeleteAuxiliaryEffectSlots(cur, effectslots);
84 SET_ERROR_AND_GOTO(context, err, done);
87 effectslots[cur] = slot->id;
89 err = AddEffectSlotArray(context, n, effectslots);
90 if(err != AL_NO_ERROR)
92 alDeleteAuxiliaryEffectSlots(cur, effectslots);
93 SET_ERROR_AND_GOTO(context, err, done);
96 done:
97 ALCcontext_DecRef(context);
100 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
102 ALCcontext *context;
103 ALeffectslot *slot;
104 ALsizei i;
106 context = GetContextRef();
107 if(!context) return;
109 if(!(n >= 0))
110 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
111 for(i = 0;i < n;i++)
113 if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
114 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
115 if(slot->ref != 0)
116 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
119 // All effectslots are valid
120 for(i = 0;i < n;i++)
122 if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
123 continue;
124 FreeThunkEntry(slot->id);
126 RemoveEffectSlotArray(context, slot);
127 DELETE_OBJ(slot->EffectState);
129 memset(slot, 0, sizeof(*slot));
130 al_free(slot);
133 done:
134 ALCcontext_DecRef(context);
137 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
139 ALCcontext *context;
140 ALboolean ret;
142 context = GetContextRef();
143 if(!context) return AL_FALSE;
145 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
147 ALCcontext_DecRef(context);
149 return ret;
152 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
154 ALCdevice *device;
155 ALCcontext *context;
156 ALeffectslot *slot;
157 ALeffect *effect = NULL;
158 ALenum err;
160 context = GetContextRef();
161 if(!context) return;
163 device = context->Device;
164 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
165 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
166 switch(param)
168 case AL_EFFECTSLOT_EFFECT:
169 effect = (value ? LookupEffect(device, value) : NULL);
170 if(!(value == 0 || effect != NULL))
171 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
173 err = InitializeEffect(device, slot, effect);
174 if(err != AL_NO_ERROR)
175 SET_ERROR_AND_GOTO(context, err, done);
176 context->UpdateSources = AL_TRUE;
177 break;
179 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
180 if(!(value == AL_TRUE || value == AL_FALSE))
181 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
183 slot->AuxSendAuto = value;
184 context->UpdateSources = AL_TRUE;
185 break;
187 default:
188 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
191 done:
192 ALCcontext_DecRef(context);
195 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
197 ALCcontext *context;
199 switch(param)
201 case AL_EFFECTSLOT_EFFECT:
202 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
203 alAuxiliaryEffectSloti(effectslot, param, values[0]);
204 return;
207 context = GetContextRef();
208 if(!context) return;
210 if(LookupEffectSlot(context, effectslot) == NULL)
211 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
212 switch(param)
214 default:
215 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
218 done:
219 ALCcontext_DecRef(context);
222 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
224 ALCcontext *context;
225 ALeffectslot *slot;
227 context = GetContextRef();
228 if(!context) return;
230 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
231 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
232 switch(param)
234 case AL_EFFECTSLOT_GAIN:
235 if(!(value >= 0.0f && value <= 1.0f))
236 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
238 slot->Gain = value;
239 slot->NeedsUpdate = AL_TRUE;
240 break;
242 default:
243 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
246 done:
247 ALCcontext_DecRef(context);
250 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
252 ALCcontext *context;
254 switch(param)
256 case AL_EFFECTSLOT_GAIN:
257 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
258 return;
261 context = GetContextRef();
262 if(!context) return;
264 if(LookupEffectSlot(context, effectslot) == NULL)
265 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
266 switch(param)
268 default:
269 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
272 done:
273 ALCcontext_DecRef(context);
276 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
278 ALCcontext *context;
279 ALeffectslot *slot;
281 context = GetContextRef();
282 if(!context) return;
284 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
285 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
286 switch(param)
288 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
289 *value = slot->AuxSendAuto;
290 break;
292 default:
293 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
296 done:
297 ALCcontext_DecRef(context);
300 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
302 ALCcontext *context;
304 switch(param)
306 case AL_EFFECTSLOT_EFFECT:
307 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
308 alGetAuxiliaryEffectSloti(effectslot, param, values);
309 return;
312 context = GetContextRef();
313 if(!context) return;
315 if(LookupEffectSlot(context, effectslot) == NULL)
316 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
317 switch(param)
319 default:
320 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
323 done:
324 ALCcontext_DecRef(context);
327 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
329 ALCcontext *context;
330 ALeffectslot *slot;
332 context = GetContextRef();
333 if(!context) return;
335 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
336 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
337 switch(param)
339 case AL_EFFECTSLOT_GAIN:
340 *value = slot->Gain;
341 break;
343 default:
344 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
347 done:
348 ALCcontext_DecRef(context);
351 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
353 ALCcontext *context;
355 switch(param)
357 case AL_EFFECTSLOT_GAIN:
358 alGetAuxiliaryEffectSlotf(effectslot, param, values);
359 return;
362 context = GetContextRef();
363 if(!context) return;
365 if(LookupEffectSlot(context, effectslot) == NULL)
366 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
367 switch(param)
369 default:
370 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
373 done:
374 ALCcontext_DecRef(context);
378 static ALvoid RemoveEffectSlotArray(ALCcontext *context, ALeffectslot *slot)
380 ALeffectslot **slotlist, **slotlistend;
382 LockContext(context);
383 slotlist = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
384 slotlistend = VECTOR_ITER_END(context->ActiveAuxSlots);
385 while(slotlist != slotlistend)
387 if(*slotlist == slot)
389 *slotlist = *(--slotlistend);
390 VECTOR_POP_BACK(context->ActiveAuxSlots);
391 break;
393 slotlist++;
395 UnlockContext(context);
398 static ALenum AddEffectSlotArray(ALCcontext *context, ALsizei count, const ALuint *slots)
400 ALsizei total = count + VECTOR_SIZE(context->ActiveAuxSlots);
402 LockContext(context);
403 if(total < VECTOR_SIZE(context->ActiveAuxSlots) || VECTOR_RESERVE(context->ActiveAuxSlots, total) == AL_FALSE)
405 UnlockContext(context);
406 return AL_OUT_OF_MEMORY;
409 while(VECTOR_SIZE(context->ActiveAuxSlots) < total)
411 ALeffectslot *slot = LookupEffectSlot(context, *(slots++));
412 assert(slot != NULL);
413 VECTOR_PUSH_BACK(context->ActiveAuxSlots, slot);
415 UnlockContext(context);
417 return AL_NO_ERROR;
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;
454 FPUCtl oldMode;
456 factory = getFactoryByType(newtype);
457 if(!factory)
459 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
460 return AL_INVALID_ENUM;
462 State = V0(factory,create)();
463 if(!State)
464 return AL_OUT_OF_MEMORY;
466 SetMixerFPUMode(&oldMode);
468 ALCdevice_Lock(Device);
469 if(V(State,deviceUpdate)(Device) == AL_FALSE)
471 ALCdevice_Unlock(Device);
472 RestoreFPUMode(&oldMode);
473 DELETE_OBJ(State);
474 return AL_OUT_OF_MEMORY;
477 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
478 if(!effect)
480 memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
481 EffectSlot->EffectType = AL_EFFECT_NULL;
483 else
485 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
486 EffectSlot->EffectType = effect->type;
489 /* FIXME: This should be done asynchronously, but since the EffectState
490 * object was changed, it needs an update before its Process method can
491 * be called. */
492 EffectSlot->NeedsUpdate = AL_FALSE;
493 V(EffectSlot->EffectState,update)(Device, EffectSlot);
494 ALCdevice_Unlock(Device);
496 RestoreFPUMode(&oldMode);
498 DELETE_OBJ(State);
499 State = NULL;
501 else
503 if(effect)
505 ALCdevice_Lock(Device);
506 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
507 ALCdevice_Unlock(Device);
508 EffectSlot->NeedsUpdate = AL_TRUE;
512 return AL_NO_ERROR;
516 ALenum InitEffectSlot(ALeffectslot *slot)
518 ALeffectStateFactory *factory;
519 ALuint i, c;
521 slot->EffectType = AL_EFFECT_NULL;
523 factory = getFactoryByType(AL_EFFECT_NULL);
524 if(!(slot->EffectState=V0(factory,create)()))
525 return AL_OUT_OF_MEMORY;
527 slot->Gain = 1.0;
528 slot->AuxSendAuto = AL_TRUE;
529 slot->NeedsUpdate = AL_FALSE;
530 for(c = 0;c < 1;c++)
532 for(i = 0;i < BUFFERSIZE;i++)
533 slot->WetBuffer[c][i] = 0.0f;
534 slot->ClickRemoval[c] = 0.0f;
535 slot->PendingClicks[c] = 0.0f;
537 slot->ref = 0;
539 return AL_NO_ERROR;
542 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
544 ALsizei pos;
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));
554 al_free(temp);