Preserve data and position when reallocating the reverb effect
[openal-soft.git] / OpenAL32 / alAuxEffectSlot.c
blob7f073435e7b855dd0cfa884716ae91001a1ca0d0
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"
34 static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
37 AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
39 ALCcontext *Context;
40 ALsizei i;
42 Context = alcGetCurrentContext();
43 if(!Context)
45 alSetError(AL_INVALID_OPERATION);
46 return;
48 SuspendContext(Context);
50 if (n > 0)
52 /* NOTE: We only support one slot currently */
53 if(n == 1 && Context->AuxiliaryEffectSlotCount == 0)
55 // Check that enough memory has been allocted in the 'effectslots' array for n Effect Slots
56 if (!IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
58 ALeffectslot **list = &Context->AuxiliaryEffectSlot;
59 while(*list)
60 list = &(*list)->next;
62 i = 0;
63 while(i < n)
65 *list = calloc(1, sizeof(ALeffectslot));
66 if(!(*list))
68 // We must have run out or memory
69 alDeleteAuxiliaryEffectSlots(i, effectslots);
70 alSetError(AL_OUT_OF_MEMORY);
71 break;
74 (*list)->Gain = 1.0;
75 (*list)->AuxSendAuto = AL_TRUE;
76 (*list)->refcount = 0;
78 effectslots[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->effectslot = effectslots[i];
81 Context->AuxiliaryEffectSlotCount++;
82 i++;
84 list = &(*list)->next;
88 else
89 alSetError(AL_INVALID_OPERATION);
92 ProcessContext(Context);
95 AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
97 ALCcontext *Context;
98 ALeffectslot *ALAuxiliaryEffectSlot;
99 ALsizei i;
101 Context = alcGetCurrentContext();
102 if(!Context)
104 alSetError(AL_INVALID_OPERATION);
105 return;
107 SuspendContext(Context);
109 if (n >= 0)
111 // Check that all effectslots are valid
112 for (i = 0; i < n; i++)
114 if (!alIsAuxiliaryEffectSlot(effectslots[i]))
116 alSetError(AL_INVALID_NAME);
117 break;
119 else
121 ALAuxiliaryEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslots[i]);
122 if(ALAuxiliaryEffectSlot->refcount > 0)
124 alSetError(AL_INVALID_NAME);
125 break;
130 if (i == n)
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 (alIsAuxiliaryEffectSlot(effectslots[i]))
138 ALeffectslot **list;
140 ALAuxiliaryEffectSlot = ((ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslots[i]));
142 // Remove Source from list of Sources
143 list = &Context->AuxiliaryEffectSlot;
144 while(*list && *list != ALAuxiliaryEffectSlot)
145 list = &(*list)->next;
147 if(*list)
148 *list = (*list)->next;
149 ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot);
151 free(ALAuxiliaryEffectSlot->ReverbBuffer);
153 memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot));
154 free(ALAuxiliaryEffectSlot);
156 Context->AuxiliaryEffectSlotCount--;
161 else
162 alSetError(AL_INVALID_VALUE);
164 ProcessContext(Context);
167 AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
169 ALCcontext *Context;
170 ALeffectslot **list;
172 Context = alcGetCurrentContext();
173 if(!Context)
175 alSetError(AL_INVALID_OPERATION);
176 return AL_FALSE;
178 SuspendContext(Context);
180 list = &Context->AuxiliaryEffectSlot;
181 while(*list && (*list)->effectslot != effectslot)
182 list = &(*list)->next;
184 ProcessContext(Context);
186 return (*list ? AL_TRUE : AL_FALSE);
189 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
191 ALCcontext *Context;
193 Context = alcGetCurrentContext();
194 if(!Context)
196 alSetError(AL_INVALID_OPERATION);
197 return;
199 SuspendContext(Context);
201 if (alIsAuxiliaryEffectSlot(effectslot))
203 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
205 switch(param)
207 case AL_EFFECTSLOT_EFFECT:
208 if(alIsEffect(iValue))
210 ALeffect *effect = (ALeffect*)ALTHUNK_LOOKUPENTRY(iValue);
211 InitializeEffect(Context, ALEffectSlot, effect);
213 else
214 alSetError(AL_INVALID_VALUE);
215 break;
217 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
218 if(iValue == AL_TRUE || iValue == AL_FALSE)
219 ALEffectSlot->AuxSendAuto = iValue;
220 else
221 alSetError(AL_INVALID_VALUE);
222 break;
224 default:
225 alSetError(AL_INVALID_ENUM);
226 break;
229 else
230 alSetError(AL_INVALID_NAME);
232 ProcessContext(Context);
235 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
237 ALCcontext *Context;
239 Context = alcGetCurrentContext();
240 if(!Context)
242 alSetError(AL_INVALID_OPERATION);
243 return;
245 SuspendContext(Context);
247 if (alIsAuxiliaryEffectSlot(effectslot))
249 switch(param)
251 case AL_EFFECTSLOT_EFFECT:
252 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
253 alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
254 break;
256 default:
257 alSetError(AL_INVALID_ENUM);
258 break;
261 else
262 alSetError(AL_INVALID_NAME);
264 ProcessContext(Context);
267 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
269 ALCcontext *Context;
271 Context = alcGetCurrentContext();
272 if(!Context)
274 alSetError(AL_INVALID_OPERATION);
275 return;
277 SuspendContext(Context);
279 if (alIsAuxiliaryEffectSlot(effectslot))
281 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
283 switch(param)
285 case AL_EFFECTSLOT_GAIN:
286 if(flValue >= 0.0f && flValue <= 1.0f)
287 ALEffectSlot->Gain = flValue;
288 else
289 alSetError(AL_INVALID_VALUE);
290 break;
292 default:
293 alSetError(AL_INVALID_ENUM);
294 break;
297 else
298 alSetError(AL_INVALID_NAME);
300 ProcessContext(Context);
303 AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
305 ALCcontext *Context;
307 Context = alcGetCurrentContext();
308 if(!Context)
310 alSetError(AL_INVALID_OPERATION);
311 return;
313 SuspendContext(Context);
315 if (alIsAuxiliaryEffectSlot(effectslot))
317 switch(param)
319 case AL_EFFECTSLOT_GAIN:
320 alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
321 break;
323 default:
324 alSetError(AL_INVALID_ENUM);
325 break;
328 else
329 alSetError(AL_INVALID_NAME);
331 ProcessContext(Context);
334 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
336 ALCcontext *Context;
338 Context = alcGetCurrentContext();
339 if(!Context)
341 alSetError(AL_INVALID_OPERATION);
342 return;
344 SuspendContext(Context);
346 if (alIsAuxiliaryEffectSlot(effectslot))
348 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
350 switch(param)
352 case AL_EFFECTSLOT_EFFECT:
353 *piValue = ALEffectSlot->effect.effect;
354 break;
356 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
357 *piValue = ALEffectSlot->AuxSendAuto;
358 break;
360 default:
361 alSetError(AL_INVALID_ENUM);
362 break;
365 else
366 alSetError(AL_INVALID_NAME);
368 ProcessContext(Context);
371 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
373 ALCcontext *Context;
375 Context = alcGetCurrentContext();
376 if(!Context)
378 alSetError(AL_INVALID_OPERATION);
379 return;
381 SuspendContext(Context);
383 if (alIsAuxiliaryEffectSlot(effectslot))
385 switch(param)
387 case AL_EFFECTSLOT_EFFECT:
388 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
389 alGetAuxiliaryEffectSloti(effectslot, param, piValues);
390 break;
392 default:
393 alSetError(AL_INVALID_ENUM);
394 break;
397 else
398 alSetError(AL_INVALID_NAME);
400 ProcessContext(Context);
403 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
405 ALCcontext *Context;
407 Context = alcGetCurrentContext();
408 if(!Context)
410 alSetError(AL_INVALID_OPERATION);
411 return;
413 SuspendContext(Context);
415 if (alIsAuxiliaryEffectSlot(effectslot))
417 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
419 switch(param)
421 case AL_EFFECTSLOT_GAIN:
422 *pflValue = ALEffectSlot->Gain;
423 break;
425 default:
426 alSetError(AL_INVALID_ENUM);
427 break;
430 else
431 alSetError(AL_INVALID_NAME);
433 ProcessContext(Context);
436 AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
438 ALCcontext *Context;
440 Context = alcGetCurrentContext();
441 if(!Context)
443 alSetError(AL_INVALID_OPERATION);
444 return;
446 SuspendContext(Context);
448 if (alIsAuxiliaryEffectSlot(effectslot))
450 switch(param)
452 case AL_EFFECTSLOT_GAIN:
453 alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
454 break;
456 default:
457 alSetError(AL_INVALID_ENUM);
458 break;
461 else
462 alSetError(AL_INVALID_NAME);
464 ProcessContext(Context);
468 static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect)
470 ALfloat *ptr = NULL;
472 if(!effect)
474 memset(&ALEffectSlot->effect, 0, sizeof(ALEffectSlot->effect));
475 goto done;
478 if(effect->type == AL_EFFECT_REVERB)
480 ALuint size;
481 ALfloat reverbwait;
483 reverbwait = (1.0f-effect->Reverb.Density)*(0.1f-0.075f) + 0.075f;
485 size = (ALuint)((ALfloat)Context->Frequency *
486 (effect->Reverb.ReflectionsDelay +
487 effect->Reverb.LateReverbDelay +
488 reverbwait)) + 1;
490 ptr = calloc(size, sizeof(ALfloat));
491 if(!ptr)
493 alSetError(AL_OUT_OF_MEMORY);
494 return;
496 if(ALEffectSlot->ReverbBuffer)
497 memcpy(ptr, ALEffectSlot->ReverbBuffer, min(size, ALEffectSlot->ReverbLength)*sizeof(ALfloat));
498 ALEffectSlot->ReverbLength = size;
499 ALEffectSlot->ReverbPos %= size;
500 ALEffectSlot->ReverbReflectPos = (ALuint)(ALEffectSlot->ReverbLength -
501 ((ALfloat)Context->Frequency *
502 effect->Reverb.ReflectionsDelay) +
503 ALEffectSlot->ReverbPos) %
504 ALEffectSlot->ReverbLength;
505 ALEffectSlot->ReverbLatePos = (ALuint)(ALEffectSlot->ReverbLength -
506 ((ALfloat)Context->Frequency *
507 (effect->Reverb.LateReverbDelay +
508 effect->Reverb.ReflectionsDelay)) +
509 ALEffectSlot->ReverbPos) %
510 ALEffectSlot->ReverbLength;
511 ALEffectSlot->ReverbDecayGain = pow(1.0/32768.0, 1.0/(effect->Reverb.DecayTime/reverbwait));
514 memcpy(&ALEffectSlot->effect, effect, sizeof(*effect));
515 done:
516 free(ALEffectSlot->ReverbBuffer);
517 ALEffectSlot->ReverbBuffer = ptr;
521 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
523 #ifdef _DEBUG
524 if(Context->AuxiliaryEffectSlotCount > 0)
525 AL_PRINT("alcDestroyContext(): %d AuxiliaryEffectSlot(s) NOT deleted\n", Context->AuxiliaryEffectSlotCount);
526 #endif
528 while(Context->AuxiliaryEffectSlot)
530 ALeffectslot *temp = Context->AuxiliaryEffectSlot;
531 Context->AuxiliaryEffectSlot = Context->AuxiliaryEffectSlot->next;
533 // Release effectslot structure
534 free(temp->ReverbBuffer);
535 ALTHUNK_REMOVEENTRY(temp->effectslot);
537 memset(temp, 0, sizeof(ALeffectslot));
538 free(temp);
540 Context->AuxiliaryEffectSlotCount = 0;