Pass the device to InitializeEffect and return the error enum from it
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blobb3385a409b4935b14b9e69b6a3f4447477a775fc
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 ALenum err;
185 err = InitializeEffect(Device, EffectSlot, effect);
186 if(err != AL_NO_ERROR)
187 alSetError(Context, err);
188 else
189 Context->UpdateSources = AL_TRUE;
191 else
192 alSetError(Context, AL_INVALID_VALUE);
193 } break;
195 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
196 if(iValue == AL_TRUE || iValue == AL_FALSE)
198 EffectSlot->AuxSendAuto = iValue;
199 Context->UpdateSources = AL_TRUE;
201 else
202 alSetError(Context, AL_INVALID_VALUE);
203 break;
205 default:
206 alSetError(Context, AL_INVALID_ENUM);
207 break;
210 else
211 alSetError(Context, AL_INVALID_NAME);
213 ALCcontext_DecRef(Context);
216 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues)
218 ALCcontext *Context;
220 switch(param)
222 case AL_EFFECTSLOT_EFFECT:
223 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
224 alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
225 return;
228 Context = GetContextRef();
229 if(!Context) return;
231 if(LookupEffectSlot(Context, effectslot) != NULL)
233 switch(param)
235 default:
236 alSetError(Context, AL_INVALID_ENUM);
237 break;
240 else
241 alSetError(Context, AL_INVALID_NAME);
243 ALCcontext_DecRef(Context);
246 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
248 ALCcontext *Context;
249 ALeffectslot *EffectSlot;
251 Context = GetContextRef();
252 if(!Context) return;
254 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
256 switch(param)
258 case AL_EFFECTSLOT_GAIN:
259 if(flValue >= 0.0f && flValue <= 1.0f)
261 EffectSlot->Gain = flValue;
262 EffectSlot->NeedsUpdate = AL_TRUE;
264 else
265 alSetError(Context, AL_INVALID_VALUE);
266 break;
268 default:
269 alSetError(Context, AL_INVALID_ENUM);
270 break;
273 else
274 alSetError(Context, AL_INVALID_NAME);
276 ALCcontext_DecRef(Context);
279 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues)
281 ALCcontext *Context;
283 switch(param)
285 case AL_EFFECTSLOT_GAIN:
286 alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
287 return;
290 Context = GetContextRef();
291 if(!Context) return;
293 if(LookupEffectSlot(Context, effectslot) != NULL)
295 switch(param)
297 default:
298 alSetError(Context, AL_INVALID_ENUM);
299 break;
302 else
303 alSetError(Context, AL_INVALID_NAME);
305 ALCcontext_DecRef(Context);
308 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
310 ALCcontext *Context;
311 ALeffectslot *EffectSlot;
313 Context = GetContextRef();
314 if(!Context) return;
316 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
318 switch(param)
320 case AL_EFFECTSLOT_EFFECT:
321 *piValue = EffectSlot->effect.effect;
322 break;
324 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
325 *piValue = EffectSlot->AuxSendAuto;
326 break;
328 default:
329 alSetError(Context, AL_INVALID_ENUM);
330 break;
333 else
334 alSetError(Context, AL_INVALID_NAME);
336 ALCcontext_DecRef(Context);
339 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
341 ALCcontext *Context;
343 switch(param)
345 case AL_EFFECTSLOT_EFFECT:
346 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
347 alGetAuxiliaryEffectSloti(effectslot, param, piValues);
348 return;
351 Context = GetContextRef();
352 if(!Context) return;
354 if(LookupEffectSlot(Context, effectslot) != NULL)
356 switch(param)
358 default:
359 alSetError(Context, AL_INVALID_ENUM);
360 break;
363 else
364 alSetError(Context, AL_INVALID_NAME);
366 ALCcontext_DecRef(Context);
369 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
371 ALCcontext *Context;
372 ALeffectslot *EffectSlot;
374 Context = GetContextRef();
375 if(!Context) return;
377 if((EffectSlot=LookupEffectSlot(Context, effectslot)) != NULL)
379 switch(param)
381 case AL_EFFECTSLOT_GAIN:
382 *pflValue = EffectSlot->Gain;
383 break;
385 default:
386 alSetError(Context, AL_INVALID_ENUM);
387 break;
390 else
391 alSetError(Context, AL_INVALID_NAME);
393 ALCcontext_DecRef(Context);
396 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
398 ALCcontext *Context;
400 switch(param)
402 case AL_EFFECTSLOT_GAIN:
403 alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
404 return;
407 Context = GetContextRef();
408 if(!Context) return;
410 if(LookupEffectSlot(Context, effectslot) != NULL)
412 switch(param)
414 default:
415 alSetError(Context, AL_INVALID_ENUM);
416 break;
419 else
420 alSetError(Context, AL_INVALID_NAME);
422 ALCcontext_DecRef(Context);
426 static ALvoid NoneDestroy(ALeffectState *State)
427 { free(State); }
428 static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
430 return AL_TRUE;
431 (void)State;
432 (void)Device;
434 static ALvoid NoneUpdate(ALeffectState *State, ALCdevice *Device, const ALeffectslot *Slot)
436 (void)State;
437 (void)Device;
438 (void)Slot;
440 static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
442 (void)State;
443 (void)SamplesToDo;
444 (void)SamplesIn;
445 (void)SamplesOut;
447 ALeffectState *NoneCreate(void)
449 ALeffectState *state;
451 state = calloc(1, sizeof(*state));
452 if(!state)
453 return NULL;
455 state->Destroy = NoneDestroy;
456 state->DeviceUpdate = NoneDeviceUpdate;
457 state->Update = NoneUpdate;
458 state->Process = NoneProcess;
460 return state;
464 static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot)
466 ALeffectslot **slotlist, **slotlistend;
468 LockContext(Context);
469 slotlist = Context->ActiveEffectSlots;
470 slotlistend = slotlist + Context->ActiveEffectSlotCount;
471 while(slotlist != slotlistend)
473 if(*slotlist == slot)
475 *slotlist = *(--slotlistend);
476 Context->ActiveEffectSlotCount--;
477 break;
479 slotlist++;
481 UnlockContext(Context);
484 static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count)
486 ALsizei newcount;
487 void *temp;
489 if(count <= Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount)
490 return AL_NO_ERROR;
492 newcount = Context->MaxActiveEffectSlots ?
493 (Context->MaxActiveEffectSlots<<1) : 1;
494 if(newcount <= Context->MaxActiveEffectSlots ||
495 !(temp=realloc(Context->ActiveEffectSlots, newcount *
496 sizeof(*Context->ActiveEffectSlots))))
497 return AL_OUT_OF_MEMORY;
499 Context->ActiveEffectSlots = temp;
500 Context->MaxActiveEffectSlots = newcount;
501 return AL_NO_ERROR;
504 ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
506 ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
507 ALeffectState *State = NULL;
508 ALenum err = AL_NO_ERROR;
510 LockDevice(Device);
511 if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL)
513 State = NoneCreate();
514 if(!State) err = AL_OUT_OF_MEMORY;
516 else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB)
518 if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB)
520 State = ReverbCreate();
521 if(!State) err = AL_OUT_OF_MEMORY;
524 else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO)
526 State = EchoCreate();
527 if(!State) err = AL_OUT_OF_MEMORY;
529 else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR)
531 State = ModulatorCreate();
532 if(!State) err = AL_OUT_OF_MEMORY;
534 else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
536 if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
538 State = DedicatedCreate();
539 if(!State) err = AL_OUT_OF_MEMORY;
543 if(err != AL_NO_ERROR)
545 UnlockDevice(Device);
546 return err;
549 if(State)
551 int oldMode;
552 oldMode = SetMixerFPUMode();
554 if(ALeffectState_DeviceUpdate(State, Device) == AL_FALSE)
556 RestoreFPUMode(oldMode);
557 UnlockDevice(Device);
558 ALeffectState_Destroy(State);
559 return AL_OUT_OF_MEMORY;
561 State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
563 if(!effect)
564 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
565 else
566 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
567 /* FIXME: This should be done asynchronously, but since the EffectState
568 * object was changed, it needs an update before its Process method can
569 * be called. */
570 EffectSlot->NeedsUpdate = AL_FALSE;
571 ALeffectState_Update(EffectSlot->EffectState, Device, EffectSlot);
572 UnlockDevice(Device);
574 RestoreFPUMode(oldMode);
576 ALeffectState_Destroy(State);
577 State = NULL;
579 else
581 if(!effect)
582 memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
583 else
584 memcpy(&EffectSlot->effect, effect, sizeof(*effect));
585 UnlockDevice(Device);
586 EffectSlot->NeedsUpdate = AL_TRUE;
589 return AL_NO_ERROR;
593 ALenum InitEffectSlot(ALeffectslot *slot)
595 ALint i;
597 if(!(slot->EffectState=NoneCreate()))
598 return AL_OUT_OF_MEMORY;
600 slot->Gain = 1.0;
601 slot->AuxSendAuto = AL_TRUE;
602 slot->NeedsUpdate = AL_FALSE;
603 for(i = 0;i < BUFFERSIZE;i++)
604 slot->WetBuffer[i] = 0.0f;
605 for(i = 0;i < 1;i++)
607 slot->ClickRemoval[i] = 0.0f;
608 slot->PendingClicks[i] = 0.0f;
610 slot->ref = 0;
612 return AL_NO_ERROR;
615 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
617 ALsizei pos;
618 for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
620 ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
621 Context->EffectSlotMap.array[pos].value = NULL;
623 // Release effectslot structure
624 ALeffectState_Destroy(temp->EffectState);
626 FreeThunkEntry(temp->effectslot);
627 memset(temp, 0, sizeof(ALeffectslot));
628 free(temp);