Release 1.15.1
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob230fe5fcddbd95387943dce2aadc9f58194bf4f6
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 static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots);
36 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot);
39 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
41 ALCcontext *Context;
42 ALsizei cur = 0;
44 Context = GetContextRef();
45 if(!Context) return;
47 al_try
49 ALenum err;
51 CHECK_VALUE(Context, n >= 0);
52 for(cur = 0;cur < n;cur++)
54 ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
55 err = AL_OUT_OF_MEMORY;
56 if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
58 al_free(slot);
59 al_throwerr(Context, err);
60 break;
63 err = NewThunkEntry(&slot->id);
64 if(err == AL_NO_ERROR)
65 err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->id, slot);
66 if(err != AL_NO_ERROR)
68 FreeThunkEntry(slot->id);
69 ALeffectState_Destroy(slot->EffectState);
70 al_free(slot);
72 al_throwerr(Context, err);
75 effectslots[cur] = slot->id;
77 err = AddEffectSlotArray(Context, n, effectslots);
78 if(err != AL_NO_ERROR)
79 al_throwerr(Context, err);
81 al_catchany()
83 if(cur > 0)
84 alDeleteAuxiliaryEffectSlots(cur, effectslots);
86 al_endtry;
88 ALCcontext_DecRef(Context);
91 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
93 ALCcontext *Context;
94 ALeffectslot *slot;
95 ALsizei i;
97 Context = GetContextRef();
98 if(!Context) return;
100 al_try
102 CHECK_VALUE(Context, n >= 0);
103 for(i = 0;i < n;i++)
105 if((slot=LookupEffectSlot(Context, effectslots[i])) == NULL)
106 al_throwerr(Context, AL_INVALID_NAME);
107 if(slot->ref != 0)
108 al_throwerr(Context, AL_INVALID_OPERATION);
111 // All effectslots are valid
112 for(i = 0;i < n;i++)
114 if((slot=RemoveEffectSlot(Context, effectslots[i])) == NULL)
115 continue;
116 FreeThunkEntry(slot->id);
118 RemoveEffectSlotArray(Context, slot);
119 ALeffectState_Destroy(slot->EffectState);
121 memset(slot, 0, sizeof(*slot));
122 al_free(slot);
125 al_endtry;
127 ALCcontext_DecRef(Context);
130 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
132 ALCcontext *Context;
133 ALboolean result;
135 Context = GetContextRef();
136 if(!Context) return AL_FALSE;
138 result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE);
140 ALCcontext_DecRef(Context);
142 return result;
145 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
147 ALCcontext *Context;
148 ALeffectslot *Slot;
149 ALeffect *effect = NULL;
150 ALenum err;
152 Context = GetContextRef();
153 if(!Context) return;
155 al_try
157 ALCdevice *device = Context->Device;
158 if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
159 al_throwerr(Context, AL_INVALID_NAME);
160 switch(param)
162 case AL_EFFECTSLOT_EFFECT:
163 CHECK_VALUE(Context, value == 0 || (effect=LookupEffect(device, value)) != NULL);
165 err = InitializeEffect(device, Slot, effect);
166 if(err != AL_NO_ERROR)
167 al_throwerr(Context, err);
168 Context->UpdateSources = AL_TRUE;
169 break;
171 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
172 CHECK_VALUE(Context, value == AL_TRUE || value == AL_FALSE);
174 Slot->AuxSendAuto = value;
175 Context->UpdateSources = AL_TRUE;
176 break;
178 default:
179 al_throwerr(Context, AL_INVALID_ENUM);
182 al_endtry;
184 ALCcontext_DecRef(Context);
187 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
189 ALCcontext *Context;
191 switch(param)
193 case AL_EFFECTSLOT_EFFECT:
194 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
195 alAuxiliaryEffectSloti(effectslot, param, values[0]);
196 return;
199 Context = GetContextRef();
200 if(!Context) return;
202 al_try
204 if(LookupEffectSlot(Context, effectslot) == NULL)
205 al_throwerr(Context, AL_INVALID_NAME);
206 switch(param)
208 default:
209 al_throwerr(Context, AL_INVALID_ENUM);
212 al_endtry;
214 ALCcontext_DecRef(Context);
217 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
219 ALCcontext *Context;
220 ALeffectslot *Slot;
222 Context = GetContextRef();
223 if(!Context) return;
225 al_try
227 if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
228 al_throwerr(Context, AL_INVALID_NAME);
229 switch(param)
231 case AL_EFFECTSLOT_GAIN:
232 CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f);
234 Slot->Gain = value;
235 Slot->NeedsUpdate = AL_TRUE;
236 break;
238 default:
239 al_throwerr(Context, AL_INVALID_ENUM);
242 al_endtry;
244 ALCcontext_DecRef(Context);
247 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
249 ALCcontext *Context;
251 switch(param)
253 case AL_EFFECTSLOT_GAIN:
254 alAuxiliaryEffectSlotf(effectslot, param, values[0]);
255 return;
258 Context = GetContextRef();
259 if(!Context) return;
261 al_try
263 if(LookupEffectSlot(Context, effectslot) == NULL)
264 al_throwerr(Context, AL_INVALID_NAME);
265 switch(param)
267 default:
268 al_throwerr(Context, AL_INVALID_ENUM);
271 al_endtry;
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 al_try
286 if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
287 al_throwerr(Context, AL_INVALID_NAME);
288 switch(param)
290 case AL_EFFECTSLOT_EFFECT:
291 *value = Slot->effect.id;
292 break;
294 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
295 *value = Slot->AuxSendAuto;
296 break;
298 default:
299 al_throwerr(Context, AL_INVALID_ENUM);
302 al_endtry;
304 ALCcontext_DecRef(Context);
307 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
309 ALCcontext *Context;
311 switch(param)
313 case AL_EFFECTSLOT_EFFECT:
314 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
315 alGetAuxiliaryEffectSloti(effectslot, param, values);
316 return;
319 Context = GetContextRef();
320 if(!Context) return;
322 al_try
324 if(LookupEffectSlot(Context, effectslot) == NULL)
325 al_throwerr(Context, AL_INVALID_NAME);
326 switch(param)
328 default:
329 al_throwerr(Context, AL_INVALID_ENUM);
332 al_endtry;
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 al_try
347 if((Slot=LookupEffectSlot(Context, effectslot)) == NULL)
348 al_throwerr(Context, AL_INVALID_NAME);
349 switch(param)
351 case AL_EFFECTSLOT_GAIN:
352 *value = Slot->Gain;
353 break;
355 default:
356 al_throwerr(Context, AL_INVALID_ENUM);
359 al_endtry;
361 ALCcontext_DecRef(Context);
364 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
366 ALCcontext *Context;
368 switch(param)
370 case AL_EFFECTSLOT_GAIN:
371 alGetAuxiliaryEffectSlotf(effectslot, param, values);
372 return;
375 Context = GetContextRef();
376 if(!Context) return;
378 al_try
380 if(LookupEffectSlot(Context, effectslot) == NULL)
381 al_throwerr(Context, AL_INVALID_NAME);
382 switch(param)
384 default:
385 al_throwerr(Context, AL_INVALID_ENUM);
388 al_endtry;
390 ALCcontext_DecRef(Context);
394 static ALvoid NoneDestroy(ALeffectState *State)
395 { free(State); }
396 static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
398 return AL_TRUE;
399 (void)State;
400 (void)Device;
402 static ALvoid NoneUpdate(ALeffectState *State, ALCdevice *Device, const ALeffectslot *Slot)
404 (void)State;
405 (void)Device;
406 (void)Slot;
408 static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE])
410 (void)State;
411 (void)SamplesToDo;
412 (void)SamplesIn;
413 (void)SamplesOut;
415 ALeffectState *NoneCreate(void)
417 ALeffectState *state;
419 state = calloc(1, sizeof(*state));
420 if(!state)
421 return NULL;
423 state->Destroy = NoneDestroy;
424 state->DeviceUpdate = NoneDeviceUpdate;
425 state->Update = NoneUpdate;
426 state->Process = NoneProcess;
428 return state;
432 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
434 ALeffectslot **slotlist, **slotlistend;
436 LockContext(Context);
437 slotlist = Context->ActiveEffectSlots;
438 slotlistend = slotlist + Context->ActiveEffectSlotCount;
439 while(slotlist != slotlistend)
441 if(*slotlist == slot)
443 *slotlist = *(--slotlistend);
444 Context->ActiveEffectSlotCount--;
445 break;
447 slotlist++;
449 UnlockContext(Context);
452 static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots)
454 ALsizei i;
456 LockContext(Context);
457 if(count > Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
459 ALsizei newcount;
460 void *temp = NULL;
462 newcount = Context->MaxActiveEffectSlots ? (Context->MaxActiveEffectSlots<<1) : 1;
463 if(newcount > Context->MaxActiveEffectSlots)
464 temp = realloc(Context->ActiveEffectSlots,
465 newcount * sizeof(*Context->ActiveEffectSlots));
466 if(!temp)
468 UnlockContext(Context);
469 return AL_OUT_OF_MEMORY;
471 Context->ActiveEffectSlots = temp;
472 Context->MaxActiveEffectSlots = newcount;
474 for(i = 0;i < count;i++)
476 ALeffectslot *slot = LookupEffectSlot(Context, slots[i]);
477 assert(slot != NULL);
478 Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot;
480 UnlockContext(Context);
481 return AL_NO_ERROR;
484 ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
486 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
487 ALeffectState *State = NULL;
488 ALenum err = AL_NO_ERROR;
490 ALCdevice_Lock(Device);
491 if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
493 State = NoneCreate();
494 if(!State) err = AL_OUT_OF_MEMORY;
496 else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
498 if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
500 State = ReverbCreate();
501 if(!State) err = AL_OUT_OF_MEMORY;
504 else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
506 State = EchoCreate();
507 if(!State) err = AL_OUT_OF_MEMORY;
509 else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
511 State = ModulatorCreate();
512 if(!State) err = AL_OUT_OF_MEMORY;
514 else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
516 if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
518 State = DedicatedCreate();
519 if(!State) err = AL_OUT_OF_MEMORY;
523 if(err != AL_NO_ERROR)
525 ALCdevice_Unlock(Device);
526 return err;
529 if(State)
531 FPUCtl oldMode;
532 SetMixerFPUMode(&oldMode);
534 if(ALeffectState_DeviceUpdate(State, Device) == AL_FALSE)
536 RestoreFPUMode(&oldMode);
537 ALCdevice_Unlock(Device);
538 ALeffectState_Destroy(State);
539 return AL_OUT_OF_MEMORY;
541 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
543 if(!effect)
544 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
545 else
546 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
547 /* FIXME: This should be done asynchronously, but since the EffectState
548 * object was changed, it needs an update before its Process method can
549 * be called. */
550 EffectSlot->NeedsUpdate = AL_FALSE;
551 ALeffectState_Update(EffectSlot->EffectState, Device, EffectSlot);
552 ALCdevice_Unlock(Device);
554 RestoreFPUMode(&oldMode);
556 ALeffectState_Destroy(State);
557 State = NULL;
559 else
561 if(!effect)
562 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
563 else
564 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
565 ALCdevice_Unlock(Device);
566 EffectSlot->NeedsUpdate = AL_TRUE;
569 return AL_NO_ERROR;
573 ALenum InitEffectSlot(ALeffectslot *slot)
575 ALint i, c;
577 if(!(slot->EffectState=NoneCreate()))
578 return AL_OUT_OF_MEMORY;
580 slot->Gain = 1.0;
581 slot->AuxSendAuto = AL_TRUE;
582 slot->NeedsUpdate = AL_FALSE;
583 for(c = 0;c < 1;c++)
585 for(i = 0;i < BUFFERSIZE;i++)
586 slot->WetBuffer[c][i] = 0.0f;
587 slot->ClickRemoval[c] = 0.0f;
588 slot->PendingClicks[c] = 0.0f;
590 slot->ref = 0;
592 return AL_NO_ERROR;
595 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
597 ALsizei pos;
598 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
600 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
601 Context->EffectSlotMap.array[pos].value = NULL;
603 ALeffectState_Destroy(temp->EffectState);
605 FreeThunkEntry(temp->id);
606 memset(temp, 0, sizeof(ALeffectslot));
607 al_free(temp);