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
29 #include "alAuxEffectSlot.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
)
43 Context
= GetContextRef();
46 if(n
< 0 || IsBadWritePtr((void*)effectslots
, n
* sizeof(ALuint
)))
47 alSetError(Context
, AL_INVALID_VALUE
);
53 err
= ResizeEffectSlotArray(Context
, n
);
54 if(err
!= AL_NO_ERROR
)
56 alSetError(Context
, err
);
62 ALeffectslot
*slot
= calloc(1, sizeof(ALeffectslot
));
63 if(!slot
|| InitEffectSlot(slot
) != AL_NO_ERROR
)
66 // We must have run out or memory
67 alSetError(Context
, AL_OUT_OF_MEMORY
);
68 alDeleteAuxiliaryEffectSlots(i
, effectslots
);
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
);
88 alSetError(Context
, err
);
89 alDeleteAuxiliaryEffectSlots(i
, effectslots
);
93 effectslots
[i
] = slot
->effectslot
;
97 ALCcontext_DecRef(Context
);
100 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
103 ALeffectslot
*EffectSlot
;
106 Context
= GetContextRef();
110 alSetError(Context
, AL_INVALID_VALUE
);
113 // Check that all effectslots are valid
116 if((EffectSlot
=LookupEffectSlot(Context
, effectslots
[i
])) == NULL
)
118 alSetError(Context
, AL_INVALID_NAME
);
122 else if(EffectSlot
->ref
!= 0)
124 alSetError(Context
, AL_INVALID_OPERATION
);
130 // All effectslots are valid
133 // Recheck that the effectslot is valid, because there could be duplicated names
134 if((EffectSlot
=RemoveEffectSlot(Context
, effectslots
[i
])) == NULL
)
136 FreeThunkEntry(EffectSlot
->effectslot
);
138 RemoveEffectSlotArray(Context
, EffectSlot
);
139 ALeffectState_Destroy(EffectSlot
->EffectState
);
141 memset(EffectSlot
, 0, sizeof(ALeffectslot
));
146 ALCcontext_DecRef(Context
);
149 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
154 Context
= GetContextRef();
155 if(!Context
) return AL_FALSE
;
157 result
= (LookupEffectSlot(Context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
159 ALCcontext_DecRef(Context
);
164 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint iValue
)
168 ALeffectslot
*EffectSlot
;
170 Context
= GetContextRef();
173 Device
= Context
->Device
;
174 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
178 case AL_EFFECTSLOT_EFFECT
: {
179 ALeffect
*effect
= NULL
;
182 (effect
=LookupEffect(Device
, iValue
)) != NULL
)
185 err
= InitializeEffect(Device
, EffectSlot
, effect
);
186 if(err
!= AL_NO_ERROR
)
187 alSetError(Context
, err
);
189 Context
->UpdateSources
= AL_TRUE
;
192 alSetError(Context
, AL_INVALID_VALUE
);
195 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
196 if(iValue
== AL_TRUE
|| iValue
== AL_FALSE
)
198 EffectSlot
->AuxSendAuto
= iValue
;
199 Context
->UpdateSources
= AL_TRUE
;
202 alSetError(Context
, AL_INVALID_VALUE
);
206 alSetError(Context
, AL_INVALID_ENUM
);
211 alSetError(Context
, AL_INVALID_NAME
);
213 ALCcontext_DecRef(Context
);
216 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*piValues
)
222 case AL_EFFECTSLOT_EFFECT
:
223 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
224 alAuxiliaryEffectSloti(effectslot
, param
, piValues
[0]);
228 Context
= GetContextRef();
231 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
236 alSetError(Context
, AL_INVALID_ENUM
);
241 alSetError(Context
, AL_INVALID_NAME
);
243 ALCcontext_DecRef(Context
);
246 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat flValue
)
249 ALeffectslot
*EffectSlot
;
251 Context
= GetContextRef();
254 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
258 case AL_EFFECTSLOT_GAIN
:
259 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
261 EffectSlot
->Gain
= flValue
;
262 EffectSlot
->NeedsUpdate
= AL_TRUE
;
265 alSetError(Context
, AL_INVALID_VALUE
);
269 alSetError(Context
, AL_INVALID_ENUM
);
274 alSetError(Context
, AL_INVALID_NAME
);
276 ALCcontext_DecRef(Context
);
279 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*pflValues
)
285 case AL_EFFECTSLOT_GAIN
:
286 alAuxiliaryEffectSlotf(effectslot
, param
, pflValues
[0]);
290 Context
= GetContextRef();
293 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
298 alSetError(Context
, AL_INVALID_ENUM
);
303 alSetError(Context
, AL_INVALID_NAME
);
305 ALCcontext_DecRef(Context
);
308 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*piValue
)
311 ALeffectslot
*EffectSlot
;
313 Context
= GetContextRef();
316 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
320 case AL_EFFECTSLOT_EFFECT
:
321 *piValue
= EffectSlot
->effect
.effect
;
324 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
325 *piValue
= EffectSlot
->AuxSendAuto
;
329 alSetError(Context
, AL_INVALID_ENUM
);
334 alSetError(Context
, AL_INVALID_NAME
);
336 ALCcontext_DecRef(Context
);
339 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*piValues
)
345 case AL_EFFECTSLOT_EFFECT
:
346 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
347 alGetAuxiliaryEffectSloti(effectslot
, param
, piValues
);
351 Context
= GetContextRef();
354 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
359 alSetError(Context
, AL_INVALID_ENUM
);
364 alSetError(Context
, AL_INVALID_NAME
);
366 ALCcontext_DecRef(Context
);
369 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*pflValue
)
372 ALeffectslot
*EffectSlot
;
374 Context
= GetContextRef();
377 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
381 case AL_EFFECTSLOT_GAIN
:
382 *pflValue
= EffectSlot
->Gain
;
386 alSetError(Context
, AL_INVALID_ENUM
);
391 alSetError(Context
, AL_INVALID_NAME
);
393 ALCcontext_DecRef(Context
);
396 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*pflValues
)
402 case AL_EFFECTSLOT_GAIN
:
403 alGetAuxiliaryEffectSlotf(effectslot
, param
, pflValues
);
407 Context
= GetContextRef();
410 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
415 alSetError(Context
, AL_INVALID_ENUM
);
420 alSetError(Context
, AL_INVALID_NAME
);
422 ALCcontext_DecRef(Context
);
426 static ALvoid
NoneDestroy(ALeffectState
*State
)
428 static ALboolean
NoneDeviceUpdate(ALeffectState
*State
, ALCdevice
*Device
)
434 static ALvoid
NoneUpdate(ALeffectState
*State
, ALCdevice
*Device
, const ALeffectslot
*Slot
)
440 static ALvoid
NoneProcess(ALeffectState
*State
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[MAXCHANNELS
])
447 ALeffectState
*NoneCreate(void)
449 ALeffectState
*state
;
451 state
= calloc(1, sizeof(*state
));
455 state
->Destroy
= NoneDestroy
;
456 state
->DeviceUpdate
= NoneDeviceUpdate
;
457 state
->Update
= NoneUpdate
;
458 state
->Process
= NoneProcess
;
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
--;
481 UnlockContext(Context
);
484 static ALenum
ResizeEffectSlotArray(ALCcontext
*Context
, ALsizei count
)
489 if(count
<= Context
->MaxActiveEffectSlots
-Context
->ActiveEffectSlotCount
)
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
;
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
;
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
);
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
);
564 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
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
570 EffectSlot
->NeedsUpdate
= AL_FALSE
;
571 ALeffectState_Update(EffectSlot
->EffectState
, Device
, EffectSlot
);
572 UnlockDevice(Device
);
574 RestoreFPUMode(oldMode
);
576 ALeffectState_Destroy(State
);
582 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
584 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
585 UnlockDevice(Device
);
586 EffectSlot
->NeedsUpdate
= AL_TRUE
;
593 ALenum
InitEffectSlot(ALeffectslot
*slot
)
597 if(!(slot
->EffectState
=NoneCreate()))
598 return AL_OUT_OF_MEMORY
;
601 slot
->AuxSendAuto
= AL_TRUE
;
602 slot
->NeedsUpdate
= AL_FALSE
;
603 for(i
= 0;i
< BUFFERSIZE
;i
++)
604 slot
->WetBuffer
[i
] = 0.0f
;
607 slot
->ClickRemoval
[i
] = 0.0f
;
608 slot
->PendingClicks
[i
] = 0.0f
;
615 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
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
));