Ensure that LoopEnd > LoopStart
[openal-soft.git] / OpenAL32 / alFilter.c
blob4d017ee2a7937250a2c752fc2b63677d67fc03aa
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 "alMain.h"
26 #include "alu.h"
27 #include "alFilter.h"
28 #include "alThunk.h"
29 #include "alError.h"
32 extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
33 extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
34 extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
36 static void InitFilterParams(ALfilter *filter, ALenum type);
39 AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
41 ALCdevice *device;
42 ALCcontext *context;
43 ALsizei cur = 0;
44 ALenum err;
46 context = GetContextRef();
47 if(!context) return;
49 if(!(n >= 0))
50 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
52 device = context->Device;
53 for(cur = 0;cur < n;cur++)
55 ALfilter *filter = calloc(1, sizeof(ALfilter));
56 if(!filter)
58 alDeleteFilters(cur, filters);
59 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
61 InitFilterParams(filter, AL_FILTER_NULL);
63 err = NewThunkEntry(&filter->id);
64 if(err == AL_NO_ERROR)
65 err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter);
66 if(err != AL_NO_ERROR)
68 FreeThunkEntry(filter->id);
69 memset(filter, 0, sizeof(ALfilter));
70 free(filter);
72 alDeleteFilters(cur, filters);
73 SET_ERROR_AND_GOTO(context, err, done);
76 filters[cur] = filter->id;
79 done:
80 ALCcontext_DecRef(context);
83 AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
85 ALCdevice *device;
86 ALCcontext *context;
87 ALfilter *filter;
88 ALsizei i;
90 context = GetContextRef();
91 if(!context) return;
93 if(!(n >= 0))
94 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
96 device = context->Device;
97 for(i = 0;i < n;i++)
99 if(filters[i] && LookupFilter(device, filters[i]) == NULL)
100 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
102 for(i = 0;i < n;i++)
104 if((filter=RemoveFilter(device, filters[i])) == NULL)
105 continue;
106 FreeThunkEntry(filter->id);
108 memset(filter, 0, sizeof(*filter));
109 free(filter);
112 done:
113 ALCcontext_DecRef(context);
116 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
118 ALCcontext *Context;
119 ALboolean result;
121 Context = GetContextRef();
122 if(!Context) return AL_FALSE;
124 result = ((!filter || LookupFilter(Context->Device, filter)) ?
125 AL_TRUE : AL_FALSE);
127 ALCcontext_DecRef(Context);
129 return result;
132 AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
134 ALCcontext *Context;
135 ALCdevice *Device;
136 ALfilter *ALFilter;
138 Context = GetContextRef();
139 if(!Context) return;
141 Device = Context->Device;
142 if((ALFilter=LookupFilter(Device, filter)) == NULL)
143 alSetError(Context, AL_INVALID_NAME);
144 else
146 if(param == AL_FILTER_TYPE)
148 if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS)
149 InitFilterParams(ALFilter, value);
150 else
151 alSetError(Context, AL_INVALID_VALUE);
153 else
155 /* Call the appropriate handler */
156 ALfilter_SetParami(ALFilter, Context, param, value);
160 ALCcontext_DecRef(Context);
163 AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
165 ALCcontext *Context;
166 ALCdevice *Device;
167 ALfilter *ALFilter;
169 switch(param)
171 case AL_FILTER_TYPE:
172 alFilteri(filter, param, values[0]);
173 return;
176 Context = GetContextRef();
177 if(!Context) return;
179 Device = Context->Device;
180 if((ALFilter=LookupFilter(Device, filter)) == NULL)
181 alSetError(Context, AL_INVALID_NAME);
182 else
184 /* Call the appropriate handler */
185 ALfilter_SetParamiv(ALFilter, Context, param, values);
188 ALCcontext_DecRef(Context);
191 AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
193 ALCcontext *Context;
194 ALCdevice *Device;
195 ALfilter *ALFilter;
197 Context = GetContextRef();
198 if(!Context) return;
200 Device = Context->Device;
201 if((ALFilter=LookupFilter(Device, filter)) == NULL)
202 alSetError(Context, AL_INVALID_NAME);
203 else
205 /* Call the appropriate handler */
206 ALfilter_SetParamf(ALFilter, Context, param, value);
209 ALCcontext_DecRef(Context);
212 AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
214 ALCcontext *Context;
215 ALCdevice *Device;
216 ALfilter *ALFilter;
218 Context = GetContextRef();
219 if(!Context) return;
221 Device = Context->Device;
222 if((ALFilter=LookupFilter(Device, filter)) == NULL)
223 alSetError(Context, AL_INVALID_NAME);
224 else
226 /* Call the appropriate handler */
227 ALfilter_SetParamfv(ALFilter, Context, param, values);
230 ALCcontext_DecRef(Context);
233 AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
235 ALCcontext *Context;
236 ALCdevice *Device;
237 ALfilter *ALFilter;
239 Context = GetContextRef();
240 if(!Context) return;
242 Device = Context->Device;
243 if((ALFilter=LookupFilter(Device, filter)) == NULL)
244 alSetError(Context, AL_INVALID_NAME);
245 else
247 if(param == AL_FILTER_TYPE)
248 *value = ALFilter->type;
249 else
251 /* Call the appropriate handler */
252 ALfilter_GetParami(ALFilter, Context, param, value);
256 ALCcontext_DecRef(Context);
259 AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
261 ALCcontext *Context;
262 ALCdevice *Device;
263 ALfilter *ALFilter;
265 switch(param)
267 case AL_FILTER_TYPE:
268 alGetFilteri(filter, param, values);
269 return;
272 Context = GetContextRef();
273 if(!Context) return;
275 Device = Context->Device;
276 if((ALFilter=LookupFilter(Device, filter)) == NULL)
277 alSetError(Context, AL_INVALID_NAME);
278 else
280 /* Call the appropriate handler */
281 ALfilter_GetParamiv(ALFilter, Context, param, values);
284 ALCcontext_DecRef(Context);
287 AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
289 ALCcontext *Context;
290 ALCdevice *Device;
291 ALfilter *ALFilter;
293 Context = GetContextRef();
294 if(!Context) return;
296 Device = Context->Device;
297 if((ALFilter=LookupFilter(Device, filter)) == NULL)
298 alSetError(Context, AL_INVALID_NAME);
299 else
301 /* Call the appropriate handler */
302 ALfilter_GetParamf(ALFilter, Context, param, value);
305 ALCcontext_DecRef(Context);
308 AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
310 ALCcontext *Context;
311 ALCdevice *Device;
312 ALfilter *ALFilter;
314 Context = GetContextRef();
315 if(!Context) return;
317 Device = Context->Device;
318 if((ALFilter=LookupFilter(Device, filter)) == NULL)
319 alSetError(Context, AL_INVALID_NAME);
320 else
322 /* Call the appropriate handler */
323 ALfilter_GetParamfv(ALFilter, Context, param, values);
326 ALCcontext_DecRef(Context);
330 void ALfilterState_clear(ALfilterState *filter)
332 filter->x[0] = 0.0f;
333 filter->x[1] = 0.0f;
334 filter->y[0] = 0.0f;
335 filter->y[1] = 0.0f;
338 void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_scale, ALfloat bandwidth)
340 ALfloat alpha;
341 ALfloat w0;
343 // Limit gain to -100dB
344 gain = maxf(gain, 0.00001f);
346 w0 = F_2PI * freq_scale;
348 /* Calculate filter coefficients depending on filter type */
349 switch(type)
351 case ALfilterType_HighShelf:
352 alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f/gain) *
353 (1.0f/0.75f - 1.0f) + 2.0f);
354 filter->b[0] = gain * ((gain + 1.0f) +
355 (gain - 1.0f) * cosf(w0) +
356 2.0f * sqrtf(gain) * alpha);
357 filter->b[1] = -2.0f * gain * ((gain - 1.0f) +
358 (gain + 1.0f) * cosf(w0));
359 filter->b[2] = gain * ((gain + 1.0f) +
360 (gain - 1.0f) * cosf(w0) -
361 2.0f * sqrtf(gain) * alpha);
362 filter->a[0] = (gain + 1.0f) -
363 (gain - 1.0f) * cosf(w0) +
364 2.0f * sqrtf(gain) * alpha;
365 filter->a[1] = 2.0f * ((gain - 1.0f) -
366 (gain + 1.0f) * cosf(w0));
367 filter->a[2] = (gain + 1.0f) -
368 (gain - 1.0f) * cosf(w0) -
369 2.0f * sqrtf(gain) * alpha;
370 break;
371 case ALfilterType_LowShelf:
372 alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) *
373 (1.0f / 0.75f - 1.0f) + 2.0f);
374 filter->b[0] = gain * ((gain + 1.0f) -
375 (gain - 1.0f) * cosf(w0) +
376 2.0f * sqrtf(gain) * alpha);
377 filter->b[1] = 2.0f * gain * ((gain - 1.0f) -
378 (gain + 1.0f) * cosf(w0));
379 filter->b[2] = gain * ((gain + 1.0f) -
380 (gain - 1.0f) * cosf(w0) -
381 2.0f * sqrtf(gain) * alpha);
382 filter->a[0] = (gain + 1.0f) +
383 (gain - 1.0f) * cosf(w0) +
384 2.0f * sqrtf(gain) * alpha;
385 filter->a[1] = -2.0f * ((gain - 1.0f) +
386 (gain + 1.0f) * cosf(w0));
387 filter->a[2] = (gain + 1.0f) +
388 (gain - 1.0f) * cosf(w0) -
389 2.0f * sqrtf(gain) * alpha;
390 break;
391 case ALfilterType_Peaking:
392 alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
393 filter->b[0] = 1.0f + alpha * gain;
394 filter->b[1] = -2.0f * cosf(w0);
395 filter->b[2] = 1.0f - alpha * gain;
396 filter->a[0] = 1.0f + alpha / gain;
397 filter->a[1] = -2.0f * cosf(w0);
398 filter->a[2] = 1.0f - alpha / gain;
399 break;
401 case ALfilterType_LowPass:
402 alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
403 filter->b[0] = (1.0f - cosf(w0)) / 2.0f;
404 filter->b[1] = 1.0f - cosf(w0);
405 filter->b[2] = (1.0f - cosf(w0)) / 2.0f;
406 filter->a[0] = 1.0f + alpha;
407 filter->a[1] = -2.0f * cosf(w0);
408 filter->a[2] = 1.0f - alpha;
409 break;
410 case ALfilterType_HighPass:
411 alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
412 filter->b[0] = (1.0f + cosf(w0)) / 2.0f;
413 filter->b[1] = 1.0f + cosf(w0);
414 filter->b[2] = (1.0f + cosf(w0)) / 2.0f;
415 filter->a[0] = 1.0f + alpha;
416 filter->a[1] = -2.0f * cosf(w0);
417 filter->a[2] = 1.0f - alpha;
418 break;
419 case ALfilterType_BandPass:
420 alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
421 filter->b[0] = alpha;
422 filter->b[1] = 0;
423 filter->b[2] = -alpha;
424 filter->a[0] = 1.0f + alpha;
425 filter->a[1] = -2.0f * cosf(w0);
426 filter->a[2] = 1.0f - alpha;
427 break;
430 filter->b[2] /= filter->a[0];
431 filter->b[1] /= filter->a[0];
432 filter->b[0] /= filter->a[0];
433 filter->a[2] /= filter->a[0];
434 filter->a[1] /= filter->a[0];
435 filter->a[0] /= filter->a[0];
439 static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
440 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
441 static void lp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
442 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
443 static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
445 switch(param)
447 case AL_LOWPASS_GAIN:
448 if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
449 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
450 filter->Gain = val;
451 break;
453 case AL_LOWPASS_GAINHF:
454 if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
455 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
456 filter->GainHF = val;
457 break;
459 default:
460 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
463 static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
465 lp_SetParamf(filter, context, param, vals[0]);
468 static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
469 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
470 static void lp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
471 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
472 static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
474 switch(param)
476 case AL_LOWPASS_GAIN:
477 *val = filter->Gain;
478 break;
480 case AL_LOWPASS_GAINHF:
481 *val = filter->GainHF;
482 break;
484 default:
485 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
488 static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
490 lp_GetParamf(filter, context, param, vals);
494 static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
495 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
496 static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
497 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
498 static void null_SetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
499 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
500 static void null_SetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals))
501 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
503 static void null_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
504 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
505 static void null_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
506 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
507 static void null_GetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
508 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
509 static void null_GetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals))
510 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
513 ALvoid ReleaseALFilters(ALCdevice *device)
515 ALsizei i;
516 for(i = 0;i < device->FilterMap.size;i++)
518 ALfilter *temp = device->FilterMap.array[i].value;
519 device->FilterMap.array[i].value = NULL;
521 // Release filter structure
522 FreeThunkEntry(temp->id);
523 memset(temp, 0, sizeof(ALfilter));
524 free(temp);
529 static void InitFilterParams(ALfilter *filter, ALenum type)
531 if(type == AL_FILTER_LOWPASS)
533 filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
534 filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
535 filter->HFReference = LOWPASSFREQREF;
537 filter->SetParami = lp_SetParami;
538 filter->SetParamiv = lp_SetParamiv;
539 filter->SetParamf = lp_SetParamf;
540 filter->SetParamfv = lp_SetParamfv;
541 filter->GetParami = lp_GetParami;
542 filter->GetParamiv = lp_GetParamiv;
543 filter->GetParamf = lp_GetParamf;
544 filter->GetParamfv = lp_GetParamfv;
546 else
548 filter->SetParami = null_SetParami;
549 filter->SetParamiv = null_SetParamiv;
550 filter->SetParamf = null_SetParamf;
551 filter->SetParamfv = null_SetParamfv;
552 filter->GetParami = null_GetParami;
553 filter->GetParamiv = null_GetParamiv;
554 filter->GetParamf = null_GetParamf;
555 filter->GetParamfv = null_GetParamfv;
557 filter->type = type;