rlm@0: /** rlm@0: * OpenAL cross platform audio library rlm@0: * Copyright (C) 1999-2007 by authors. rlm@0: * This library is free software; you can redistribute it and/or rlm@0: * modify it under the terms of the GNU Library General Public rlm@0: * License as published by the Free Software Foundation; either rlm@0: * version 2 of the License, or (at your option) any later version. rlm@0: * rlm@0: * This library is distributed in the hope that it will be useful, rlm@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of rlm@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU rlm@0: * Library General Public License for more details. rlm@0: * rlm@0: * You should have received a copy of the GNU Library General Public rlm@0: * License along with this library; if not, write to the rlm@0: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, rlm@0: * Boston, MA 02111-1307, USA. rlm@0: * Or go to http://www.gnu.org/copyleft/lgpl.html rlm@0: */ rlm@0: rlm@0: #include "config.h" rlm@0: rlm@0: #include rlm@0: #include rlm@0: rlm@0: #include "AL/al.h" rlm@0: #include "AL/alc.h" rlm@0: #include "alMain.h" rlm@0: #include "alAuxEffectSlot.h" rlm@0: #include "alThunk.h" rlm@0: #include "alError.h" rlm@0: #include "alSource.h" rlm@0: rlm@0: rlm@0: static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); rlm@0: rlm@0: #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k))) rlm@0: #define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k))) rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint))) rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: else if((ALuint)n > Device->AuxiliaryEffectSlotMax - Context->EffectSlotMap.size) rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: else rlm@0: { rlm@0: ALenum err; rlm@0: ALsizei i, j; rlm@0: rlm@0: i = 0; rlm@0: while(i < n) rlm@0: { rlm@0: ALeffectslot *slot = calloc(1, sizeof(ALeffectslot)); rlm@0: if(!slot || !(slot->EffectState=NoneCreate())) rlm@0: { rlm@0: free(slot); rlm@0: // We must have run out or memory rlm@0: alSetError(Context, AL_OUT_OF_MEMORY); rlm@0: alDeleteAuxiliaryEffectSlots(i, effectslots); rlm@0: break; rlm@0: } rlm@0: rlm@0: err = NewThunkEntry(&slot->effectslot); rlm@0: if(err == AL_NO_ERROR) rlm@0: err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->effectslot, slot); rlm@0: if(err != AL_NO_ERROR) rlm@0: { rlm@0: FreeThunkEntry(slot->effectslot); rlm@0: ALEffect_Destroy(slot->EffectState); rlm@0: free(slot); rlm@0: rlm@0: alSetError(Context, err); rlm@0: alDeleteAuxiliaryEffectSlots(i, effectslots); rlm@0: break; rlm@0: } rlm@0: rlm@0: effectslots[i++] = slot->effectslot; rlm@0: rlm@0: slot->Gain = 1.0; rlm@0: slot->AuxSendAuto = AL_TRUE; rlm@0: slot->NeedsUpdate = AL_FALSE; rlm@0: for(j = 0;j < BUFFERSIZE;j++) rlm@0: slot->WetBuffer[j] = 0.0f; rlm@0: for(j = 0;j < 1;j++) rlm@0: { rlm@0: slot->ClickRemoval[j] = 0.0f; rlm@0: slot->PendingClicks[j] = 0.0f; rlm@0: } rlm@0: slot->refcount = 0; rlm@0: } rlm@0: } rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALeffectslot *EffectSlot; rlm@0: ALboolean SlotsValid = AL_FALSE; rlm@0: ALsizei i; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(n < 0) rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: else rlm@0: { rlm@0: SlotsValid = AL_TRUE; rlm@0: // Check that all effectslots are valid rlm@0: for(i = 0;i < n;i++) rlm@0: { rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL) rlm@0: { rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: SlotsValid = AL_FALSE; rlm@0: break; rlm@0: } rlm@0: else if(EffectSlot->refcount > 0) rlm@0: { rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: SlotsValid = AL_FALSE; rlm@0: break; rlm@0: } rlm@0: } rlm@0: } rlm@0: rlm@0: if(SlotsValid) rlm@0: { rlm@0: // All effectslots are valid rlm@0: for(i = 0;i < n;i++) rlm@0: { rlm@0: // Recheck that the effectslot is valid, because there could be duplicated names rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL) rlm@0: continue; rlm@0: rlm@0: ALEffect_Destroy(EffectSlot->EffectState); rlm@0: rlm@0: RemoveUIntMapKey(&Context->EffectSlotMap, EffectSlot->effectslot); rlm@0: FreeThunkEntry(EffectSlot->effectslot); rlm@0: rlm@0: memset(EffectSlot, 0, sizeof(ALeffectslot)); rlm@0: free(EffectSlot); rlm@0: } rlm@0: } rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALboolean result; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return AL_FALSE; rlm@0: rlm@0: result = (LookupEffectSlot(Context->EffectSlotMap, effectslot) ? rlm@0: AL_TRUE : AL_FALSE); rlm@0: rlm@0: UnlockContext(Context); rlm@0: rlm@0: return result; rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue) rlm@0: { rlm@0: ALCdevice *Device; rlm@0: ALCcontext *Context; rlm@0: ALeffectslot *EffectSlot; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_EFFECT: { rlm@0: ALeffect *effect = NULL; rlm@0: rlm@0: if(iValue == 0 || rlm@0: (effect=LookupEffect(Device->EffectMap, iValue)) != NULL) rlm@0: { rlm@0: InitializeEffect(Context, EffectSlot, effect); rlm@0: Context->UpdateSources = AL_TRUE; rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: } break; rlm@0: rlm@0: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: rlm@0: if(iValue == AL_TRUE || iValue == AL_FALSE) rlm@0: { rlm@0: EffectSlot->AuxSendAuto = iValue; rlm@0: Context->UpdateSources = AL_TRUE; rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: break; rlm@0: rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_EFFECT: rlm@0: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: rlm@0: alAuxiliaryEffectSloti(effectslot, param, piValues[0]); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALeffectslot *EffectSlot; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_GAIN: rlm@0: if(flValue >= 0.0f && flValue <= 1.0f) rlm@0: { rlm@0: EffectSlot->Gain = flValue; rlm@0: EffectSlot->NeedsUpdate = AL_TRUE; rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: break; rlm@0: rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_GAIN: rlm@0: alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALeffectslot *EffectSlot; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_EFFECT: rlm@0: *piValue = EffectSlot->effect.effect; rlm@0: break; rlm@0: rlm@0: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: rlm@0: *piValue = EffectSlot->AuxSendAuto; rlm@0: break; rlm@0: rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_EFFECT: rlm@0: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: rlm@0: alGetAuxiliaryEffectSloti(effectslot, param, piValues); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALeffectslot *EffectSlot; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_GAIN: rlm@0: *pflValue = EffectSlot->Gain; rlm@0: break; rlm@0: rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_EFFECTSLOT_GAIN: rlm@0: alGetAuxiliaryEffectSlotf(effectslot, param, pflValues); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } rlm@0: } rlm@0: else rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: rlm@0: static ALvoid NoneDestroy(ALeffectState *State) rlm@0: { free(State); } rlm@0: static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device) rlm@0: { rlm@0: return AL_TRUE; rlm@0: (void)State; rlm@0: (void)Device; rlm@0: } rlm@0: static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffectslot *Slot) rlm@0: { rlm@0: (void)State; rlm@0: (void)Context; rlm@0: (void)Slot; rlm@0: } rlm@0: static ALvoid NoneProcess(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS]) rlm@0: { rlm@0: (void)State; rlm@0: (void)Slot; rlm@0: (void)SamplesToDo; rlm@0: (void)SamplesIn; rlm@0: (void)SamplesOut; rlm@0: } rlm@0: ALeffectState *NoneCreate(void) rlm@0: { rlm@0: ALeffectState *state; rlm@0: rlm@0: state = calloc(1, sizeof(*state)); rlm@0: if(!state) rlm@0: return NULL; rlm@0: rlm@0: state->Destroy = NoneDestroy; rlm@0: state->DeviceUpdate = NoneDeviceUpdate; rlm@0: state->Update = NoneUpdate; rlm@0: state->Process = NoneProcess; rlm@0: rlm@0: return state; rlm@0: } rlm@0: rlm@0: static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) rlm@0: { rlm@0: if(EffectSlot->effect.type != (effect?effect->type:AL_EFFECT_NULL)) rlm@0: { rlm@0: ALeffectState *NewState = NULL; rlm@0: if(!effect || effect->type == AL_EFFECT_NULL) rlm@0: NewState = NoneCreate(); rlm@0: else if(effect->type == AL_EFFECT_EAXREVERB) rlm@0: NewState = EAXVerbCreate(); rlm@0: else if(effect->type == AL_EFFECT_REVERB) rlm@0: NewState = VerbCreate(); rlm@0: else if(effect->type == AL_EFFECT_ECHO) rlm@0: NewState = EchoCreate(); rlm@0: else if(effect->type == AL_EFFECT_RING_MODULATOR) rlm@0: NewState = ModulatorCreate(); rlm@0: else if(effect->type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) rlm@0: NewState = DedicatedLFECreate(); rlm@0: else if(effect->type == AL_EFFECT_DEDICATED_DIALOGUE) rlm@0: NewState = DedicatedDLGCreate(); rlm@0: /* No new state? An error occured.. */ rlm@0: if(NewState == NULL || rlm@0: ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE) rlm@0: { rlm@0: if(NewState) rlm@0: ALEffect_Destroy(NewState); rlm@0: alSetError(Context, AL_OUT_OF_MEMORY); rlm@0: return; rlm@0: } rlm@0: if(EffectSlot->EffectState) rlm@0: ALEffect_Destroy(EffectSlot->EffectState); rlm@0: EffectSlot->EffectState = NewState; rlm@0: rlm@0: if(!effect) rlm@0: memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); rlm@0: else rlm@0: memcpy(&EffectSlot->effect, effect, sizeof(*effect)); rlm@0: /* FIXME: This should be done asychronously, but since the EfefctState rlm@0: * object was changed, it needs an update before its Process method can rlm@0: * be called (coming changes may not guarantee an update when the rlm@0: * NeedsUpdate flag is set). */ rlm@0: EffectSlot->NeedsUpdate = AL_FALSE; rlm@0: ALEffect_Update(EffectSlot->EffectState, Context, EffectSlot); rlm@0: } rlm@0: else rlm@0: { rlm@0: if(!effect) rlm@0: memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); rlm@0: else rlm@0: memcpy(&EffectSlot->effect, effect, sizeof(*effect)); rlm@0: EffectSlot->NeedsUpdate = AL_TRUE; rlm@0: } rlm@0: } rlm@0: rlm@0: rlm@0: ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) rlm@0: { rlm@0: ALsizei pos; rlm@0: for(pos = 0;pos < Context->EffectSlotMap.size;pos++) rlm@0: { rlm@0: ALeffectslot *temp = Context->EffectSlotMap.array[pos].value; rlm@0: Context->EffectSlotMap.array[pos].value = NULL; rlm@0: rlm@0: // Release effectslot structure rlm@0: ALEffect_Destroy(temp->EffectState); rlm@0: rlm@0: FreeThunkEntry(temp->effectslot); rlm@0: memset(temp, 0, sizeof(ALeffectslot)); rlm@0: free(temp); rlm@0: } rlm@0: }