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
)
184 InitializeEffect(Context
, EffectSlot
, effect
);
185 Context
->UpdateSources
= AL_TRUE
;
188 alSetError(Context
, AL_INVALID_VALUE
);
191 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
192 if(iValue
== AL_TRUE
|| iValue
== AL_FALSE
)
194 EffectSlot
->AuxSendAuto
= iValue
;
195 Context
->UpdateSources
= AL_TRUE
;
198 alSetError(Context
, AL_INVALID_VALUE
);
202 alSetError(Context
, AL_INVALID_ENUM
);
207 alSetError(Context
, AL_INVALID_NAME
);
209 ALCcontext_DecRef(Context
);
212 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*piValues
)
218 case AL_EFFECTSLOT_EFFECT
:
219 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
220 alAuxiliaryEffectSloti(effectslot
, param
, piValues
[0]);
224 Context
= GetContextRef();
227 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
232 alSetError(Context
, AL_INVALID_ENUM
);
237 alSetError(Context
, AL_INVALID_NAME
);
239 ALCcontext_DecRef(Context
);
242 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat flValue
)
245 ALeffectslot
*EffectSlot
;
247 Context
= GetContextRef();
250 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
254 case AL_EFFECTSLOT_GAIN
:
255 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
257 EffectSlot
->Gain
= flValue
;
258 EffectSlot
->NeedsUpdate
= AL_TRUE
;
261 alSetError(Context
, AL_INVALID_VALUE
);
265 alSetError(Context
, AL_INVALID_ENUM
);
270 alSetError(Context
, AL_INVALID_NAME
);
272 ALCcontext_DecRef(Context
);
275 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*pflValues
)
281 case AL_EFFECTSLOT_GAIN
:
282 alAuxiliaryEffectSlotf(effectslot
, param
, pflValues
[0]);
286 Context
= GetContextRef();
289 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
294 alSetError(Context
, AL_INVALID_ENUM
);
299 alSetError(Context
, AL_INVALID_NAME
);
301 ALCcontext_DecRef(Context
);
304 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*piValue
)
307 ALeffectslot
*EffectSlot
;
309 Context
= GetContextRef();
312 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
316 case AL_EFFECTSLOT_EFFECT
:
317 *piValue
= EffectSlot
->effect
.effect
;
320 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
321 *piValue
= EffectSlot
->AuxSendAuto
;
325 alSetError(Context
, AL_INVALID_ENUM
);
330 alSetError(Context
, AL_INVALID_NAME
);
332 ALCcontext_DecRef(Context
);
335 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*piValues
)
341 case AL_EFFECTSLOT_EFFECT
:
342 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
343 alGetAuxiliaryEffectSloti(effectslot
, param
, piValues
);
347 Context
= GetContextRef();
350 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
355 alSetError(Context
, AL_INVALID_ENUM
);
360 alSetError(Context
, AL_INVALID_NAME
);
362 ALCcontext_DecRef(Context
);
365 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*pflValue
)
368 ALeffectslot
*EffectSlot
;
370 Context
= GetContextRef();
373 if((EffectSlot
=LookupEffectSlot(Context
, effectslot
)) != NULL
)
377 case AL_EFFECTSLOT_GAIN
:
378 *pflValue
= EffectSlot
->Gain
;
382 alSetError(Context
, AL_INVALID_ENUM
);
387 alSetError(Context
, AL_INVALID_NAME
);
389 ALCcontext_DecRef(Context
);
392 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*pflValues
)
398 case AL_EFFECTSLOT_GAIN
:
399 alGetAuxiliaryEffectSlotf(effectslot
, param
, pflValues
);
403 Context
= GetContextRef();
406 if(LookupEffectSlot(Context
, effectslot
) != NULL
)
411 alSetError(Context
, AL_INVALID_ENUM
);
416 alSetError(Context
, AL_INVALID_NAME
);
418 ALCcontext_DecRef(Context
);
422 static ALvoid
NoneDestroy(ALeffectState
*State
)
424 static ALboolean
NoneDeviceUpdate(ALeffectState
*State
, ALCdevice
*Device
)
430 static ALvoid
NoneUpdate(ALeffectState
*State
, ALCcontext
*Context
, const ALeffectslot
*Slot
)
436 static ALvoid
NoneProcess(ALeffectState
*State
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[MAXCHANNELS
])
443 ALeffectState
*NoneCreate(void)
445 ALeffectState
*state
;
447 state
= calloc(1, sizeof(*state
));
451 state
->Destroy
= NoneDestroy
;
452 state
->DeviceUpdate
= NoneDeviceUpdate
;
453 state
->Update
= NoneUpdate
;
454 state
->Process
= NoneProcess
;
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
--;
477 UnlockContext(Context
);
480 static ALenum
ResizeEffectSlotArray(ALCcontext
*Context
, ALsizei count
)
485 if(count
<= Context
->MaxActiveEffectSlots
-Context
->ActiveEffectSlotCount
)
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
;
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
);
549 oldMode
= SetMixerFPUMode();
551 if(ALeffectState_DeviceUpdate(State
, Context
->Device
) == AL_FALSE
)
553 UnlockContext(Context
);
554 ALeffectState_Destroy(State
);
555 alSetError(Context
, AL_OUT_OF_MEMORY
);
558 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
561 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
563 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
564 /* FIXME: This should be done asynchronously, but since the EffectState
565 * object was changed, it needs an update before its Process method can
567 EffectSlot
->NeedsUpdate
= AL_FALSE
;
568 ALeffectState_Update(EffectSlot
->EffectState
, Context
, EffectSlot
);
569 UnlockContext(Context
);
571 RestoreFPUMode(oldMode
);
573 ALeffectState_Destroy(State
);
579 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
581 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
582 UnlockContext(Context
);
583 EffectSlot
->NeedsUpdate
= AL_TRUE
;
588 ALenum
InitEffectSlot(ALeffectslot
*slot
)
592 if(!(slot
->EffectState
=NoneCreate()))
593 return AL_OUT_OF_MEMORY
;
596 slot
->AuxSendAuto
= AL_TRUE
;
597 slot
->NeedsUpdate
= AL_FALSE
;
598 for(i
= 0;i
< BUFFERSIZE
;i
++)
599 slot
->WetBuffer
[i
] = 0.0f
;
602 slot
->ClickRemoval
[i
] = 0.0f
;
603 slot
->PendingClicks
[i
] = 0.0f
;
610 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
613 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
615 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
616 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
618 // Release effectslot structure
619 ALeffectState_Destroy(temp
->EffectState
);
621 FreeThunkEntry(temp
->effectslot
);
622 memset(temp
, 0, sizeof(ALeffectslot
));