Merge pull request #11 from alexxvk/master
[openal-soft/openbsd.git] / OpenAL32 / alAuxEffectSlot.c
blobc131430185fea70c77564a07434449b6e80dbd1a
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, 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)
47 return getFactory();
48 return NULL;
52 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
54 ALCcontext *context;
55 VECTOR(ALeffectslot*) 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, VECTOR_ITER_BEGIN(slotvec), n);
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 ATOMIC_STORE(&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 ATOMIC_STORE(&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 ATOMIC_STORE(&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, 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);
397 return err;
400 static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
402 ALeffectslot **iter;
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);
412 #undef MATCH_SLOT
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;
450 FPUCtl oldMode;
452 factory = getFactoryByType(newtype);
453 if(!factory)
455 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
456 return AL_INVALID_ENUM;
458 State = V0(factory,create)();
459 if(!State)
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);
469 DELETE_OBJ(State);
470 return AL_OUT_OF_MEMORY;
473 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
474 if(!effect)
476 memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
477 EffectSlot->EffectType = AL_EFFECT_NULL;
479 else
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
487 * be called. */
488 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
489 V(EffectSlot->EffectState,update)(Device, EffectSlot);
490 ALCdevice_Unlock(Device);
492 RestoreFPUMode(&oldMode);
494 DELETE_OBJ(State);
495 State = NULL;
497 else
499 if(effect)
501 ALCdevice_Lock(Device);
502 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
503 ALCdevice_Unlock(Device);
504 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
508 return AL_NO_ERROR;
512 ALenum InitEffectSlot(ALeffectslot *slot)
514 ALeffectStateFactory *factory;
515 ALuint i, c;
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;
523 slot->Gain = 1.0;
524 slot->AuxSendAuto = AL_TRUE;
525 ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
526 for(c = 0;c < 1;c++)
528 for(i = 0;i < BUFFERSIZE;i++)
529 slot->WetBuffer[c][i] = 0.0f;
531 InitRef(&slot->ref, 0);
533 return AL_NO_ERROR;
536 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
538 ALsizei pos;
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));
548 al_free(temp);