Move some inline functions into a header instead of copying them
[openal-soft.git] / OpenAL32 / alFilter.c
blobde527fea74fdbb154cfc886dfe1cde04483f7cd3
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 void LockFilterList(ALCdevice *device);
33 extern inline void UnlockFilterList(ALCdevice *device);
34 extern inline void ALfilterState_clear(ALfilterState *filter);
35 extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src);
36 extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples);
37 extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
38 extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth);
40 static ALfilter *AllocFilter(ALCcontext *context);
41 static void FreeFilter(ALCdevice *device, ALfilter *filter);
42 static void InitFilterParams(ALfilter *filter, ALenum type);
44 static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
46 FilterSubList *sublist;
47 ALuint lidx = (id-1) >> 6;
48 ALsizei slidx = (id-1) & 0x3f;
50 if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList)))
51 return NULL;
52 sublist = &VECTOR_ELEM(device->FilterList, lidx);
53 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
54 return NULL;
55 return sublist->Filters + slidx;
59 AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
61 ALCcontext *context;
62 ALsizei cur = 0;
64 context = GetContextRef();
65 if(!context) return;
67 if(!(n >= 0))
68 alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n);
69 else for(cur = 0;cur < n;cur++)
71 ALfilter *filter = AllocFilter(context);
72 if(!filter)
74 alDeleteFilters(cur, filters);
75 break;
78 filters[cur] = filter->id;
81 ALCcontext_DecRef(context);
84 AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
86 ALCdevice *device;
87 ALCcontext *context;
88 ALfilter *filter;
89 ALsizei i;
91 context = GetContextRef();
92 if(!context) return;
94 device = context->Device;
95 LockFilterList(device);
96 if(!(n >= 0))
97 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n);
98 for(i = 0;i < n;i++)
100 if(filters[i] && LookupFilter(device, filters[i]) == NULL)
101 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]);
103 for(i = 0;i < n;i++)
105 if((filter=LookupFilter(device, filters[i])) != NULL)
106 FreeFilter(device, filter);
109 done:
110 UnlockFilterList(device);
111 ALCcontext_DecRef(context);
114 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
116 ALCcontext *Context;
117 ALboolean result;
119 Context = GetContextRef();
120 if(!Context) return AL_FALSE;
122 LockFilterList(Context->Device);
123 result = ((!filter || LookupFilter(Context->Device, filter)) ?
124 AL_TRUE : AL_FALSE);
125 UnlockFilterList(Context->Device);
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 LockFilterList(Device);
143 if((ALFilter=LookupFilter(Device, filter)) == NULL)
144 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
145 else
147 if(param == AL_FILTER_TYPE)
149 if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS ||
150 value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
151 InitFilterParams(ALFilter, value);
152 else
153 alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
155 else
157 /* Call the appropriate handler */
158 V(ALFilter,setParami)(Context, param, value);
161 UnlockFilterList(Device);
163 ALCcontext_DecRef(Context);
166 AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
168 ALCcontext *Context;
169 ALCdevice *Device;
170 ALfilter *ALFilter;
172 switch(param)
174 case AL_FILTER_TYPE:
175 alFilteri(filter, param, values[0]);
176 return;
179 Context = GetContextRef();
180 if(!Context) return;
182 Device = Context->Device;
183 LockFilterList(Device);
184 if((ALFilter=LookupFilter(Device, filter)) == NULL)
185 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
186 else
188 /* Call the appropriate handler */
189 V(ALFilter,setParamiv)(Context, param, values);
191 UnlockFilterList(Device);
193 ALCcontext_DecRef(Context);
196 AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
198 ALCcontext *Context;
199 ALCdevice *Device;
200 ALfilter *ALFilter;
202 Context = GetContextRef();
203 if(!Context) return;
205 Device = Context->Device;
206 LockFilterList(Device);
207 if((ALFilter=LookupFilter(Device, filter)) == NULL)
208 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
209 else
211 /* Call the appropriate handler */
212 V(ALFilter,setParamf)(Context, param, value);
214 UnlockFilterList(Device);
216 ALCcontext_DecRef(Context);
219 AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
221 ALCcontext *Context;
222 ALCdevice *Device;
223 ALfilter *ALFilter;
225 Context = GetContextRef();
226 if(!Context) return;
228 Device = Context->Device;
229 LockFilterList(Device);
230 if((ALFilter=LookupFilter(Device, filter)) == NULL)
231 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
232 else
234 /* Call the appropriate handler */
235 V(ALFilter,setParamfv)(Context, param, values);
237 UnlockFilterList(Device);
239 ALCcontext_DecRef(Context);
242 AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
244 ALCcontext *Context;
245 ALCdevice *Device;
246 ALfilter *ALFilter;
248 Context = GetContextRef();
249 if(!Context) return;
251 Device = Context->Device;
252 LockFilterList(Device);
253 if((ALFilter=LookupFilter(Device, filter)) == NULL)
254 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
255 else
257 if(param == AL_FILTER_TYPE)
258 *value = ALFilter->type;
259 else
261 /* Call the appropriate handler */
262 V(ALFilter,getParami)(Context, param, value);
265 UnlockFilterList(Device);
267 ALCcontext_DecRef(Context);
270 AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
272 ALCcontext *Context;
273 ALCdevice *Device;
274 ALfilter *ALFilter;
276 switch(param)
278 case AL_FILTER_TYPE:
279 alGetFilteri(filter, param, values);
280 return;
283 Context = GetContextRef();
284 if(!Context) return;
286 Device = Context->Device;
287 LockFilterList(Device);
288 if((ALFilter=LookupFilter(Device, filter)) == NULL)
289 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
290 else
292 /* Call the appropriate handler */
293 V(ALFilter,getParamiv)(Context, param, values);
295 UnlockFilterList(Device);
297 ALCcontext_DecRef(Context);
300 AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
302 ALCcontext *Context;
303 ALCdevice *Device;
304 ALfilter *ALFilter;
306 Context = GetContextRef();
307 if(!Context) return;
309 Device = Context->Device;
310 LockFilterList(Device);
311 if((ALFilter=LookupFilter(Device, filter)) == NULL)
312 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
313 else
315 /* Call the appropriate handler */
316 V(ALFilter,getParamf)(Context, param, value);
318 UnlockFilterList(Device);
320 ALCcontext_DecRef(Context);
323 AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
325 ALCcontext *Context;
326 ALCdevice *Device;
327 ALfilter *ALFilter;
329 Context = GetContextRef();
330 if(!Context) return;
332 Device = Context->Device;
333 LockFilterList(Device);
334 if((ALFilter=LookupFilter(Device, filter)) == NULL)
335 alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
336 else
338 /* Call the appropriate handler */
339 V(ALFilter,getParamfv)(Context, param, values);
341 UnlockFilterList(Device);
343 ALCcontext_DecRef(Context);
347 void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ)
349 ALfloat alpha, sqrtgain_alpha_2;
350 ALfloat w0, sin_w0, cos_w0;
351 ALfloat a[3] = { 1.0f, 0.0f, 0.0f };
352 ALfloat b[3] = { 1.0f, 0.0f, 0.0f };
354 // Limit gain to -100dB
355 assert(gain > 0.00001f);
357 w0 = F_TAU * f0norm;
358 sin_w0 = sinf(w0);
359 cos_w0 = cosf(w0);
360 alpha = sin_w0/2.0f * rcpQ;
362 /* Calculate filter coefficients depending on filter type */
363 switch(type)
365 case ALfilterType_HighShelf:
366 sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
367 b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
368 b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
369 b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
370 a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
371 a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
372 a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
373 break;
374 case ALfilterType_LowShelf:
375 sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
376 b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
377 b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
378 b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
379 a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
380 a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
381 a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
382 break;
383 case ALfilterType_Peaking:
384 gain = sqrtf(gain);
385 b[0] = 1.0f + alpha * gain;
386 b[1] = -2.0f * cos_w0;
387 b[2] = 1.0f - alpha * gain;
388 a[0] = 1.0f + alpha / gain;
389 a[1] = -2.0f * cos_w0;
390 a[2] = 1.0f - alpha / gain;
391 break;
393 case ALfilterType_LowPass:
394 b[0] = (1.0f - cos_w0) / 2.0f;
395 b[1] = 1.0f - cos_w0;
396 b[2] = (1.0f - cos_w0) / 2.0f;
397 a[0] = 1.0f + alpha;
398 a[1] = -2.0f * cos_w0;
399 a[2] = 1.0f - alpha;
400 break;
401 case ALfilterType_HighPass:
402 b[0] = (1.0f + cos_w0) / 2.0f;
403 b[1] = -(1.0f + cos_w0);
404 b[2] = (1.0f + cos_w0) / 2.0f;
405 a[0] = 1.0f + alpha;
406 a[1] = -2.0f * cos_w0;
407 a[2] = 1.0f - alpha;
408 break;
409 case ALfilterType_BandPass:
410 b[0] = alpha;
411 b[1] = 0;
412 b[2] = -alpha;
413 a[0] = 1.0f + alpha;
414 a[1] = -2.0f * cos_w0;
415 a[2] = 1.0f - alpha;
416 break;
419 filter->a1 = a[1] / a[0];
420 filter->a2 = a[2] / a[0];
421 filter->b0 = b[0] / a[0];
422 filter->b1 = b[1] / a[0];
423 filter->b2 = b[2] / a[0];
427 static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
428 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
429 static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
430 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
431 static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
433 switch(param)
435 case AL_LOWPASS_GAIN:
436 if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
437 SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val);
438 filter->Gain = val;
439 break;
441 case AL_LOWPASS_GAINHF:
442 if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
443 SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val);
444 filter->GainHF = val;
445 break;
447 default:
448 alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
451 static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
452 { ALlowpass_setParamf(filter, context, param, vals[0]); }
454 static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
455 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
456 static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
457 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
458 static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
460 switch(param)
462 case AL_LOWPASS_GAIN:
463 *val = filter->Gain;
464 break;
466 case AL_LOWPASS_GAINHF:
467 *val = filter->GainHF;
468 break;
470 default:
471 alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
474 static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
475 { ALlowpass_getParamf(filter, context, param, vals); }
477 DEFINE_ALFILTER_VTABLE(ALlowpass);
480 static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
481 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
482 static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
483 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
484 static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
486 switch(param)
488 case AL_HIGHPASS_GAIN:
489 if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
490 SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range");
491 filter->Gain = val;
492 break;
494 case AL_HIGHPASS_GAINLF:
495 if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
496 SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range");
497 filter->GainLF = val;
498 break;
500 default:
501 alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
504 static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
505 { ALhighpass_setParamf(filter, context, param, vals[0]); }
507 static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
508 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
509 static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
510 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
511 static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
513 switch(param)
515 case AL_HIGHPASS_GAIN:
516 *val = filter->Gain;
517 break;
519 case AL_HIGHPASS_GAINLF:
520 *val = filter->GainLF;
521 break;
523 default:
524 alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
527 static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
528 { ALhighpass_getParamf(filter, context, param, vals); }
530 DEFINE_ALFILTER_VTABLE(ALhighpass);
533 static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
534 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
535 static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
536 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
537 static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
539 switch(param)
541 case AL_BANDPASS_GAIN:
542 if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
543 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range");
544 filter->Gain = val;
545 break;
547 case AL_BANDPASS_GAINHF:
548 if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
549 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range");
550 filter->GainHF = val;
551 break;
553 case AL_BANDPASS_GAINLF:
554 if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
555 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range");
556 filter->GainLF = val;
557 break;
559 default:
560 alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
563 static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
564 { ALbandpass_setParamf(filter, context, param, vals[0]); }
566 static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
567 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
568 static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
569 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
570 static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
572 switch(param)
574 case AL_BANDPASS_GAIN:
575 *val = filter->Gain;
576 break;
578 case AL_BANDPASS_GAINHF:
579 *val = filter->GainHF;
580 break;
582 case AL_BANDPASS_GAINLF:
583 *val = filter->GainLF;
584 break;
586 default:
587 alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
590 static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
591 { ALbandpass_getParamf(filter, context, param, vals); }
593 DEFINE_ALFILTER_VTABLE(ALbandpass);
596 static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
597 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
598 static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
599 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
600 static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
601 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
602 static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals))
603 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
605 static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
606 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
607 static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
608 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
609 static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val))
610 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
611 static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals))
612 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
614 DEFINE_ALFILTER_VTABLE(ALnullfilter);
617 static ALfilter *AllocFilter(ALCcontext *context)
619 ALCdevice *device = context->Device;
620 FilterSubList *sublist, *subend;
621 ALfilter *filter = NULL;
622 ALsizei lidx = 0;
623 ALsizei slidx;
625 almtx_lock(&device->FilterLock);
626 sublist = VECTOR_BEGIN(device->FilterList);
627 subend = VECTOR_END(device->FilterList);
628 for(;sublist != subend;++sublist)
630 if(sublist->FreeMask)
632 slidx = CTZ64(sublist->FreeMask);
633 filter = sublist->Filters + slidx;
634 break;
636 ++lidx;
638 if(UNLIKELY(!filter))
640 const FilterSubList empty_sublist = { 0, NULL };
641 /* Don't allocate so many list entries that the 32-bit ID could
642 * overflow...
644 if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25))
646 almtx_unlock(&device->FilterLock);
647 alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated");
648 return NULL;
650 lidx = (ALsizei)VECTOR_SIZE(device->FilterList);
651 VECTOR_PUSH_BACK(device->FilterList, empty_sublist);
652 sublist = &VECTOR_BACK(device->FilterList);
653 sublist->FreeMask = ~U64(0);
654 sublist->Filters = al_calloc(16, sizeof(ALfilter)*64);
655 if(UNLIKELY(!sublist->Filters))
657 VECTOR_POP_BACK(device->FilterList);
658 almtx_unlock(&device->FilterLock);
659 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch");
660 return NULL;
663 slidx = 0;
664 filter = sublist->Filters + slidx;
667 memset(filter, 0, sizeof(*filter));
668 InitFilterParams(filter, AL_FILTER_NULL);
670 /* Add 1 to avoid filter ID 0. */
671 filter->id = ((lidx<<6) | slidx) + 1;
673 sublist->FreeMask &= ~(U64(1)<<slidx);
674 almtx_unlock(&device->FilterLock);
676 return filter;
679 static void FreeFilter(ALCdevice *device, ALfilter *filter)
681 ALuint id = filter->id - 1;
682 ALsizei lidx = id >> 6;
683 ALsizei slidx = id & 0x3f;
685 memset(filter, 0, sizeof(*filter));
687 VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx;
690 void ReleaseALFilters(ALCdevice *device)
692 FilterSubList *sublist = VECTOR_BEGIN(device->FilterList);
693 FilterSubList *subend = VECTOR_END(device->FilterList);
694 size_t leftover = 0;
695 for(;sublist != subend;++sublist)
697 ALuint64 usemask = ~sublist->FreeMask;
698 while(usemask)
700 ALsizei idx = CTZ64(usemask);
701 ALfilter *filter = sublist->Filters + idx;
703 memset(filter, 0, sizeof(*filter));
704 ++leftover;
706 usemask &= ~(U64(1) << idx);
708 sublist->FreeMask = ~usemask;
710 if(leftover > 0)
711 WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s");
715 static void InitFilterParams(ALfilter *filter, ALenum type)
717 if(type == AL_FILTER_LOWPASS)
719 filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
720 filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
721 filter->HFReference = LOWPASSFREQREF;
722 filter->GainLF = 1.0f;
723 filter->LFReference = HIGHPASSFREQREF;
724 filter->vtbl = &ALlowpass_vtable;
726 else if(type == AL_FILTER_HIGHPASS)
728 filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
729 filter->GainHF = 1.0f;
730 filter->HFReference = LOWPASSFREQREF;
731 filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
732 filter->LFReference = HIGHPASSFREQREF;
733 filter->vtbl = &ALhighpass_vtable;
735 else if(type == AL_FILTER_BANDPASS)
737 filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
738 filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
739 filter->HFReference = LOWPASSFREQREF;
740 filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
741 filter->LFReference = HIGHPASSFREQREF;
742 filter->vtbl = &ALbandpass_vtable;
744 else
746 filter->Gain = 1.0f;
747 filter->GainHF = 1.0f;
748 filter->HFReference = LOWPASSFREQREF;
749 filter->GainLF = 1.0f;
750 filter->LFReference = HIGHPASSFREQREF;
751 filter->vtbl = &ALnullfilter_vtable;
753 filter->type = type;