Avoid duplicating some initialization code
[openal-soft/android.git] / OpenAL32 / alAuxEffectSlot.c
blobfdabaeb2529ed550e196637ff48cf47f0f6b8290
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 ResizeEffectSlotArray(ALCcontext *Context, ALsizei count);
36 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *val);
39 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
41 ALCcontext *Context;
42 ALCdevice *Device;
44 Context = GetContextRef();
45 if(!Context) return;
47 Device = Context->Device;
48 if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
49 alSetError(Context, AL_INVALID_VALUE);
50 else
52 ALenum err;
53 ALsizei i;
55 err = ResizeEffectSlotArray(Context, n);
56 if(err != AL_NO_ERROR)
58 alSetError(Context, err);
59 n = 0;
62 for(i = 0;i < n;i++)
64 ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
65 if(!slot || InitEffectSlot(slot) != AL_NO_ERROR)
67 free(slot);
68 // We must have run out or memory
69 alSetError(Context, AL_OUT_OF_MEMORY);
70 alDeleteAuxiliaryEffectSlots(i, effectslots);
71 break;
74 LockContext(Context);
75 err = ResizeEffectSlotArray(Context, 1);
76 if(err == AL_NO_ERROR)
77 Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot;
78 UnlockContext(Context);
79 if(err == AL_NO_ERROR)
80 err = NewThunkEntry(&slot->effectslot);
81 if(err == AL_NO_ERROR)
82 err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->effectslot, slot);
83 if(err != AL_NO_ERROR)
85 RemoveEffectSlotArray(Context, slot);
86 FreeThunkEntry(slot->effectslot);
87 ALeffectState_Destroy(slot->EffectState);
88 free(slot);
90 alSetError(Context, err);
91 alDeleteAuxiliaryEffectSlots(i, effectslots);
92 break;
95 effectslots[i] = slot->effectslot;
99 ALCcontext_DecRef(Context);
102 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
104 ALCcontext *Context;
105 ALeffectslot *EffectSlot;
106 ALsizei i;
108 Context = GetContextRef();
109 if(!Context) return;
111 if(n < 0)
112 alSetError(Context, AL_INVALID_VALUE);
113 else
115 // Check that all effectslots are valid
116 for(i = 0;i < n;i++)
118 if((EffectSlot=LookupEffectSlot(Context, effectslots[i])) == NULL)
120 alSetError(Context, AL_INVALID_NAME);
121 n = 0;
122 break;
124 else if(EffectSlot->ref != 0)
126 alSetError(Context, AL_INVALID_OPERATION);
127 n = 0;
128 break;
132 // All effectslots are valid
133 for(i = 0;i < n;i++)
135 // Recheck that the effectslot is valid, because there could be duplicated names
136 if((EffectSlot=RemoveEffectSlot(Context, effectslots[i])) == NULL)
137 continue;
138 FreeThunkEntry(EffectSlot->effectslot);
140 RemoveEffectSlotArray(Context, EffectSlot);
141 ALeffectState_Destroy(EffectSlot->EffectState);
143 memset(EffectSlot, 0, sizeof(ALeffectslot));
144 free(EffectSlot);
148 ALCcontext_DecRef(Context);
151 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
153 ALCcontext *Context;
154 ALboolean result;
156 Context = GetContextRef();
157 if(!Context) return AL_FALSE;
159 result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE);
161 ALCcontext_DecRef(Context);
163 return result;
166 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
168 ALCdevice *Device;
169 ALCcontext *Context;
170 ALeffectslot *EffectSlot;
172 Context = GetContextRef();
173 if(!Context) return;
175 Device = Context->Device;
176 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
178 switch(param)
180 case AL_EFFECTSLOT_EFFECT: {
181 ALeffect *effect = NULL;
183 if(iValue == 0 ||
184 (effect=LookupEffect(Device, iValue)) != NULL)
186 InitializeEffect(Context, EffectSlot, effect);
187 Context->UpdateSources = AL_TRUE;
189 else
190 alSetError(Context, AL_INVALID_VALUE);
191 } break;
193 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
194 if(iValue == AL_TRUE || iValue == AL_FALSE)
196 EffectSlot->AuxSendAuto = iValue;
197 Context->UpdateSources = AL_TRUE;
199 else
200 alSetError(Context, AL_INVALID_VALUE);
201 break;
203 default:
204 alSetError(Context, AL_INVALID_ENUM);
205 break;
208 else
209 alSetError(Context, AL_INVALID_NAME);
211 ALCcontext_DecRef(Context);
214 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues)
216 ALCcontext *Context;
218 switch(param)
220 case AL_EFFECTSLOT_EFFECT:
221 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
222 alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
223 return;
226 Context = GetContextRef();
227 if(!Context) return;
229 if(LookupEffectSlot(Context, effectslot) != NULL)
231 switch(param)
233 default:
234 alSetError(Context, AL_INVALID_ENUM);
235 break;
238 else
239 alSetError(Context, AL_INVALID_NAME);
241 ALCcontext_DecRef(Context);
244 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
246 ALCcontext *Context;
247 ALeffectslot *EffectSlot;
249 Context = GetContextRef();
250 if(!Context) return;
252 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
254 switch(param)
256 case AL_EFFECTSLOT_GAIN:
257 if(flValue >= 0.0f && flValue <= 1.0f)
259 EffectSlot->Gain = flValue;
260 EffectSlot->NeedsUpdate = AL_TRUE;
262 else
263 alSetError(Context, AL_INVALID_VALUE);
264 break;
266 default:
267 alSetError(Context, AL_INVALID_ENUM);
268 break;
271 else
272 alSetError(Context, AL_INVALID_NAME);
274 ALCcontext_DecRef(Context);
277 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues)
279 ALCcontext *Context;
281 switch(param)
283 case AL_EFFECTSLOT_GAIN:
284 alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
285 return;
288 Context = GetContextRef();
289 if(!Context) return;
291 if(LookupEffectSlot(Context, effectslot) != NULL)
293 switch(param)
295 default:
296 alSetError(Context, AL_INVALID_ENUM);
297 break;
300 else
301 alSetError(Context, AL_INVALID_NAME);
303 ALCcontext_DecRef(Context);
306 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
308 ALCcontext *Context;
309 ALeffectslot *EffectSlot;
311 Context = GetContextRef();
312 if(!Context) return;
314 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
316 switch(param)
318 case AL_EFFECTSLOT_EFFECT:
319 *piValue = EffectSlot->effect.effect;
320 break;
322 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
323 *piValue = EffectSlot->AuxSendAuto;
324 break;
326 default:
327 alSetError(Context, AL_INVALID_ENUM);
328 break;
331 else
332 alSetError(Context, AL_INVALID_NAME);
334 ALCcontext_DecRef(Context);
337 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
339 ALCcontext *Context;
341 switch(param)
343 case AL_EFFECTSLOT_EFFECT:
344 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
345 alGetAuxiliaryEffectSloti(effectslot, param, piValues);
346 return;
349 Context = GetContextRef();
350 if(!Context) return;
352 if(LookupEffectSlot(Context, effectslot) != NULL)
354 switch(param)
356 default:
357 alSetError(Context, AL_INVALID_ENUM);
358 break;
361 else
362 alSetError(Context, AL_INVALID_NAME);
364 ALCcontext_DecRef(Context);
367 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
369 ALCcontext *Context;
370 ALeffectslot *EffectSlot;
372 Context = GetContextRef();
373 if(!Context) return;
375 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
377 switch(param)
379 case AL_EFFECTSLOT_GAIN:
380 *pflValue = EffectSlot->Gain;
381 break;
383 default:
384 alSetError(Context, AL_INVALID_ENUM);
385 break;
388 else
389 alSetError(Context, AL_INVALID_NAME);
391 ALCcontext_DecRef(Context);
394 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
396 ALCcontext *Context;
398 switch(param)
400 case AL_EFFECTSLOT_GAIN:
401 alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
402 return;
405 Context = GetContextRef();
406 if(!Context) return;
408 if(LookupEffectSlot(Context, effectslot) != NULL)
410 switch(param)
412 default:
413 alSetError(Context, AL_INVALID_ENUM);
414 break;
417 else
418 alSetError(Context, AL_INVALID_NAME);
420 ALCcontext_DecRef(Context);
424 static ALvoid NoneDestroy(ALeffectState *State)
425 { free(State); }
426 static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
428 return AL_TRUE;
429 (void)State;
430 (void)Device;
432 static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffectslot *Slot)
434 (void)State;
435 (void)Context;
436 (void)Slot;
438 static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
440 (void)State;
441 (void)SamplesToDo;
442 (void)SamplesIn;
443 (void)SamplesOut;
445 ALeffectState *NoneCreate(void)
447 ALeffectState *state;
449 state = calloc(1, sizeof(*state));
450 if(!state)
451 return NULL;
453 state->Destroy = NoneDestroy;
454 state->DeviceUpdate = NoneDeviceUpdate;
455 state->Update = NoneUpdate;
456 state->Process = NoneProcess;
458 return state;
462 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
464 ALeffectslot **slotlist, **slotlistend;
466 LockContext(Context);
467 slotlist = Context->ActiveEffectSlots;
468 slotlistend = slotlist + Context->ActiveEffectSlotCount;
469 while(slotlist != slotlistend)
471 if(*slotlist == slot)
473 *slotlist = *(--slotlistend);
474 Context->ActiveEffectSlotCount--;
475 break;
477 slotlist++;
479 UnlockContext(Context);
482 static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count)
484 ALsizei newcount;
485 void *temp;
487 if(count <= Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
488 return AL_NO_ERROR;
490 newcount = Context->MaxActiveEffectSlots ?
491 (Context->MaxActiveEffectSlots<<1) : 1;
492 if(newcount <= Context->MaxActiveEffectSlots ||
493 !(temp=realloc(Context->ActiveEffectSlots, newcount *
494 sizeof(*Context->ActiveEffectSlots))))
495 return AL_OUT_OF_MEMORY;
497 Context->ActiveEffectSlots = temp;
498 Context->MaxActiveEffectSlots = newcount;
499 return AL_NO_ERROR;
502 ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
504 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
505 ALeffectState *State = NULL;
506 ALenum err = AL_NO_ERROR;
508 LockContext(Context);
509 if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
511 State = NoneCreate();
512 if(!State) err = AL_OUT_OF_MEMORY;
514 else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
516 if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
518 State = ReverbCreate();
519 if(!State) err = AL_OUT_OF_MEMORY;
522 else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
524 State = EchoCreate();
525 if(!State) err = AL_OUT_OF_MEMORY;
527 else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
529 State = ModulatorCreate();
530 if(!State) err = AL_OUT_OF_MEMORY;
532 else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
534 if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
536 State = DedicatedCreate();
537 if(!State) err = AL_OUT_OF_MEMORY;
541 if(err != AL_NO_ERROR)
543 UnlockContext(Context);
544 alSetError(Context, err);
545 return;
548 if(State)
550 int oldMode;
551 oldMode = SetMixerFPUMode();
553 if(ALeffectState_DeviceUpdate(State, Context->Device) == AL_FALSE)
555 UnlockContext(Context);
556 ALeffectState_Destroy(State);
557 alSetError(Context, AL_OUT_OF_MEMORY);
558 return;
560 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
562 if(!effect)
563 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
564 else
565 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
566 /* FIXME: This should be done asynchronously, but since the EffectState
567 * object was changed, it needs an update before its Process method can
568 * be called. */
569 EffectSlot->NeedsUpdate = AL_FALSE;
570 ALeffectState_Update(EffectSlot->EffectState, Context, EffectSlot);
571 UnlockContext(Context);
573 RestoreFPUMode(oldMode);
575 ALeffectState_Destroy(State);
576 State = NULL;
578 else
580 if(!effect)
581 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
582 else
583 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
584 UnlockContext(Context);
585 EffectSlot->NeedsUpdate = AL_TRUE;
590 ALenum InitEffectSlot(ALeffectslot *slot)
592 ALint i;
594 if(!(slot->EffectState=NoneCreate()))
595 return AL_OUT_OF_MEMORY;
597 slot->Gain = 1.0;
598 slot->AuxSendAuto = AL_TRUE;
599 slot->NeedsUpdate = AL_FALSE;
600 for(i = 0;i < BUFFERSIZE;i++)
601 slot->WetBuffer[i] = 0.0f;
602 for(i = 0;i < 1;i++)
604 slot->ClickRemoval[i] = 0.0f;
605 slot->PendingClicks[i] = 0.0f;
607 slot->ref = 0;
609 return AL_NO_ERROR;
612 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
614 ALsizei pos;
615 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
617 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
618 Context->EffectSlotMap.array[pos].value = NULL;
620 // Release effectslot structure
621 ALeffectState_Destroy(temp->EffectState);
623 FreeThunkEntry(temp->effectslot);
624 memset(temp, 0, sizeof(ALeffectslot));
625 free(temp);