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
AddEffectSlotArray(ALCcontext
*Context
, ALsizei count
, const ALuint
*slots
);
36 static ALvoid
RemoveEffectSlotArray(ALCcontext
*Context
, ALeffectslot
*slot
);
39 AL_API ALvoid AL_APIENTRY
alGenAuxiliaryEffectSlots(ALsizei n
, ALuint
*effectslots
)
44 Context
= GetContextRef();
51 CHECK_VALUE(Context
, n
>= 0);
52 for(cur
= 0;cur
< n
;cur
++)
54 ALeffectslot
*slot
= calloc(1, sizeof(ALeffectslot
));
55 err
= AL_OUT_OF_MEMORY
;
56 if(!slot
|| (err
=InitEffectSlot(slot
)) != AL_NO_ERROR
)
59 al_throwerr(Context
, err
);
63 err
= NewThunkEntry(&slot
->id
);
64 if(err
== AL_NO_ERROR
)
65 err
= InsertUIntMapEntry(&Context
->EffectSlotMap
, slot
->id
, slot
);
66 if(err
!= AL_NO_ERROR
)
68 FreeThunkEntry(slot
->id
);
69 ALeffectState_Destroy(slot
->EffectState
);
72 al_throwerr(Context
, err
);
75 effectslots
[cur
] = slot
->id
;
77 err
= AddEffectSlotArray(Context
, n
, effectslots
);
78 if(err
!= AL_NO_ERROR
)
79 al_throwerr(Context
, err
);
84 alDeleteAuxiliaryEffectSlots(cur
, effectslots
);
88 ALCcontext_DecRef(Context
);
91 AL_API ALvoid AL_APIENTRY
alDeleteAuxiliaryEffectSlots(ALsizei n
, const ALuint
*effectslots
)
97 Context
= GetContextRef();
102 CHECK_VALUE(Context
, n
>= 0);
105 if((slot
=LookupEffectSlot(Context
, effectslots
[i
])) == NULL
)
106 al_throwerr(Context
, AL_INVALID_NAME
);
108 al_throwerr(Context
, AL_INVALID_OPERATION
);
111 // All effectslots are valid
114 if((slot
=RemoveEffectSlot(Context
, effectslots
[i
])) == NULL
)
116 FreeThunkEntry(slot
->id
);
118 RemoveEffectSlotArray(Context
, slot
);
119 ALeffectState_Destroy(slot
->EffectState
);
121 memset(slot
, 0, sizeof(*slot
));
127 ALCcontext_DecRef(Context
);
130 AL_API ALboolean AL_APIENTRY
alIsAuxiliaryEffectSlot(ALuint effectslot
)
135 Context
= GetContextRef();
136 if(!Context
) return AL_FALSE
;
138 result
= (LookupEffectSlot(Context
, effectslot
) ? AL_TRUE
: AL_FALSE
);
140 ALCcontext_DecRef(Context
);
145 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint value
)
149 ALeffect
*effect
= NULL
;
152 Context
= GetContextRef();
157 ALCdevice
*device
= Context
->Device
;
158 if((Slot
=LookupEffectSlot(Context
, effectslot
)) == NULL
)
159 al_throwerr(Context
, AL_INVALID_NAME
);
162 case AL_EFFECTSLOT_EFFECT
:
163 CHECK_VALUE(Context
, value
== 0 || (effect
=LookupEffect(device
, value
)) != NULL
);
165 err
= InitializeEffect(device
, Slot
, effect
);
166 if(err
!= AL_NO_ERROR
)
167 al_throwerr(Context
, err
);
168 Context
->UpdateSources
= AL_TRUE
;
171 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
172 CHECK_VALUE(Context
, value
== AL_TRUE
|| value
== AL_FALSE
);
174 Slot
->AuxSendAuto
= value
;
175 Context
->UpdateSources
= AL_TRUE
;
179 al_throwerr(Context
, AL_INVALID_ENUM
);
184 ALCcontext_DecRef(Context
);
187 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, const ALint
*values
)
193 case AL_EFFECTSLOT_EFFECT
:
194 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
195 alAuxiliaryEffectSloti(effectslot
, param
, values
[0]);
199 Context
= GetContextRef();
204 if(LookupEffectSlot(Context
, effectslot
) == NULL
)
205 al_throwerr(Context
, AL_INVALID_NAME
);
209 al_throwerr(Context
, AL_INVALID_ENUM
);
214 ALCcontext_DecRef(Context
);
217 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat value
)
222 Context
= GetContextRef();
227 if((Slot
=LookupEffectSlot(Context
, effectslot
)) == NULL
)
228 al_throwerr(Context
, AL_INVALID_NAME
);
231 case AL_EFFECTSLOT_GAIN
:
232 CHECK_VALUE(Context
, value
>= 0.0f
&& value
<= 1.0f
);
235 Slot
->NeedsUpdate
= AL_TRUE
;
239 al_throwerr(Context
, AL_INVALID_ENUM
);
244 ALCcontext_DecRef(Context
);
247 AL_API ALvoid AL_APIENTRY
alAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, const ALfloat
*values
)
253 case AL_EFFECTSLOT_GAIN
:
254 alAuxiliaryEffectSlotf(effectslot
, param
, values
[0]);
258 Context
= GetContextRef();
263 if(LookupEffectSlot(Context
, effectslot
) == NULL
)
264 al_throwerr(Context
, AL_INVALID_NAME
);
268 al_throwerr(Context
, AL_INVALID_ENUM
);
273 ALCcontext_DecRef(Context
);
276 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSloti(ALuint effectslot
, ALenum param
, ALint
*value
)
281 Context
= GetContextRef();
286 if((Slot
=LookupEffectSlot(Context
, effectslot
)) == NULL
)
287 al_throwerr(Context
, AL_INVALID_NAME
);
290 case AL_EFFECTSLOT_EFFECT
:
291 *value
= Slot
->effect
.id
;
294 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
295 *value
= Slot
->AuxSendAuto
;
299 al_throwerr(Context
, AL_INVALID_ENUM
);
304 ALCcontext_DecRef(Context
);
307 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotiv(ALuint effectslot
, ALenum param
, ALint
*values
)
313 case AL_EFFECTSLOT_EFFECT
:
314 case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
:
315 alGetAuxiliaryEffectSloti(effectslot
, param
, values
);
319 Context
= GetContextRef();
324 if(LookupEffectSlot(Context
, effectslot
) == NULL
)
325 al_throwerr(Context
, AL_INVALID_NAME
);
329 al_throwerr(Context
, AL_INVALID_ENUM
);
334 ALCcontext_DecRef(Context
);
337 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotf(ALuint effectslot
, ALenum param
, ALfloat
*value
)
342 Context
= GetContextRef();
347 if((Slot
=LookupEffectSlot(Context
, effectslot
)) == NULL
)
348 al_throwerr(Context
, AL_INVALID_NAME
);
351 case AL_EFFECTSLOT_GAIN
:
356 al_throwerr(Context
, AL_INVALID_ENUM
);
361 ALCcontext_DecRef(Context
);
364 AL_API ALvoid AL_APIENTRY
alGetAuxiliaryEffectSlotfv(ALuint effectslot
, ALenum param
, ALfloat
*values
)
370 case AL_EFFECTSLOT_GAIN
:
371 alGetAuxiliaryEffectSlotf(effectslot
, param
, values
);
375 Context
= GetContextRef();
380 if(LookupEffectSlot(Context
, effectslot
) == NULL
)
381 al_throwerr(Context
, AL_INVALID_NAME
);
385 al_throwerr(Context
, AL_INVALID_ENUM
);
390 ALCcontext_DecRef(Context
);
394 static ALvoid
NoneDestroy(ALeffectState
*State
)
396 static ALboolean
NoneDeviceUpdate(ALeffectState
*State
, ALCdevice
*Device
)
402 static ALvoid
NoneUpdate(ALeffectState
*State
, ALCdevice
*Device
, const ALeffectslot
*Slot
)
408 static ALvoid
NoneProcess(ALeffectState
*State
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[MaxChannels
])
415 ALeffectState
*NoneCreate(void)
417 ALeffectState
*state
;
419 state
= calloc(1, sizeof(*state
));
423 state
->Destroy
= NoneDestroy
;
424 state
->DeviceUpdate
= NoneDeviceUpdate
;
425 state
->Update
= NoneUpdate
;
426 state
->Process
= NoneProcess
;
432 static ALvoid
RemoveEffectSlotArray(ALCcontext
*Context
, ALeffectslot
*slot
)
434 ALeffectslot
**slotlist
, **slotlistend
;
436 LockContext(Context
);
437 slotlist
= Context
->ActiveEffectSlots
;
438 slotlistend
= slotlist
+ Context
->ActiveEffectSlotCount
;
439 while(slotlist
!= slotlistend
)
441 if(*slotlist
== slot
)
443 *slotlist
= *(--slotlistend
);
444 Context
->ActiveEffectSlotCount
--;
449 UnlockContext(Context
);
452 static ALenum
AddEffectSlotArray(ALCcontext
*Context
, ALsizei count
, const ALuint
*slots
)
456 LockContext(Context
);
457 if(count
> Context
->MaxActiveEffectSlots
-Context
->ActiveEffectSlotCount
)
462 newcount
= Context
->MaxActiveEffectSlots
? (Context
->MaxActiveEffectSlots
<<1) : 1;
463 if(newcount
> Context
->MaxActiveEffectSlots
)
464 temp
= realloc(Context
->ActiveEffectSlots
,
465 newcount
* sizeof(*Context
->ActiveEffectSlots
));
468 UnlockContext(Context
);
469 return AL_OUT_OF_MEMORY
;
471 Context
->ActiveEffectSlots
= temp
;
472 Context
->MaxActiveEffectSlots
= newcount
;
474 for(i
= 0;i
< count
;i
++)
476 ALeffectslot
*slot
= LookupEffectSlot(Context
, slots
[i
]);
477 assert(slot
!= NULL
);
478 Context
->ActiveEffectSlots
[Context
->ActiveEffectSlotCount
++] = slot
;
480 UnlockContext(Context
);
484 ALenum
InitializeEffect(ALCdevice
*Device
, ALeffectslot
*EffectSlot
, ALeffect
*effect
)
486 ALenum newtype
= (effect
? effect
->type
: AL_EFFECT_NULL
);
487 ALeffectState
*State
= NULL
;
488 ALenum err
= AL_NO_ERROR
;
490 ALCdevice_Lock(Device
);
491 if(newtype
== AL_EFFECT_NULL
&& EffectSlot
->effect
.type
!= AL_EFFECT_NULL
)
493 State
= NoneCreate();
494 if(!State
) err
= AL_OUT_OF_MEMORY
;
496 else if(newtype
== AL_EFFECT_EAXREVERB
|| newtype
== AL_EFFECT_REVERB
)
498 if(EffectSlot
->effect
.type
!= AL_EFFECT_EAXREVERB
&& EffectSlot
->effect
.type
!= AL_EFFECT_REVERB
)
500 State
= ReverbCreate();
501 if(!State
) err
= AL_OUT_OF_MEMORY
;
504 else if(newtype
== AL_EFFECT_ECHO
&& EffectSlot
->effect
.type
!= AL_EFFECT_ECHO
)
506 State
= EchoCreate();
507 if(!State
) err
= AL_OUT_OF_MEMORY
;
509 else if(newtype
== AL_EFFECT_RING_MODULATOR
&& EffectSlot
->effect
.type
!= AL_EFFECT_RING_MODULATOR
)
511 State
= ModulatorCreate();
512 if(!State
) err
= AL_OUT_OF_MEMORY
;
514 else if(newtype
== AL_EFFECT_DEDICATED_DIALOGUE
|| newtype
== AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
)
516 if(EffectSlot
->effect
.type
!= AL_EFFECT_DEDICATED_DIALOGUE
&& EffectSlot
->effect
.type
!= AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT
)
518 State
= DedicatedCreate();
519 if(!State
) err
= AL_OUT_OF_MEMORY
;
523 if(err
!= AL_NO_ERROR
)
525 ALCdevice_Unlock(Device
);
532 oldMode
= SetMixerFPUMode();
534 if(ALeffectState_DeviceUpdate(State
, Device
) == AL_FALSE
)
536 RestoreFPUMode(oldMode
);
537 ALCdevice_Unlock(Device
);
538 ALeffectState_Destroy(State
);
539 return AL_OUT_OF_MEMORY
;
541 State
= ExchangePtr((XchgPtr
*)&EffectSlot
->EffectState
, State
);
544 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
546 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
547 /* FIXME: This should be done asynchronously, but since the EffectState
548 * object was changed, it needs an update before its Process method can
550 EffectSlot
->NeedsUpdate
= AL_FALSE
;
551 ALeffectState_Update(EffectSlot
->EffectState
, Device
, EffectSlot
);
552 ALCdevice_Unlock(Device
);
554 RestoreFPUMode(oldMode
);
556 ALeffectState_Destroy(State
);
562 memset(&EffectSlot
->effect
, 0, sizeof(EffectSlot
->effect
));
564 memcpy(&EffectSlot
->effect
, effect
, sizeof(*effect
));
565 ALCdevice_Unlock(Device
);
566 EffectSlot
->NeedsUpdate
= AL_TRUE
;
573 ALenum
InitEffectSlot(ALeffectslot
*slot
)
577 if(!(slot
->EffectState
=NoneCreate()))
578 return AL_OUT_OF_MEMORY
;
581 slot
->AuxSendAuto
= AL_TRUE
;
582 slot
->NeedsUpdate
= AL_FALSE
;
583 for(i
= 0;i
< BUFFERSIZE
;i
++)
584 slot
->WetBuffer
[i
] = 0.0f
;
587 slot
->ClickRemoval
[i
] = 0.0f
;
588 slot
->PendingClicks
[i
] = 0.0f
;
595 ALvoid
ReleaseALAuxiliaryEffectSlots(ALCcontext
*Context
)
598 for(pos
= 0;pos
< Context
->EffectSlotMap
.size
;pos
++)
600 ALeffectslot
*temp
= Context
->EffectSlotMap
.array
[pos
].value
;
601 Context
->EffectSlotMap
.array
[pos
].value
= NULL
;
603 ALeffectState_Destroy(temp
->EffectState
);
605 FreeThunkEntry(temp
->id
);
606 memset(temp
, 0, sizeof(ALeffectslot
));