Apply the main reverb gain with the panning
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blobb0dba25df9fc64586d244bd1a6bc8287bdff8539
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 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);
106 done:
107 VECTOR_DEINIT(slotvec);
109 ALCcontext_DecRef(context);
112 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
114 ALCcontext *context;
115 ALeffectslot *slot;
116 ALsizei i;
118 context = GetContextRef();
119 if(!context) return;
121 if(!(n >= 0))
122 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
123 for(i = 0;i < n;i++)
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
132 for(i = 0;i < n;i++)
134 if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
135 continue;
136 FreeThunkEntry(slot->id);
138 RemoveEffectSlotArray(context, slot);
139 DELETE_OBJ(slot->EffectState);
141 memset(slot, 0, sizeof(*slot));
142 al_free(slot);
145 done:
146 ALCcontext_DecRef(context);
149 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
151 ALCcontext *context;
152 ALboolean ret;
154 context = GetContextRef();
155 if(!context) return AL_FALSE;
157 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
159 ALCcontext_DecRef(context);
161 return ret;
164 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
166 ALCdevice *device;
167 ALCcontext *context;
168 ALeffectslot *slot;
169 ALeffect *effect = NULL;
170 ALenum err;
172 context = GetContextRef();
173 if(!context) return;
175 device = context->Device;
176 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
177 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
178 switch(param)
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);
189 break;
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);
197 break;
199 default:
200 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
203 done:
204 ALCcontext_DecRef(context);
207 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
209 ALCcontext *context;
211 switch(param)
213 case AL_EFFECTSLOT_EFFECT:
214 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
215 alAuxiliaryEffectSloti(effectslot, param, values[0]);
216 return;
219 context = GetContextRef();
220 if(!context) return;
222 if(LookupEffectSlot(context, effectslot) == NULL)
223 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
224 switch(param)
226 default:
227 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
230 done:
231 ALCcontext_DecRef(context);
234 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
236 ALCcontext *context;
237 ALeffectslot *slot;
239 context = GetContextRef();
240 if(!context) return;
242 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
243 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
244 switch(param)
246 case AL_EFFECTSLOT_GAIN:
247 if(!(value >= 0.0f && value <= 1.0f))
248 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
250 slot->Gain = value;
251 ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
252 break;
254 default:
255 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
258 done:
259 ALCcontext_DecRef(context);
262 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
264 ALCcontext *context;
266 switch(param)
268 case AL_EFFECTSLOT_GAIN:
269 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
270 return;
273 context = GetContextRef();
274 if(!context) return;
276 if(LookupEffectSlot(context, effectslot) == NULL)
277 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
278 switch(param)
280 default:
281 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
284 done:
285 ALCcontext_DecRef(context);
288 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
290 ALCcontext *context;
291 ALeffectslot *slot;
293 context = GetContextRef();
294 if(!context) return;
296 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
297 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
298 switch(param)
300 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
301 *value = slot->AuxSendAuto;
302 break;
304 default:
305 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
308 done:
309 ALCcontext_DecRef(context);
312 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
314 ALCcontext *context;
316 switch(param)
318 case AL_EFFECTSLOT_EFFECT:
319 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
320 alGetAuxiliaryEffectSloti(effectslot, param, values);
321 return;
324 context = GetContextRef();
325 if(!context) return;
327 if(LookupEffectSlot(context, effectslot) == NULL)
328 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
329 switch(param)
331 default:
332 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
335 done:
336 ALCcontext_DecRef(context);
339 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
341 ALCcontext *context;
342 ALeffectslot *slot;
344 context = GetContextRef();
345 if(!context) return;
347 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
348 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
349 switch(param)
351 case AL_EFFECTSLOT_GAIN:
352 *value = slot->Gain;
353 break;
355 default:
356 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
359 done:
360 ALCcontext_DecRef(context);
363 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
365 ALCcontext *context;
367 switch(param)
369 case AL_EFFECTSLOT_GAIN:
370 alGetAuxiliaryEffectSlotf(effectslot, param, values);
371 return;
374 context = GetContextRef();
375 if(!context) return;
377 if(LookupEffectSlot(context, effectslot) == NULL)
378 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
379 switch(param)
381 default:
382 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
385 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);
399 return err;
402 static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
404 ALeffectslot **iter;
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);
414 #undef MATCH_SLOT
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;
452 FPUCtl oldMode;
454 factory = getFactoryByType(newtype);
455 if(!factory)
457 ERR("Failed to find factory for effect type 0x%04x\n", newtype);
458 return AL_INVALID_ENUM;
460 State = V0(factory,create)();
461 if(!State)
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);
471 DELETE_OBJ(State);
472 return AL_OUT_OF_MEMORY;
475 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
476 if(!effect)
478 memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
479 EffectSlot->EffectType = AL_EFFECT_NULL;
481 else
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
489 * be called. */
490 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
491 V(EffectSlot->EffectState,update)(Device, EffectSlot);
492 ALCdevice_Unlock(Device);
494 RestoreFPUMode(&oldMode);
496 DELETE_OBJ(State);
497 State = NULL;
499 else
501 if(effect)
503 ALCdevice_Lock(Device);
504 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
505 ALCdevice_Unlock(Device);
506 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
510 return AL_NO_ERROR;
514 ALenum InitEffectSlot(ALeffectslot *slot)
516 ALeffectStateFactory *factory;
517 ALuint i, c;
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;
525 slot->Gain = 1.0;
526 slot->AuxSendAuto = AL_TRUE;
527 ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
528 for(c = 0;c < 1;c++)
530 for(i = 0;i < BUFFERSIZE;i++)
531 slot->WetBuffer[c][i] = 0.0f;
533 InitRef(&slot->ref, 0);
535 return AL_NO_ERROR;
538 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
540 ALsizei pos;
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));
550 al_free(temp);