Use inline assembly for fast float-to-int conversions
[openal-soft/android.git] / OpenAL32 / alAuxEffectSlot.c
blob42dd20cb223d777f8d1e964f1b04224126b14d4e
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 ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
36 static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count);
37 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *val);
40 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
42 ALCcontext *Context;
43 ALCdevice *Device;
45 Context = GetContextRef();
46 if(!Context) return;
48 Device = Context->Device;
49 if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
50 alSetError(Context, AL_INVALID_VALUE);
51 else
53 ALenum err;
54 ALsizei i, j;
56 err = ResizeEffectSlotArray(Context, n);
57 if(err != AL_NO_ERROR)
59 alSetError(Context, err);
60 n = 0;
63 for(i = 0;i < n;i++)
65 ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
66 if(!slot || !(slot->EffectState=NoneCreate()))
68 free(slot);
69 // We must have run out or memory
70 alSetError(Context, AL_OUT_OF_MEMORY);
71 alDeleteAuxiliaryEffectSlots(i, effectslots);
72 break;
75 slot->Gain = 1.0;
76 slot->AuxSendAuto = AL_TRUE;
77 slot->NeedsUpdate = AL_FALSE;
78 for(j = 0;j < BUFFERSIZE;j++)
79 slot->WetBuffer[j] = 0.0f;
80 for(j = 0;j < 1;j++)
82 slot->ClickRemoval[j] = 0.0f;
83 slot->PendingClicks[j] = 0.0f;
85 slot->ref = 0;
87 LockContext(Context);
88 err = ResizeEffectSlotArray(Context, 1);
89 if(err == AL_NO_ERROR)
90 Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot;
91 UnlockContext(Context);
92 if(err == AL_NO_ERROR)
93 err = NewThunkEntry(&slot->effectslot);
94 if(err == AL_NO_ERROR)
95 err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->effectslot, slot);
96 if(err != AL_NO_ERROR)
98 RemoveEffectSlotArray(Context, slot);
99 FreeThunkEntry(slot->effectslot);
100 ALeffectState_Destroy(slot->EffectState);
101 free(slot);
103 alSetError(Context, err);
104 alDeleteAuxiliaryEffectSlots(i, effectslots);
105 break;
108 effectslots[i] = slot->effectslot;
112 ALCcontext_DecRef(Context);
115 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
117 ALCcontext *Context;
118 ALeffectslot *EffectSlot;
119 ALsizei i;
121 Context = GetContextRef();
122 if(!Context) return;
124 if(n < 0)
125 alSetError(Context, AL_INVALID_VALUE);
126 else
128 // Check that all effectslots are valid
129 for(i = 0;i < n;i++)
131 if((EffectSlot=LookupEffectSlot(Context, effectslots[i])) == NULL)
133 alSetError(Context, AL_INVALID_NAME);
134 n = 0;
135 break;
137 else if(EffectSlot->ref != 0)
139 alSetError(Context, AL_INVALID_OPERATION);
140 n = 0;
141 break;
145 // All effectslots are valid
146 for(i = 0;i < n;i++)
148 // Recheck that the effectslot is valid, because there could be duplicated names
149 if((EffectSlot=RemoveEffectSlot(Context, effectslots[i])) == NULL)
150 continue;
151 FreeThunkEntry(EffectSlot->effectslot);
153 RemoveEffectSlotArray(Context, EffectSlot);
154 ALeffectState_Destroy(EffectSlot->EffectState);
156 memset(EffectSlot, 0, sizeof(ALeffectslot));
157 free(EffectSlot);
161 ALCcontext_DecRef(Context);
164 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
166 ALCcontext *Context;
167 ALboolean result;
169 Context = GetContextRef();
170 if(!Context) return AL_FALSE;
172 result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE);
174 ALCcontext_DecRef(Context);
176 return result;
179 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
181 ALCdevice *Device;
182 ALCcontext *Context;
183 ALeffectslot *EffectSlot;
185 Context = GetContextRef();
186 if(!Context) return;
188 Device = Context->Device;
189 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
191 switch(param)
193 case AL_EFFECTSLOT_EFFECT: {
194 ALeffect *effect = NULL;
196 if(iValue == 0 ||
197 (effect=LookupEffect(Device, iValue)) != NULL)
199 InitializeEffect(Context, EffectSlot, effect);
200 Context->UpdateSources = AL_TRUE;
202 else
203 alSetError(Context, AL_INVALID_VALUE);
204 } break;
206 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
207 if(iValue == AL_TRUE || iValue == AL_FALSE)
209 EffectSlot->AuxSendAuto = iValue;
210 Context->UpdateSources = AL_TRUE;
212 else
213 alSetError(Context, AL_INVALID_VALUE);
214 break;
216 default:
217 alSetError(Context, AL_INVALID_ENUM);
218 break;
221 else
222 alSetError(Context, AL_INVALID_NAME);
224 ALCcontext_DecRef(Context);
227 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues)
229 ALCcontext *Context;
231 switch(param)
233 case AL_EFFECTSLOT_EFFECT:
234 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
235 alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
236 return;
239 Context = GetContextRef();
240 if(!Context) return;
242 if(LookupEffectSlot(Context, effectslot) != NULL)
244 switch(param)
246 default:
247 alSetError(Context, AL_INVALID_ENUM);
248 break;
251 else
252 alSetError(Context, AL_INVALID_NAME);
254 ALCcontext_DecRef(Context);
257 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
259 ALCcontext *Context;
260 ALeffectslot *EffectSlot;
262 Context = GetContextRef();
263 if(!Context) return;
265 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
267 switch(param)
269 case AL_EFFECTSLOT_GAIN:
270 if(flValue >= 0.0f && flValue <= 1.0f)
272 EffectSlot->Gain = flValue;
273 EffectSlot->NeedsUpdate = AL_TRUE;
275 else
276 alSetError(Context, AL_INVALID_VALUE);
277 break;
279 default:
280 alSetError(Context, AL_INVALID_ENUM);
281 break;
284 else
285 alSetError(Context, AL_INVALID_NAME);
287 ALCcontext_DecRef(Context);
290 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues)
292 ALCcontext *Context;
294 switch(param)
296 case AL_EFFECTSLOT_GAIN:
297 alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
298 return;
301 Context = GetContextRef();
302 if(!Context) return;
304 if(LookupEffectSlot(Context, effectslot) != NULL)
306 switch(param)
308 default:
309 alSetError(Context, AL_INVALID_ENUM);
310 break;
313 else
314 alSetError(Context, AL_INVALID_NAME);
316 ALCcontext_DecRef(Context);
319 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
321 ALCcontext *Context;
322 ALeffectslot *EffectSlot;
324 Context = GetContextRef();
325 if(!Context) return;
327 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
329 switch(param)
331 case AL_EFFECTSLOT_EFFECT:
332 *piValue = EffectSlot->effect.effect;
333 break;
335 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
336 *piValue = EffectSlot->AuxSendAuto;
337 break;
339 default:
340 alSetError(Context, AL_INVALID_ENUM);
341 break;
344 else
345 alSetError(Context, AL_INVALID_NAME);
347 ALCcontext_DecRef(Context);
350 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
352 ALCcontext *Context;
354 switch(param)
356 case AL_EFFECTSLOT_EFFECT:
357 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
358 alGetAuxiliaryEffectSloti(effectslot, param, piValues);
359 return;
362 Context = GetContextRef();
363 if(!Context) return;
365 if(LookupEffectSlot(Context, effectslot) != NULL)
367 switch(param)
369 default:
370 alSetError(Context, AL_INVALID_ENUM);
371 break;
374 else
375 alSetError(Context, AL_INVALID_NAME);
377 ALCcontext_DecRef(Context);
380 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
382 ALCcontext *Context;
383 ALeffectslot *EffectSlot;
385 Context = GetContextRef();
386 if(!Context) return;
388 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
390 switch(param)
392 case AL_EFFECTSLOT_GAIN:
393 *pflValue = EffectSlot->Gain;
394 break;
396 default:
397 alSetError(Context, AL_INVALID_ENUM);
398 break;
401 else
402 alSetError(Context, AL_INVALID_NAME);
404 ALCcontext_DecRef(Context);
407 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
409 ALCcontext *Context;
411 switch(param)
413 case AL_EFFECTSLOT_GAIN:
414 alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
415 return;
418 Context = GetContextRef();
419 if(!Context) return;
421 if(LookupEffectSlot(Context, effectslot) != NULL)
423 switch(param)
425 default:
426 alSetError(Context, AL_INVALID_ENUM);
427 break;
430 else
431 alSetError(Context, AL_INVALID_NAME);
433 ALCcontext_DecRef(Context);
437 static ALvoid NoneDestroy(ALeffectState *State)
438 { free(State); }
439 static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
441 return AL_TRUE;
442 (void)State;
443 (void)Device;
445 static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffectslot *Slot)
447 (void)State;
448 (void)Context;
449 (void)Slot;
451 static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
453 (void)State;
454 (void)SamplesToDo;
455 (void)SamplesIn;
456 (void)SamplesOut;
458 ALeffectState *NoneCreate(void)
460 ALeffectState *state;
462 state = calloc(1, sizeof(*state));
463 if(!state)
464 return NULL;
466 state->Destroy = NoneDestroy;
467 state->DeviceUpdate = NoneDeviceUpdate;
468 state->Update = NoneUpdate;
469 state->Process = NoneProcess;
471 return state;
475 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
477 ALeffectslot **slotlist, **slotlistend;
479 LockContext(Context);
480 slotlist = Context->ActiveEffectSlots;
481 slotlistend = slotlist + Context->ActiveEffectSlotCount;
482 while(slotlist != slotlistend)
484 if(*slotlist == slot)
486 *slotlist = *(--slotlistend);
487 Context->ActiveEffectSlotCount--;
488 break;
490 slotlist++;
492 UnlockContext(Context);
495 static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count)
497 ALsizei newcount;
498 void *temp;
500 if(count <= Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
501 return AL_NO_ERROR;
503 newcount = Context->MaxActiveEffectSlots ?
504 (Context->MaxActiveEffectSlots<<1) : 1;
505 if(newcount <= Context->MaxActiveEffectSlots ||
506 !(temp=realloc(Context->ActiveEffectSlots, newcount *
507 sizeof(*Context->ActiveEffectSlots))))
508 return AL_OUT_OF_MEMORY;
510 Context->ActiveEffectSlots = temp;
511 Context->MaxActiveEffectSlots = newcount;
512 return AL_NO_ERROR;
515 static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
517 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
518 ALeffectState *State = NULL;
519 ALenum err = AL_NO_ERROR;
521 LockContext(Context);
522 if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
524 State = NoneCreate();
525 if(!State) err = AL_OUT_OF_MEMORY;
527 else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
529 if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
531 State = ReverbCreate();
532 if(!State) err = AL_OUT_OF_MEMORY;
535 else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
537 State = EchoCreate();
538 if(!State) err = AL_OUT_OF_MEMORY;
540 else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
542 State = ModulatorCreate();
543 if(!State) err = AL_OUT_OF_MEMORY;
545 else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
547 if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
549 State = DedicatedCreate();
550 if(!State) err = AL_OUT_OF_MEMORY;
554 if(err != AL_NO_ERROR)
556 UnlockContext(Context);
557 alSetError(Context, err);
558 return;
561 if(State)
563 if(ALeffectState_DeviceUpdate(State, Context->Device) == AL_FALSE)
565 UnlockContext(Context);
566 ALeffectState_Destroy(State);
567 alSetError(Context, AL_OUT_OF_MEMORY);
568 return;
570 State = ExchangePtr((void**)&EffectSlot->EffectState, State);
572 if(!effect)
573 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
574 else
575 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
576 /* FIXME: This should be done asynchronously, but since the EffectState
577 * object was changed, it needs an update before its Process method can
578 * be called. */
579 EffectSlot->NeedsUpdate = AL_FALSE;
580 ALeffectState_Update(EffectSlot->EffectState, Context, EffectSlot);
581 UnlockContext(Context);
583 ALeffectState_Destroy(State);
584 State = NULL;
586 else
588 if(!effect)
589 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
590 else
591 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
592 UnlockContext(Context);
593 EffectSlot->NeedsUpdate = AL_TRUE;
598 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
600 ALsizei pos;
601 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
603 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
604 Context->EffectSlotMap.array[pos].value = NULL;
606 // Release effectslot structure
607 ALeffectState_Destroy(temp->EffectState);
609 FreeThunkEntry(temp->effectslot);
610 memset(temp, 0, sizeof(ALeffectslot));
611 free(temp);