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
)
44 Context
= GetContextRef();
47 Device
= Context
->Device
;
48 if(n
< 0 || IsBadWritePtr((void*)effectslots
, n
* sizeof(ALuint
)))
49 alSetError(Context
, AL_INVALID_VALUE
);
55 err
= ResizeEffectSlotArray(Context
, n
);
56 if(err
!= AL_NO_ERROR
)
58 alSetError(Context
, err
);
64 ALeffectslot
*slot
= calloc(1, sizeof(ALeffectslot
));
65 if(!slot
|| InitEffectSlot(slot
) != AL_NO_ERROR
)
68 // We must have run out or memory
69 alSetError(Context
, AL_OUT_OF_MEMORY
);
70 alDeleteAuxiliaryEffectSlots(i
, effectslots
);
75 err
= ResizeEffectSlotArray(Context
, 1);
76 if(err
== AL_NO_ERROR
)
77 Context
->ActiveEffectSlots
[Context
->ActiveEffectSlotCount
++] = slot
;
78 UnlockContext(Context
);
79 if(err
== AL_NO_ERROR
)
80 err
= NewThunkEntry(&slot
->effectslot
);
81 if(err
== AL_NO_ERROR
)
82 err
= InsertUIntMapEntry(&Context
->EffectSlotMap
, slot
->effectslot
, slot
);
83 if(err
!= AL_NO_ERROR
)
85 RemoveEffectSlotArray(Context
, slot
);
86 FreeThunkEntry(slot
->effectslot
);
87 ALeffectState_Destroy(slot
->EffectState
);
90 alSetError(Context
, err
);
91 alDeleteAuxiliaryEffectSlots(i
, effectslots
);
95 effectslots
[i
] = slot
->effectslot
;
99 ALCcontext_DecRef(Context
);
102 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
105 ALeffectslot
*EffectSlot
;
108 Context
= GetContextRef();
112 alSetError(Context
, AL_INVALID_VALUE
);
115 // Check that all effectslots are valid
118 if((EffectSlot
=LookupEffectSlot(Context
, effectslots
[i
])) == NULL
)
120 alSetError(Context
, AL_INVALID_NAME
);
124 else if(EffectSlot
->ref
!= 0)
126 alSetError(Context
, AL_INVALID_OPERATION
);
132 // All effectslots are valid
135 // Recheck that the effectslot is valid, because there could be duplicated names
136 if((EffectSlot
=RemoveEffectSlot(Context
, effectslots
[i
])) == NULL
)
138 FreeThunkEntry(EffectSlot
->effectslot
);
140 RemoveEffectSlotArray(Context
, EffectSlot
);
141 ALeffectState_Destroy(EffectSlot
->EffectState
);
143 memset(EffectSlot
, 0, sizeof(ALeffectslot
));
148 ALCcontext_DecRef(Context
);
151 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
156 Context
= GetContextRef();
157 if(!Context
) return AL_FALSE
;
159 result
= (LookupEffectSlot(Context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
161 ALCcontext_DecRef(Context
);
166 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint iValue
)
170 ALeffectslot
*EffectSlot
;
172 Context
= GetContextRef();
175 Device
= Context
->Device
;
176 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
180 case AL_EFFECTSLOT_EFFECT
: {
181 ALeffect
*effect
= NULL
;
184 (effect
=LookupEffect(Device
, iValue
)) != NULL
)
186 InitializeEffect(Context
, EffectSlot
, effect
);
187 Context
->UpdateSources
= AL_TRUE
;
190 alSetError(Context
, AL_INVALID_VALUE
);
193 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
194 if(iValue
== AL_TRUE
|| iValue
== AL_FALSE
)
196 EffectSlot
->AuxSendAuto
= iValue
;
197 Context
->UpdateSources
= AL_TRUE
;
200 alSetError(Context
, AL_INVALID_VALUE
);
204 alSetError(Context
, AL_INVALID_ENUM
);
209 alSetError(Context
, AL_INVALID_NAME
);
211 ALCcontext_DecRef(Context
);
214 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*piValues
)
220 case AL_EFFECTSLOT_EFFECT
:
221 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
222 alAuxiliaryEffectSloti(effectslot
, param
, piValues
[0]);
226 Context
= GetContextRef();
229 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
234 alSetError(Context
, AL_INVALID_ENUM
);
239 alSetError(Context
, AL_INVALID_NAME
);
241 ALCcontext_DecRef(Context
);
244 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat flValue
)
247 ALeffectslot
*EffectSlot
;
249 Context
= GetContextRef();
252 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
256 case AL_EFFECTSLOT_GAIN
:
257 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
259 EffectSlot
->Gain
= flValue
;
260 EffectSlot
->NeedsUpdate
= AL_TRUE
;
263 alSetError(Context
, AL_INVALID_VALUE
);
267 alSetError(Context
, AL_INVALID_ENUM
);
272 alSetError(Context
, AL_INVALID_NAME
);
274 ALCcontext_DecRef(Context
);
277 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*pflValues
)
283 case AL_EFFECTSLOT_GAIN
:
284 alAuxiliaryEffectSlotf(effectslot
, param
, pflValues
[0]);
288 Context
= GetContextRef();
291 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
296 alSetError(Context
, AL_INVALID_ENUM
);
301 alSetError(Context
, AL_INVALID_NAME
);
303 ALCcontext_DecRef(Context
);
306 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*piValue
)
309 ALeffectslot
*EffectSlot
;
311 Context
= GetContextRef();
314 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
318 case AL_EFFECTSLOT_EFFECT
:
319 *piValue
= EffectSlot
->effect
.effect
;
322 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
323 *piValue
= EffectSlot
->AuxSendAuto
;
327 alSetError(Context
, AL_INVALID_ENUM
);
332 alSetError(Context
, AL_INVALID_NAME
);
334 ALCcontext_DecRef(Context
);
337 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*piValues
)
343 case AL_EFFECTSLOT_EFFECT
:
344 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
345 alGetAuxiliaryEffectSloti(effectslot
, param
, piValues
);
349 Context
= GetContextRef();
352 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
357 alSetError(Context
, AL_INVALID_ENUM
);
362 alSetError(Context
, AL_INVALID_NAME
);
364 ALCcontext_DecRef(Context
);
367 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*pflValue
)
370 ALeffectslot
*EffectSlot
;
372 Context
= GetContextRef();
375 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
379 case AL_EFFECTSLOT_GAIN
:
380 *pflValue
= EffectSlot
->Gain
;
384 alSetError(Context
, AL_INVALID_ENUM
);
389 alSetError(Context
, AL_INVALID_NAME
);
391 ALCcontext_DecRef(Context
);
394 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*pflValues
)
400 case AL_EFFECTSLOT_GAIN
:
401 alGetAuxiliaryEffectSlotf(effectslot
, param
, pflValues
);
405 Context
= GetContextRef();
408 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
413 alSetError(Context
, AL_INVALID_ENUM
);
418 alSetError(Context
, AL_INVALID_NAME
);
420 ALCcontext_DecRef(Context
);
424 static ALvoid
NoneDestroy(ALeffectState
*State
)
426 static ALboolean
NoneDeviceUpdate(ALeffectState
*State
, ALCdevice
*Device
)
432 static ALvoid
NoneUpdate(ALeffectState
*State
, ALCcontext
*Context
, const ALeffectslot
*Slot
)
438 static ALvoid
NoneProcess(ALeffectState
*State
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[MAXCHANNELS
])
445 ALeffectState
*NoneCreate(void)
447 ALeffectState
*state
;
449 state
= calloc(1, sizeof(*state
));
453 state
->Destroy
= NoneDestroy
;
454 state
->DeviceUpdate
= NoneDeviceUpdate
;
455 state
->Update
= NoneUpdate
;
456 state
->Process
= NoneProcess
;
462 static ALvoid
RemoveEffectSlotArray(ALCcontext
*Context
, ALeffectslot
*slot
)
464 ALeffectslot
**slotlist
, **slotlistend
;
466 LockContext(Context
);
467 slotlist
= Context
->ActiveEffectSlots
;
468 slotlistend
= slotlist
+ Context
->ActiveEffectSlotCount
;
469 while(slotlist
!= slotlistend
)
471 if(*slotlist
== slot
)
473 *slotlist
= *(--slotlistend
);
474 Context
->ActiveEffectSlotCount
--;
479 UnlockContext(Context
);
482 static ALenum
ResizeEffectSlotArray(ALCcontext
*Context
, ALsizei count
)
487 if(count
<= Context
->MaxActiveEffectSlots
-Context
->ActiveEffectSlotCount
)
490 newcount
= Context
->MaxActiveEffectSlots
?
491 (Context
->MaxActiveEffectSlots
<<1) : 1;
492 if(newcount
<= Context
->MaxActiveEffectSlots
||
493 !(temp
=realloc(Context
->ActiveEffectSlots
, newcount
*
494 sizeof(*Context
->ActiveEffectSlots
))))
495 return AL_OUT_OF_MEMORY
;
497 Context
->ActiveEffectSlots
= temp
;
498 Context
->MaxActiveEffectSlots
= newcount
;
502 ALvoid
InitializeEffect(ALCcontext
*Context
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
504 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
505 ALeffectState
*State
= NULL
;
506 ALenum err
= AL_NO_ERROR
;
508 LockContext(Context
);
509 if(newtype
== AL_EFFECT_NULL
&& EffectSlot
->effect
.type
!= AL_EFFECT_NULL
)
511 State
= NoneCreate();
512 if(!State
) err
= AL_OUT_OF_MEMORY
;
514 else if(newtype
== AL_EFFECT_EAXREVERB
|| newtype
== AL_EFFECT_REVERB
)
516 if(EffectSlot
->effect
.type
!= AL_EFFECT_EAXREVERB
&& EffectSlot
->effect
.type
!= AL_EFFECT_REVERB
)
518 State
= ReverbCreate();
519 if(!State
) err
= AL_OUT_OF_MEMORY
;
522 else if(newtype
== AL_EFFECT_ECHO
&& EffectSlot
->effect
.type
!= AL_EFFECT_ECHO
)
524 State
= EchoCreate();
525 if(!State
) err
= AL_OUT_OF_MEMORY
;
527 else if(newtype
== AL_EFFECT_RING_MODULATOR
&& EffectSlot
->effect
.type
!= AL_EFFECT_RING_MODULATOR
)
529 State
= ModulatorCreate();
530 if(!State
) err
= AL_OUT_OF_MEMORY
;
532 else if(newtype
== AL_EFFECT_DEDICATED_DIALOGUE
|| newtype
== AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
)
534 if(EffectSlot
->effect
.type
!= AL_EFFECT_DEDICATED_DIALOGUE
&& EffectSlot
->effect
.type
!= AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
)
536 State
= DedicatedCreate();
537 if(!State
) err
= AL_OUT_OF_MEMORY
;
541 if(err
!= AL_NO_ERROR
)
543 UnlockContext(Context
);
544 alSetError(Context
, err
);
551 oldMode
= SetMixerFPUMode();
553 if(ALeffectState_DeviceUpdate(State
, Context
->Device
) == AL_FALSE
)
555 UnlockContext(Context
);
556 ALeffectState_Destroy(State
);
557 alSetError(Context
, AL_OUT_OF_MEMORY
);
560 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
563 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
565 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
566 /* FIXME: This should be done asynchronously, but since the EffectState
567 * object was changed, it needs an update before its Process method can
569 EffectSlot
->NeedsUpdate
= AL_FALSE
;
570 ALeffectState_Update(EffectSlot
->EffectState
, Context
, EffectSlot
);
571 UnlockContext(Context
);
573 RestoreFPUMode(oldMode
);
575 ALeffectState_Destroy(State
);
581 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
583 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
584 UnlockContext(Context
);
585 EffectSlot
->NeedsUpdate
= AL_TRUE
;
590 ALenum
InitEffectSlot(ALeffectslot
*slot
)
594 if(!(slot
->EffectState
=NoneCreate()))
595 return AL_OUT_OF_MEMORY
;
598 slot
->AuxSendAuto
= AL_TRUE
;
599 slot
->NeedsUpdate
= AL_FALSE
;
600 for(i
= 0;i
< BUFFERSIZE
;i
++)
601 slot
->WetBuffer
[i
] = 0.0f
;
604 slot
->ClickRemoval
[i
] = 0.0f
;
605 slot
->PendingClicks
[i
] = 0.0f
;
612 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
615 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
617 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
618 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
620 // Release effectslot structure
621 ALeffectState_Destroy(temp
->EffectState
);
623 FreeThunkEntry(temp
->effectslot
);
624 memset(temp
, 0, sizeof(ALeffectslot
));