Use a read-write lock to protect access to the UInt maps
[openal-soft/android.git] / OpenAL32 / alFilter.c
blob995d1851fae54df9191992af494ab0aa8555259d
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
25 #include "AL/al.h"
26 #include "AL/alc.h"
27 #include "alMain.h"
28 #include "alFilter.h"
29 #include "alThunk.h"
30 #include "alError.h"
33 static void InitFilterParams(ALfilter *filter, ALenum type);
35 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
37 AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
39 ALCcontext *Context;
40 ALsizei i=0;
42 Context = GetLockedContext();
43 if(!Context) return;
45 if(n < 0 || IsBadWritePtr((void*)filters, n * sizeof(ALuint)))
46 alSetError(Context, AL_INVALID_VALUE);
47 else
49 ALCdevice *device = Context->Device;
50 ALenum err;
52 while(i < n)
54 ALfilter *filter = calloc(1, sizeof(ALfilter));
55 if(!filter)
57 alSetError(Context, AL_OUT_OF_MEMORY);
58 alDeleteFilters(i, filters);
59 break;
62 err = NewThunkEntry(&filter->filter);
63 if(err == AL_NO_ERROR)
64 err = InsertUIntMapEntry(&device->FilterMap, filter->filter, filter);
65 if(err != AL_NO_ERROR)
67 FreeThunkEntry(filter->filter);
68 memset(filter, 0, sizeof(ALfilter));
69 free(filter);
71 alSetError(Context, err);
72 alDeleteFilters(i, filters);
73 break;
76 filters[i++] = filter->filter;
77 InitFilterParams(filter, AL_FILTER_NULL);
81 UnlockContext(Context);
84 AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
86 ALCcontext *Context;
87 ALCdevice *device;
88 ALfilter *ALFilter;
89 ALboolean Failed;
90 ALsizei i;
92 Context = GetLockedContext();
93 if(!Context) return;
95 Failed = AL_TRUE;
96 device = Context->Device;
97 if(n < 0)
98 alSetError(Context, AL_INVALID_VALUE);
99 else
101 Failed = AL_FALSE;
102 // Check that all filters are valid
103 for(i = 0;i < n;i++)
105 if(!filters[i])
106 continue;
108 if(LookupFilter(device->FilterMap, filters[i]) == NULL)
110 alSetError(Context, AL_INVALID_NAME);
111 Failed = AL_TRUE;
112 break;
117 if(!Failed)
119 // All filters are valid
120 for(i = 0;i < n;i++)
122 // Recheck that the filter is valid, because there could be duplicated names
123 if((ALFilter=LookupFilter(device->FilterMap, filters[i])) == NULL)
124 continue;
126 RemoveUIntMapKey(&device->FilterMap, ALFilter->filter);
127 FreeThunkEntry(ALFilter->filter);
129 memset(ALFilter, 0, sizeof(ALfilter));
130 free(ALFilter);
134 UnlockContext(Context);
137 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
139 ALCcontext *Context;
140 ALboolean result;
142 Context = GetLockedContext();
143 if(!Context) return AL_FALSE;
145 result = ((!filter || LookupFilter(Context->Device->FilterMap, filter)) ?
146 AL_TRUE : AL_FALSE);
148 UnlockContext(Context);
150 return result;
153 AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
155 ALCcontext *Context;
156 ALCdevice *Device;
157 ALfilter *ALFilter;
159 Context = GetLockedContext();
160 if(!Context) return;
162 Device = Context->Device;
163 if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
165 switch(param)
167 case AL_FILTER_TYPE:
168 if(iValue == AL_FILTER_NULL ||
169 iValue == AL_FILTER_LOWPASS)
170 InitFilterParams(ALFilter, iValue);
171 else
172 alSetError(Context, AL_INVALID_VALUE);
173 break;
175 default:
176 alSetError(Context, AL_INVALID_ENUM);
177 break;
180 else
181 alSetError(Context, AL_INVALID_NAME);
183 UnlockContext(Context);
186 AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
188 ALCcontext *Context;
189 ALCdevice *Device;
191 switch(param)
193 case AL_FILTER_TYPE:
194 alFilteri(filter, param, piValues[0]);
195 return;
198 Context = GetLockedContext();
199 if(!Context) return;
201 Device = Context->Device;
202 if(LookupFilter(Device->FilterMap, filter) != NULL)
204 switch(param)
206 default:
207 alSetError(Context, AL_INVALID_ENUM);
208 break;
211 else
212 alSetError(Context, AL_INVALID_NAME);
214 UnlockContext(Context);
217 AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
219 ALCcontext *Context;
220 ALCdevice *Device;
221 ALfilter *ALFilter;
223 Context = GetLockedContext();
224 if(!Context) return;
226 Device = Context->Device;
227 if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
229 switch(ALFilter->type)
231 case AL_FILTER_LOWPASS:
232 switch(param)
234 case AL_LOWPASS_GAIN:
235 if(flValue >= AL_LOWPASS_MIN_GAIN &&
236 flValue <= AL_LOWPASS_MAX_GAIN)
237 ALFilter->Gain = flValue;
238 else
239 alSetError(Context, AL_INVALID_VALUE);
240 break;
242 case AL_LOWPASS_GAINHF:
243 if(flValue >= AL_LOWPASS_MIN_GAINHF &&
244 flValue <= AL_LOWPASS_MAX_GAINHF)
245 ALFilter->GainHF = flValue;
246 else
247 alSetError(Context, AL_INVALID_VALUE);
248 break;
250 default:
251 alSetError(Context, AL_INVALID_ENUM);
252 break;
254 break;
256 default:
257 alSetError(Context, AL_INVALID_ENUM);
258 break;
261 else
262 alSetError(Context, AL_INVALID_NAME);
264 UnlockContext(Context);
267 AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
269 /* There are currently no multi-value filter parameters */
270 alFilterf(filter, param, pflValues[0]);
273 AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
275 ALCcontext *Context;
276 ALCdevice *Device;
277 ALfilter *ALFilter;
279 Context = GetLockedContext();
280 if(!Context) return;
282 Device = Context->Device;
283 if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
285 switch(param)
287 case AL_FILTER_TYPE:
288 *piValue = ALFilter->type;
289 break;
291 default:
292 alSetError(Context, AL_INVALID_ENUM);
293 break;
296 else
297 alSetError(Context, AL_INVALID_NAME);
299 UnlockContext(Context);
302 AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
304 ALCcontext *Context;
305 ALCdevice *Device;
307 switch(param)
309 case AL_FILTER_TYPE:
310 alGetFilteri(filter, param, piValues);
311 return;
314 Context = GetLockedContext();
315 if(!Context) return;
317 Device = Context->Device;
318 if(LookupFilter(Device->FilterMap, filter) != NULL)
320 switch(param)
322 default:
323 alSetError(Context, AL_INVALID_ENUM);
324 break;
327 else
328 alSetError(Context, AL_INVALID_NAME);
330 UnlockContext(Context);
333 AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
335 ALCcontext *Context;
336 ALCdevice *Device;
337 ALfilter *ALFilter;
339 Context = GetLockedContext();
340 if(!Context) return;
342 Device = Context->Device;
343 if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
345 switch(ALFilter->type)
347 case AL_FILTER_LOWPASS:
348 switch(param)
350 case AL_LOWPASS_GAIN:
351 *pflValue = ALFilter->Gain;
352 break;
354 case AL_LOWPASS_GAINHF:
355 *pflValue = ALFilter->GainHF;
356 break;
358 default:
359 alSetError(Context, AL_INVALID_ENUM);
360 break;
362 break;
364 default:
365 alSetError(Context, AL_INVALID_ENUM);
366 break;
369 else
370 alSetError(Context, AL_INVALID_NAME);
372 UnlockContext(Context);
375 AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
377 /* There are currently no multi-value filter parameters */
378 alGetFilterf(filter, param, pflValues);
382 ALfloat lpCoeffCalc(ALfloat g, ALfloat cw)
384 ALfloat a = 0.0f;
386 /* Be careful with gains < 0.01, as that causes the coefficient
387 * head towards 1, which will flatten the signal */
388 if(g < 0.9999f) /* 1-epsilon */
390 g = maxf(g, 0.01f);
391 a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) /
392 (1 - g);
395 return a;
398 ALvoid ReleaseALFilters(ALCdevice *device)
400 ALsizei i;
401 for(i = 0;i < device->FilterMap.size;i++)
403 ALfilter *temp = device->FilterMap.array[i].value;
404 device->FilterMap.array[i].value = NULL;
406 // Release filter structure
407 FreeThunkEntry(temp->filter);
408 memset(temp, 0, sizeof(ALfilter));
409 free(temp);
414 static void InitFilterParams(ALfilter *filter, ALenum type)
416 filter->type = type;
418 filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
419 filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;