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: rlm@0: #include "AL/al.h" rlm@0: #include "AL/alc.h" rlm@0: #include "alMain.h" rlm@0: #include "alFilter.h" rlm@0: #include "alThunk.h" rlm@0: #include "alError.h" rlm@0: rlm@0: rlm@0: static void InitFilterParams(ALfilter *filter, ALenum type); rlm@0: rlm@0: #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k))) rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALsizei i=0; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: if(n < 0 || IsBadWritePtr((void*)filters, n * sizeof(ALuint))) rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: else rlm@0: { rlm@0: ALCdevice *device = Context->Device; rlm@0: ALenum err; rlm@0: rlm@0: while(i < n) rlm@0: { rlm@0: ALfilter *filter = calloc(1, sizeof(ALfilter)); rlm@0: if(!filter) rlm@0: { rlm@0: alSetError(Context, AL_OUT_OF_MEMORY); rlm@0: alDeleteFilters(i, filters); rlm@0: break; rlm@0: } rlm@0: rlm@0: err = NewThunkEntry(&filter->filter); rlm@0: if(err == AL_NO_ERROR) rlm@0: err = InsertUIntMapEntry(&device->FilterMap, filter->filter, filter); rlm@0: if(err != AL_NO_ERROR) rlm@0: { rlm@0: FreeThunkEntry(filter->filter); rlm@0: memset(filter, 0, sizeof(ALfilter)); rlm@0: free(filter); rlm@0: rlm@0: alSetError(Context, err); rlm@0: alDeleteFilters(i, filters); rlm@0: break; rlm@0: } rlm@0: rlm@0: filters[i++] = filter->filter; rlm@0: InitFilterParams(filter, AL_FILTER_NULL); rlm@0: } rlm@0: } rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *device; rlm@0: ALfilter *ALFilter; rlm@0: ALboolean Failed; rlm@0: ALsizei i; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Failed = AL_TRUE; rlm@0: device = Context->Device; rlm@0: if(n < 0) rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: else rlm@0: { rlm@0: Failed = AL_FALSE; rlm@0: // Check that all filters are valid rlm@0: for(i = 0;i < n;i++) rlm@0: { rlm@0: if(!filters[i]) rlm@0: continue; rlm@0: rlm@0: if(LookupFilter(device->FilterMap, filters[i]) == NULL) rlm@0: { rlm@0: alSetError(Context, AL_INVALID_NAME); rlm@0: Failed = AL_TRUE; rlm@0: break; rlm@0: } rlm@0: } rlm@0: } rlm@0: rlm@0: if(!Failed) rlm@0: { rlm@0: // All filters are valid rlm@0: for(i = 0;i < n;i++) rlm@0: { rlm@0: // Recheck that the filter is valid, because there could be duplicated names rlm@0: if((ALFilter=LookupFilter(device->FilterMap, filters[i])) == NULL) rlm@0: continue; rlm@0: rlm@0: RemoveUIntMapKey(&device->FilterMap, ALFilter->filter); rlm@0: FreeThunkEntry(ALFilter->filter); rlm@0: rlm@0: memset(ALFilter, 0, sizeof(ALfilter)); rlm@0: free(ALFilter); rlm@0: } rlm@0: } rlm@0: rlm@0: UnlockContext(Context); rlm@0: } rlm@0: rlm@0: AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) 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 = ((!filter || LookupFilter(Context->Device->FilterMap, filter)) ? 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 alFilteri(ALuint filter, ALenum param, ALint iValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: ALfilter *ALFilter; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_FILTER_TYPE: rlm@0: if(iValue == AL_FILTER_NULL || rlm@0: iValue == AL_FILTER_LOWPASS) rlm@0: InitFilterParams(ALFilter, iValue); 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 alFilteriv(ALuint filter, ALenum param, ALint *piValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_FILTER_TYPE: rlm@0: alFilteri(filter, param, piValues[0]); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if(LookupFilter(Device->FilterMap, filter) != 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 alFilterf(ALuint filter, ALenum param, ALfloat flValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: ALfilter *ALFilter; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) rlm@0: { rlm@0: switch(ALFilter->type) rlm@0: { rlm@0: case AL_FILTER_LOWPASS: rlm@0: switch(param) rlm@0: { rlm@0: case AL_LOWPASS_GAIN: rlm@0: if(flValue >= AL_LOWPASS_MIN_GAIN && rlm@0: flValue <= AL_LOWPASS_MAX_GAIN) rlm@0: ALFilter->Gain = flValue; rlm@0: else rlm@0: alSetError(Context, AL_INVALID_VALUE); rlm@0: break; rlm@0: rlm@0: case AL_LOWPASS_GAINHF: rlm@0: if(flValue >= AL_LOWPASS_MIN_GAINHF && rlm@0: flValue <= AL_LOWPASS_MAX_GAINHF) rlm@0: ALFilter->GainHF = flValue; 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: 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 alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues) rlm@0: { rlm@0: /* There are currently no multi-value filter parameters */ rlm@0: alFilterf(filter, param, pflValues[0]); rlm@0: } rlm@0: rlm@0: AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: ALfilter *ALFilter; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) rlm@0: { rlm@0: switch(param) rlm@0: { rlm@0: case AL_FILTER_TYPE: rlm@0: *piValue = ALFilter->type; 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 alGetFilteriv(ALuint filter, ALenum param, ALint *piValues) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: rlm@0: switch(param) rlm@0: { rlm@0: case AL_FILTER_TYPE: rlm@0: alGetFilteri(filter, param, piValues); rlm@0: return; rlm@0: } rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if(LookupFilter(Device->FilterMap, filter) != 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 alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue) rlm@0: { rlm@0: ALCcontext *Context; rlm@0: ALCdevice *Device; rlm@0: ALfilter *ALFilter; rlm@0: rlm@0: Context = GetLockedContext(); rlm@0: if(!Context) return; rlm@0: rlm@0: Device = Context->Device; rlm@0: if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) rlm@0: { rlm@0: switch(ALFilter->type) rlm@0: { rlm@0: case AL_FILTER_LOWPASS: rlm@0: switch(param) rlm@0: { rlm@0: case AL_LOWPASS_GAIN: rlm@0: *pflValue = ALFilter->Gain; rlm@0: break; rlm@0: rlm@0: case AL_LOWPASS_GAINHF: rlm@0: *pflValue = ALFilter->GainHF; rlm@0: break; rlm@0: rlm@0: default: rlm@0: alSetError(Context, AL_INVALID_ENUM); rlm@0: break; rlm@0: } 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 alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues) rlm@0: { rlm@0: /* There are currently no multi-value filter parameters */ rlm@0: alGetFilterf(filter, param, pflValues); rlm@0: } rlm@0: rlm@0: rlm@0: ALfloat lpCoeffCalc(ALfloat g, ALfloat cw) rlm@0: { rlm@0: ALfloat a = 0.0f; rlm@0: rlm@0: /* Be careful with gains < 0.01, as that causes the coefficient rlm@0: * head towards 1, which will flatten the signal */ rlm@0: if(g < 0.9999f) /* 1-epsilon */ rlm@0: { rlm@0: g = maxf(g, 0.01f); rlm@0: a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / rlm@0: (1 - g); rlm@0: } rlm@0: rlm@0: return a; rlm@0: } rlm@0: rlm@0: ALvoid ReleaseALFilters(ALCdevice *device) rlm@0: { rlm@0: ALsizei i; rlm@0: for(i = 0;i < device->FilterMap.size;i++) rlm@0: { rlm@0: ALfilter *temp = device->FilterMap.array[i].value; rlm@0: device->FilterMap.array[i].value = NULL; rlm@0: rlm@0: // Release filter structure rlm@0: FreeThunkEntry(temp->filter); rlm@0: memset(temp, 0, sizeof(ALfilter)); rlm@0: free(temp); rlm@0: } rlm@0: } rlm@0: rlm@0: rlm@0: static void InitFilterParams(ALfilter *filter, ALenum type) rlm@0: { rlm@0: filter->type = type; rlm@0: rlm@0: filter->Gain = AL_LOWPASS_DEFAULT_GAIN; rlm@0: filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; rlm@0: }