Restore the FPU mode in an error path
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob38b182df3867a369fd59eaaeb411739281b194bf
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;
43 Context = GetContextRef();
44 if(!Context) return;
46 if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
47 alSetError(Context, AL_INVALID_VALUE);
48 else
50 ALenum err;
51 ALsizei i;
53 err = ResizeEffectSlotArray(Context, n);
54 if(err != AL_NO_ERROR)
56 alSetError(Context, err);
57 n = 0;
60 for(i = 0;i < n;i++)
62 ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
63 if(!slot || InitEffectSlot(slot) != AL_NO_ERROR)
65 free(slot);
66 // We must have run out or memory
67 alSetError(Context, AL_OUT_OF_MEMORY);
68 alDeleteAuxiliaryEffectSlots(i, effectslots);
69 break;
72 LockContext(Context);
73 err = ResizeEffectSlotArray(Context, 1);
74 if(err == AL_NO_ERROR)
75 Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot;
76 UnlockContext(Context);
77 if(err == AL_NO_ERROR)
78 err = NewThunkEntry(&slot->effectslot);
79 if(err == AL_NO_ERROR)
80 err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->effectslot, slot);
81 if(err != AL_NO_ERROR)
83 RemoveEffectSlotArray(Context, slot);
84 FreeThunkEntry(slot->effectslot);
85 ALeffectState_Destroy(slot->EffectState);
86 free(slot);
88 alSetError(Context, err);
89 alDeleteAuxiliaryEffectSlots(i, effectslots);
90 break;
93 effectslots[i] = slot->effectslot;
97 ALCcontext_DecRef(Context);
100 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
102 ALCcontext *Context;
103 ALeffectslot *EffectSlot;
104 ALsizei i;
106 Context = GetContextRef();
107 if(!Context) return;
109 if(n < 0)
110 alSetError(Context, AL_INVALID_VALUE);
111 else
113 // Check that all effectslots are valid
114 for(i = 0;i < n;i++)
116 if((EffectSlot=LookupEffectSlot(Context, effectslots[i])) == NULL)
118 alSetError(Context, AL_INVALID_NAME);
119 n = 0;
120 break;
122 else if(EffectSlot->ref != 0)
124 alSetError(Context, AL_INVALID_OPERATION);
125 n = 0;
126 break;
130 // All effectslots are valid
131 for(i = 0;i < n;i++)
133 // Recheck that the effectslot is valid, because there could be duplicated names
134 if((EffectSlot=RemoveEffectSlot(Context, effectslots[i])) == NULL)
135 continue;
136 FreeThunkEntry(EffectSlot->effectslot);
138 RemoveEffectSlotArray(Context, EffectSlot);
139 ALeffectState_Destroy(EffectSlot->EffectState);
141 memset(EffectSlot, 0, sizeof(ALeffectslot));
142 free(EffectSlot);
146 ALCcontext_DecRef(Context);
149 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
151 ALCcontext *Context;
152 ALboolean result;
154 Context = GetContextRef();
155 if(!Context) return AL_FALSE;
157 result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE);
159 ALCcontext_DecRef(Context);
161 return result;
164 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
166 ALCdevice *Device;
167 ALCcontext *Context;
168 ALeffectslot *EffectSlot;
170 Context = GetContextRef();
171 if(!Context) return;
173 Device = Context->Device;
174 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
176 switch(param)
178 case AL_EFFECTSLOT_EFFECT: {
179 ALeffect *effect = NULL;
181 if(iValue == 0 ||
182 (effect=LookupEffect(Device, iValue)) != NULL)
184 InitializeEffect(Context, EffectSlot, effect);
185 Context->UpdateSources = AL_TRUE;
187 else
188 alSetError(Context, AL_INVALID_VALUE);
189 } break;
191 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
192 if(iValue == AL_TRUE || iValue == AL_FALSE)
194 EffectSlot->AuxSendAuto = iValue;
195 Context->UpdateSources = AL_TRUE;
197 else
198 alSetError(Context, AL_INVALID_VALUE);
199 break;
201 default:
202 alSetError(Context, AL_INVALID_ENUM);
203 break;
206 else
207 alSetError(Context, AL_INVALID_NAME);
209 ALCcontext_DecRef(Context);
212 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues)
214 ALCcontext *Context;
216 switch(param)
218 case AL_EFFECTSLOT_EFFECT:
219 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
220 alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
221 return;
224 Context = GetContextRef();
225 if(!Context) return;
227 if(LookupEffectSlot(Context, effectslot) != NULL)
229 switch(param)
231 default:
232 alSetError(Context, AL_INVALID_ENUM);
233 break;
236 else
237 alSetError(Context, AL_INVALID_NAME);
239 ALCcontext_DecRef(Context);
242 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
244 ALCcontext *Context;
245 ALeffectslot *EffectSlot;
247 Context = GetContextRef();
248 if(!Context) return;
250 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
252 switch(param)
254 case AL_EFFECTSLOT_GAIN:
255 if(flValue >= 0.0f && flValue <= 1.0f)
257 EffectSlot->Gain = flValue;
258 EffectSlot->NeedsUpdate = AL_TRUE;
260 else
261 alSetError(Context, AL_INVALID_VALUE);
262 break;
264 default:
265 alSetError(Context, AL_INVALID_ENUM);
266 break;
269 else
270 alSetError(Context, AL_INVALID_NAME);
272 ALCcontext_DecRef(Context);
275 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues)
277 ALCcontext *Context;
279 switch(param)
281 case AL_EFFECTSLOT_GAIN:
282 alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
283 return;
286 Context = GetContextRef();
287 if(!Context) return;
289 if(LookupEffectSlot(Context, effectslot) != NULL)
291 switch(param)
293 default:
294 alSetError(Context, AL_INVALID_ENUM);
295 break;
298 else
299 alSetError(Context, AL_INVALID_NAME);
301 ALCcontext_DecRef(Context);
304 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
306 ALCcontext *Context;
307 ALeffectslot *EffectSlot;
309 Context = GetContextRef();
310 if(!Context) return;
312 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
314 switch(param)
316 case AL_EFFECTSLOT_EFFECT:
317 *piValue = EffectSlot->effect.effect;
318 break;
320 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
321 *piValue = EffectSlot->AuxSendAuto;
322 break;
324 default:
325 alSetError(Context, AL_INVALID_ENUM);
326 break;
329 else
330 alSetError(Context, AL_INVALID_NAME);
332 ALCcontext_DecRef(Context);
335 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
337 ALCcontext *Context;
339 switch(param)
341 case AL_EFFECTSLOT_EFFECT:
342 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
343 alGetAuxiliaryEffectSloti(effectslot, param, piValues);
344 return;
347 Context = GetContextRef();
348 if(!Context) return;
350 if(LookupEffectSlot(Context, effectslot) != NULL)
352 switch(param)
354 default:
355 alSetError(Context, AL_INVALID_ENUM);
356 break;
359 else
360 alSetError(Context, AL_INVALID_NAME);
362 ALCcontext_DecRef(Context);
365 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
367 ALCcontext *Context;
368 ALeffectslot *EffectSlot;
370 Context = GetContextRef();
371 if(!Context) return;
373 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
375 switch(param)
377 case AL_EFFECTSLOT_GAIN:
378 *pflValue = EffectSlot->Gain;
379 break;
381 default:
382 alSetError(Context, AL_INVALID_ENUM);
383 break;
386 else
387 alSetError(Context, AL_INVALID_NAME);
389 ALCcontext_DecRef(Context);
392 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
394 ALCcontext *Context;
396 switch(param)
398 case AL_EFFECTSLOT_GAIN:
399 alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
400 return;
403 Context = GetContextRef();
404 if(!Context) return;
406 if(LookupEffectSlot(Context, effectslot) != NULL)
408 switch(param)
410 default:
411 alSetError(Context, AL_INVALID_ENUM);
412 break;
415 else
416 alSetError(Context, AL_INVALID_NAME);
418 ALCcontext_DecRef(Context);
422 static ALvoid NoneDestroy(ALeffectState *State)
423 { free(State); }
424 static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
426 return AL_TRUE;
427 (void)State;
428 (void)Device;
430 static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffectslot *Slot)
432 (void)State;
433 (void)Context;
434 (void)Slot;
436 static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
438 (void)State;
439 (void)SamplesToDo;
440 (void)SamplesIn;
441 (void)SamplesOut;
443 ALeffectState *NoneCreate(void)
445 ALeffectState *state;
447 state = calloc(1, sizeof(*state));
448 if(!state)
449 return NULL;
451 state->Destroy = NoneDestroy;
452 state->DeviceUpdate = NoneDeviceUpdate;
453 state->Update = NoneUpdate;
454 state->Process = NoneProcess;
456 return state;
460 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
462 ALeffectslot **slotlist, **slotlistend;
464 LockContext(Context);
465 slotlist = Context->ActiveEffectSlots;
466 slotlistend = slotlist + Context->ActiveEffectSlotCount;
467 while(slotlist != slotlistend)
469 if(*slotlist == slot)
471 *slotlist = *(--slotlistend);
472 Context->ActiveEffectSlotCount--;
473 break;
475 slotlist++;
477 UnlockContext(Context);
480 static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count)
482 ALsizei newcount;
483 void *temp;
485 if(count <= Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
486 return AL_NO_ERROR;
488 newcount = Context->MaxActiveEffectSlots ?
489 (Context->MaxActiveEffectSlots<<1) : 1;
490 if(newcount <= Context->MaxActiveEffectSlots ||
491 !(temp=realloc(Context->ActiveEffectSlots, newcount *
492 sizeof(*Context->ActiveEffectSlots))))
493 return AL_OUT_OF_MEMORY;
495 Context->ActiveEffectSlots = temp;
496 Context->MaxActiveEffectSlots = newcount;
497 return AL_NO_ERROR;
500 ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
502 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
503 ALeffectState *State = NULL;
504 ALenum err = AL_NO_ERROR;
506 LockContext(Context);
507 if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
509 State = NoneCreate();
510 if(!State) err = AL_OUT_OF_MEMORY;
512 else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
514 if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
516 State = ReverbCreate();
517 if(!State) err = AL_OUT_OF_MEMORY;
520 else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
522 State = EchoCreate();
523 if(!State) err = AL_OUT_OF_MEMORY;
525 else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
527 State = ModulatorCreate();
528 if(!State) err = AL_OUT_OF_MEMORY;
530 else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
532 if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
534 State = DedicatedCreate();
535 if(!State) err = AL_OUT_OF_MEMORY;
539 if(err != AL_NO_ERROR)
541 UnlockContext(Context);
542 alSetError(Context, err);
543 return;
546 if(State)
548 int oldMode;
549 oldMode = SetMixerFPUMode();
551 if(ALeffectState_DeviceUpdate(State, Context->Device) == AL_FALSE)
553 RestoreFPUMode(oldMode);
554 UnlockContext(Context);
555 ALeffectState_Destroy(State);
556 alSetError(Context, AL_OUT_OF_MEMORY);
557 return;
559 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
561 if(!effect)
562 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
563 else
564 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
565 /* FIXME: This should be done asynchronously, but since the EffectState
566 * object was changed, it needs an update before its Process method can
567 * be called. */
568 EffectSlot->NeedsUpdate = AL_FALSE;
569 ALeffectState_Update(EffectSlot->EffectState, Context, EffectSlot);
570 UnlockContext(Context);
572 RestoreFPUMode(oldMode);
574 ALeffectState_Destroy(State);
575 State = NULL;
577 else
579 if(!effect)
580 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
581 else
582 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
583 UnlockContext(Context);
584 EffectSlot->NeedsUpdate = AL_TRUE;
589 ALenum InitEffectSlot(ALeffectslot *slot)
591 ALint i;
593 if(!(slot->EffectState=NoneCreate()))
594 return AL_OUT_OF_MEMORY;
596 slot->Gain = 1.0;
597 slot->AuxSendAuto = AL_TRUE;
598 slot->NeedsUpdate = AL_FALSE;
599 for(i = 0;i < BUFFERSIZE;i++)
600 slot->WetBuffer[i] = 0.0f;
601 for(i = 0;i < 1;i++)
603 slot->ClickRemoval[i] = 0.0f;
604 slot->PendingClicks[i] = 0.0f;
606 slot->ref = 0;
608 return AL_NO_ERROR;
611 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
613 ALsizei pos;
614 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
616 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
617 Context->EffectSlotMap.array[pos].value = NULL;
619 // Release effectslot structure
620 ALeffectState_Destroy(temp->EffectState);
622 FreeThunkEntry(temp->effectslot);
623 memset(temp, 0, sizeof(ALeffectslot));
624 free(temp);