Remove unneeded ChannelMaps for BFormat formats
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob9780cff39a707785a4e73042f9305ba06822ceda
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"
34 #include "almalloc.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)
49 return getFactory();
50 return NULL;
54 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
56 ALCcontext *context;
57 VECTOR(ALeffectslot*) slotvec;
58 ALsizei cur;
59 ALenum err;
61 context = GetContextRef();
62 if(!context) return;
64 VECTOR_INIT(slotvec);
66 if(!(n >= 0))
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)
77 al_free(slot);
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);
89 al_free(slot);
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);
108 done:
109 VECTOR_DEINIT(slotvec);
111 ALCcontext_DecRef(context);
114 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
116 ALCcontext *context;
117 ALeffectslot *slot;
118 ALsizei i;
120 context = GetContextRef();
121 if(!context) return;
123 if(!(n >= 0))
124 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
125 for(i = 0;i < n;i++)
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
134 for(i = 0;i < n;i++)
136 if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
137 continue;
138 FreeThunkEntry(slot->id);
140 RemoveEffectSlotArray(context, slot);
141 DELETE_OBJ(slot->EffectState);
143 memset(slot, 0, sizeof(*slot));
144 al_free(slot);
147 done:
148 ALCcontext_DecRef(context);
151 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
153 ALCcontext *context;
154 ALboolean ret;
156 context = GetContextRef();
157 if(!context) return AL_FALSE;
159 ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
161 ALCcontext_DecRef(context);
163 return ret;
166 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
168 ALCdevice *device;
169 ALCcontext *context;
170 ALeffectslot *slot;
171 ALeffect *effect = NULL;
172 ALenum err;
174 context = GetContextRef();
175 if(!context) return;
177 device = context->Device;
178 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
179 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
180 switch(param)
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);
191 break;
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);
199 break;
201 default:
202 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
205 done:
206 ALCcontext_DecRef(context);
209 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
211 ALCcontext *context;
213 switch(param)
215 case AL_EFFECTSLOT_EFFECT:
216 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
217 alAuxiliaryEffectSloti(effectslot, param, values[0]);
218 return;
221 context = GetContextRef();
222 if(!context) return;
224 if(LookupEffectSlot(context, effectslot) == NULL)
225 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
226 switch(param)
228 default:
229 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
232 done:
233 ALCcontext_DecRef(context);
236 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
238 ALCcontext *context;
239 ALeffectslot *slot;
241 context = GetContextRef();
242 if(!context) return;
244 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
245 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
246 switch(param)
248 case AL_EFFECTSLOT_GAIN:
249 if(!(value >= 0.0f && value <= 1.0f))
250 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
252 slot->Gain = value;
253 ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
254 break;
256 default:
257 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
260 done:
261 ALCcontext_DecRef(context);
264 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
266 ALCcontext *context;
268 switch(param)
270 case AL_EFFECTSLOT_GAIN:
271 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
272 return;
275 context = GetContextRef();
276 if(!context) return;
278 if(LookupEffectSlot(context, effectslot) == NULL)
279 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
280 switch(param)
282 default:
283 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
286 done:
287 ALCcontext_DecRef(context);
290 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
292 ALCcontext *context;
293 ALeffectslot *slot;
295 context = GetContextRef();
296 if(!context) return;
298 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
299 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
300 switch(param)
302 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
303 *value = slot->AuxSendAuto;
304 break;
306 default:
307 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
310 done:
311 ALCcontext_DecRef(context);
314 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
316 ALCcontext *context;
318 switch(param)
320 case AL_EFFECTSLOT_EFFECT:
321 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
322 alGetAuxiliaryEffectSloti(effectslot, param, values);
323 return;
326 context = GetContextRef();
327 if(!context) return;
329 if(LookupEffectSlot(context, effectslot) == NULL)
330 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
331 switch(param)
333 default:
334 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
337 done:
338 ALCcontext_DecRef(context);
341 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
343 ALCcontext *context;
344 ALeffectslot *slot;
346 context = GetContextRef();
347 if(!context) return;
349 if((slot=LookupEffectSlot(context, effectslot)) == NULL)
350 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
351 switch(param)
353 case AL_EFFECTSLOT_GAIN:
354 *value = slot->Gain;
355 break;
357 default:
358 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
361 done:
362 ALCcontext_DecRef(context);
365 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
367 ALCcontext *context;
369 switch(param)
371 case AL_EFFECTSLOT_GAIN:
372 alGetAuxiliaryEffectSlotf(effectslot, param, values);
373 return;
376 context = GetContextRef();
377 if(!context) return;
379 if(LookupEffectSlot(context, effectslot) == NULL)
380 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
381 switch(param)
383 default:
384 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
387 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);
401 return err;
404 static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
406 ALeffectslot **iter;
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);
416 #undef MATCH_SLOT
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;
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 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);
475 DELETE_OBJ(State);
476 return AL_OUT_OF_MEMORY;
479 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
480 if(!effect)
482 memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
483 EffectSlot->EffectType = AL_EFFECT_NULL;
485 else
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
493 * be called. */
494 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
495 V(EffectSlot->EffectState,update)(Device, EffectSlot);
496 ALCdevice_Unlock(Device);
498 RestoreFPUMode(&oldMode);
500 DELETE_OBJ(State);
501 State = NULL;
503 else
505 if(effect)
507 ALCdevice_Lock(Device);
508 memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
509 ALCdevice_Unlock(Device);
510 ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
514 return AL_NO_ERROR;
518 ALenum InitEffectSlot(ALeffectslot *slot)
520 ALeffectStateFactory *factory;
521 ALuint i, c;
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;
529 slot->Gain = 1.0;
530 slot->AuxSendAuto = AL_TRUE;
531 ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
532 for(c = 0;c < 1;c++)
534 for(i = 0;i < BUFFERSIZE;i++)
535 slot->WetBuffer[c][i] = 0.0f;
537 InitRef(&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);