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
31 extern inline void LockFilterList(ALCdevice
*device
);
32 extern inline void UnlockFilterList(ALCdevice
*device
);
33 extern inline void ALfilterState_clear(ALfilterState
*filter
);
34 extern inline void ALfilterState_copyParams(ALfilterState
*restrict dst
, const ALfilterState
*restrict src
);
35 extern inline void ALfilterState_processPassthru(ALfilterState
*filter
, const ALfloat
*restrict src
, ALsizei numsamples
);
36 extern inline ALfloat
calc_rcpQ_from_slope(ALfloat gain
, ALfloat slope
);
37 extern inline ALfloat
calc_rcpQ_from_bandwidth(ALfloat f0norm
, ALfloat bandwidth
);
39 static ALfilter
*AllocFilter(ALCcontext
*context
);
40 static void FreeFilter(ALCdevice
*device
, ALfilter
*filter
);
41 static void InitFilterParams(ALfilter
*filter
, ALenum type
);
43 static inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
)
45 FilterSubList
*sublist
;
46 ALuint lidx
= (id
-1) >> 6;
47 ALsizei slidx
= (id
-1) & 0x3f;
49 if(UNLIKELY(lidx
>= VECTOR_SIZE(device
->FilterList
)))
51 sublist
= &VECTOR_ELEM(device
->FilterList
, lidx
);
52 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
54 return sublist
->Filters
+ slidx
;
58 AL_API ALvoid AL_APIENTRY
alGenFilters(ALsizei n
, ALuint
*filters
)
63 context
= GetContextRef();
67 alSetError(context
, AL_INVALID_VALUE
, "Generating %d filters", n
);
68 else for(cur
= 0;cur
< n
;cur
++)
70 ALfilter
*filter
= AllocFilter(context
);
73 alDeleteFilters(cur
, filters
);
77 filters
[cur
] = filter
->id
;
80 ALCcontext_DecRef(context
);
83 AL_API ALvoid AL_APIENTRY
alDeleteFilters(ALsizei n
, const ALuint
*filters
)
90 context
= GetContextRef();
93 device
= context
->Device
;
94 LockFilterList(device
);
96 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d filters", n
);
99 if(filters
[i
] && LookupFilter(device
, filters
[i
]) == NULL
)
100 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid filter ID %u", filters
[i
]);
104 if((filter
=LookupFilter(device
, filters
[i
])) != NULL
)
105 FreeFilter(device
, filter
);
109 UnlockFilterList(device
);
110 ALCcontext_DecRef(context
);
113 AL_API ALboolean AL_APIENTRY
alIsFilter(ALuint filter
)
118 Context
= GetContextRef();
119 if(!Context
) return AL_FALSE
;
121 LockFilterList(Context
->Device
);
122 result
= ((!filter
|| LookupFilter(Context
->Device
, filter
)) ?
124 UnlockFilterList(Context
->Device
);
126 ALCcontext_DecRef(Context
);
131 AL_API ALvoid AL_APIENTRY
alFilteri(ALuint filter
, ALenum param
, ALint value
)
137 Context
= GetContextRef();
140 Device
= Context
->Device
;
141 LockFilterList(Device
);
142 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
143 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
146 if(param
== AL_FILTER_TYPE
)
148 if(value
== AL_FILTER_NULL
|| value
== AL_FILTER_LOWPASS
||
149 value
== AL_FILTER_HIGHPASS
|| value
== AL_FILTER_BANDPASS
)
150 InitFilterParams(ALFilter
, value
);
152 alSetError(Context
, AL_INVALID_VALUE
, "Invalid filter type 0x%04x", value
);
156 /* Call the appropriate handler */
157 ALfilter_setParami(ALFilter
, Context
, param
, value
);
160 UnlockFilterList(Device
);
162 ALCcontext_DecRef(Context
);
165 AL_API ALvoid AL_APIENTRY
alFilteriv(ALuint filter
, ALenum param
, const ALint
*values
)
174 alFilteri(filter
, param
, values
[0]);
178 Context
= GetContextRef();
181 Device
= Context
->Device
;
182 LockFilterList(Device
);
183 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
184 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
187 /* Call the appropriate handler */
188 ALfilter_setParamiv(ALFilter
, Context
, param
, values
);
190 UnlockFilterList(Device
);
192 ALCcontext_DecRef(Context
);
195 AL_API ALvoid AL_APIENTRY
alFilterf(ALuint filter
, ALenum param
, ALfloat value
)
201 Context
= GetContextRef();
204 Device
= Context
->Device
;
205 LockFilterList(Device
);
206 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
207 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
210 /* Call the appropriate handler */
211 ALfilter_setParamf(ALFilter
, Context
, param
, value
);
213 UnlockFilterList(Device
);
215 ALCcontext_DecRef(Context
);
218 AL_API ALvoid AL_APIENTRY
alFilterfv(ALuint filter
, ALenum param
, const ALfloat
*values
)
224 Context
= GetContextRef();
227 Device
= Context
->Device
;
228 LockFilterList(Device
);
229 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
230 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
233 /* Call the appropriate handler */
234 ALfilter_setParamfv(ALFilter
, Context
, param
, values
);
236 UnlockFilterList(Device
);
238 ALCcontext_DecRef(Context
);
241 AL_API ALvoid AL_APIENTRY
alGetFilteri(ALuint filter
, ALenum param
, ALint
*value
)
247 Context
= GetContextRef();
250 Device
= Context
->Device
;
251 LockFilterList(Device
);
252 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
253 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
256 if(param
== AL_FILTER_TYPE
)
257 *value
= ALFilter
->type
;
260 /* Call the appropriate handler */
261 ALfilter_getParami(ALFilter
, Context
, param
, value
);
264 UnlockFilterList(Device
);
266 ALCcontext_DecRef(Context
);
269 AL_API ALvoid AL_APIENTRY
alGetFilteriv(ALuint filter
, ALenum param
, ALint
*values
)
278 alGetFilteri(filter
, param
, values
);
282 Context
= GetContextRef();
285 Device
= Context
->Device
;
286 LockFilterList(Device
);
287 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
288 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
291 /* Call the appropriate handler */
292 ALfilter_getParamiv(ALFilter
, Context
, param
, values
);
294 UnlockFilterList(Device
);
296 ALCcontext_DecRef(Context
);
299 AL_API ALvoid AL_APIENTRY
alGetFilterf(ALuint filter
, ALenum param
, ALfloat
*value
)
305 Context
= GetContextRef();
308 Device
= Context
->Device
;
309 LockFilterList(Device
);
310 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
311 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
314 /* Call the appropriate handler */
315 ALfilter_getParamf(ALFilter
, Context
, param
, value
);
317 UnlockFilterList(Device
);
319 ALCcontext_DecRef(Context
);
322 AL_API ALvoid AL_APIENTRY
alGetFilterfv(ALuint filter
, ALenum param
, ALfloat
*values
)
328 Context
= GetContextRef();
331 Device
= Context
->Device
;
332 LockFilterList(Device
);
333 if((ALFilter
=LookupFilter(Device
, filter
)) == NULL
)
334 alSetError(Context
, AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
337 /* Call the appropriate handler */
338 ALfilter_getParamfv(ALFilter
, Context
, param
, values
);
340 UnlockFilterList(Device
);
342 ALCcontext_DecRef(Context
);
346 void ALfilterState_setParams(ALfilterState
*filter
, ALfilterType type
, ALfloat gain
, ALfloat f0norm
, ALfloat rcpQ
)
348 ALfloat alpha
, sqrtgain_alpha_2
;
349 ALfloat w0
, sin_w0
, cos_w0
;
350 ALfloat a
[3] = { 1.0f
, 0.0f
, 0.0f
};
351 ALfloat b
[3] = { 1.0f
, 0.0f
, 0.0f
};
353 // Limit gain to -100dB
354 assert(gain
> 0.00001f
);
359 alpha
= sin_w0
/2.0f
* rcpQ
;
361 /* Calculate filter coefficients depending on filter type */
364 case ALfilterType_HighShelf
:
365 sqrtgain_alpha_2
= 2.0f
* sqrtf(gain
) * alpha
;
366 b
[0] = gain
*((gain
+1.0f
) + (gain
-1.0f
)*cos_w0
+ sqrtgain_alpha_2
);
367 b
[1] = -2.0f
*gain
*((gain
-1.0f
) + (gain
+1.0f
)*cos_w0
);
368 b
[2] = gain
*((gain
+1.0f
) + (gain
-1.0f
)*cos_w0
- sqrtgain_alpha_2
);
369 a
[0] = (gain
+1.0f
) - (gain
-1.0f
)*cos_w0
+ sqrtgain_alpha_2
;
370 a
[1] = 2.0f
* ((gain
-1.0f
) - (gain
+1.0f
)*cos_w0
);
371 a
[2] = (gain
+1.0f
) - (gain
-1.0f
)*cos_w0
- sqrtgain_alpha_2
;
373 case ALfilterType_LowShelf
:
374 sqrtgain_alpha_2
= 2.0f
* sqrtf(gain
) * alpha
;
375 b
[0] = gain
*((gain
+1.0f
) - (gain
-1.0f
)*cos_w0
+ sqrtgain_alpha_2
);
376 b
[1] = 2.0f
*gain
*((gain
-1.0f
) - (gain
+1.0f
)*cos_w0
);
377 b
[2] = gain
*((gain
+1.0f
) - (gain
-1.0f
)*cos_w0
- sqrtgain_alpha_2
);
378 a
[0] = (gain
+1.0f
) + (gain
-1.0f
)*cos_w0
+ sqrtgain_alpha_2
;
379 a
[1] = -2.0f
* ((gain
-1.0f
) + (gain
+1.0f
)*cos_w0
);
380 a
[2] = (gain
+1.0f
) + (gain
-1.0f
)*cos_w0
- sqrtgain_alpha_2
;
382 case ALfilterType_Peaking
:
384 b
[0] = 1.0f
+ alpha
* gain
;
385 b
[1] = -2.0f
* cos_w0
;
386 b
[2] = 1.0f
- alpha
* gain
;
387 a
[0] = 1.0f
+ alpha
/ gain
;
388 a
[1] = -2.0f
* cos_w0
;
389 a
[2] = 1.0f
- alpha
/ gain
;
392 case ALfilterType_LowPass
:
393 b
[0] = (1.0f
- cos_w0
) / 2.0f
;
394 b
[1] = 1.0f
- cos_w0
;
395 b
[2] = (1.0f
- cos_w0
) / 2.0f
;
397 a
[1] = -2.0f
* cos_w0
;
400 case ALfilterType_HighPass
:
401 b
[0] = (1.0f
+ cos_w0
) / 2.0f
;
402 b
[1] = -(1.0f
+ cos_w0
);
403 b
[2] = (1.0f
+ cos_w0
) / 2.0f
;
405 a
[1] = -2.0f
* cos_w0
;
408 case ALfilterType_BandPass
:
413 a
[1] = -2.0f
* cos_w0
;
418 filter
->a1
= a
[1] / a
[0];
419 filter
->a2
= a
[2] / a
[0];
420 filter
->b0
= b
[0] / a
[0];
421 filter
->b1
= b
[1] / a
[0];
422 filter
->b2
= b
[2] / a
[0];
426 static void ALlowpass_setParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
UNUSED(val
))
427 { alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass integer property 0x%04x", param
); }
428 static void ALlowpass_setParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, const ALint
*UNUSED(vals
))
429 { alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass integer-vector property 0x%04x", param
); }
430 static void ALlowpass_setParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat val
)
434 case AL_LOWPASS_GAIN
:
435 if(!(val
>= AL_LOWPASS_MIN_GAIN
&& val
<= AL_LOWPASS_MAX_GAIN
))
436 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Low-pass gain %f out of range", val
);
440 case AL_LOWPASS_GAINHF
:
441 if(!(val
>= AL_LOWPASS_MIN_GAINHF
&& val
<= AL_LOWPASS_MAX_GAINHF
))
442 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Low-pass gainhf %f out of range", val
);
443 filter
->GainHF
= val
;
447 alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass float property 0x%04x", param
);
450 static void ALlowpass_setParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
451 { ALlowpass_setParamf(filter
, context
, param
, vals
[0]); }
453 static void ALlowpass_getParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(val
))
454 { alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass integer property 0x%04x", param
); }
455 static void ALlowpass_getParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(vals
))
456 { alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass integer-vector property 0x%04x", param
); }
457 static void ALlowpass_getParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
461 case AL_LOWPASS_GAIN
:
465 case AL_LOWPASS_GAINHF
:
466 *val
= filter
->GainHF
;
470 alSetError(context
, AL_INVALID_ENUM
, "Invalid low-pass float property 0x%04x", param
);
473 static void ALlowpass_getParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
474 { ALlowpass_getParamf(filter
, context
, param
, vals
); }
476 DEFINE_ALFILTER_VTABLE(ALlowpass
);
479 static void ALhighpass_setParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
UNUSED(val
))
480 { alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass integer property 0x%04x", param
); }
481 static void ALhighpass_setParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, const ALint
*UNUSED(vals
))
482 { alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass integer-vector property 0x%04x", param
); }
483 static void ALhighpass_setParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat val
)
487 case AL_HIGHPASS_GAIN
:
488 if(!(val
>= AL_HIGHPASS_MIN_GAIN
&& val
<= AL_HIGHPASS_MAX_GAIN
))
489 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "High-pass gain out of range");
493 case AL_HIGHPASS_GAINLF
:
494 if(!(val
>= AL_HIGHPASS_MIN_GAINLF
&& val
<= AL_HIGHPASS_MAX_GAINLF
))
495 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "High-pass gainlf out of range");
496 filter
->GainLF
= val
;
500 alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass float property 0x%04x", param
);
503 static void ALhighpass_setParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
504 { ALhighpass_setParamf(filter
, context
, param
, vals
[0]); }
506 static void ALhighpass_getParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(val
))
507 { alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass integer property 0x%04x", param
); }
508 static void ALhighpass_getParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(vals
))
509 { alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass integer-vector property 0x%04x", param
); }
510 static void ALhighpass_getParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
514 case AL_HIGHPASS_GAIN
:
518 case AL_HIGHPASS_GAINLF
:
519 *val
= filter
->GainLF
;
523 alSetError(context
, AL_INVALID_ENUM
, "Invalid high-pass float property 0x%04x", param
);
526 static void ALhighpass_getParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
527 { ALhighpass_getParamf(filter
, context
, param
, vals
); }
529 DEFINE_ALFILTER_VTABLE(ALhighpass
);
532 static void ALbandpass_setParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
UNUSED(val
))
533 { alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass integer property 0x%04x", param
); }
534 static void ALbandpass_setParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, const ALint
*UNUSED(vals
))
535 { alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass integer-vector property 0x%04x", param
); }
536 static void ALbandpass_setParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat val
)
540 case AL_BANDPASS_GAIN
:
541 if(!(val
>= AL_BANDPASS_MIN_GAIN
&& val
<= AL_BANDPASS_MAX_GAIN
))
542 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Band-pass gain out of range");
546 case AL_BANDPASS_GAINHF
:
547 if(!(val
>= AL_BANDPASS_MIN_GAINHF
&& val
<= AL_BANDPASS_MAX_GAINHF
))
548 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Band-pass gainhf out of range");
549 filter
->GainHF
= val
;
552 case AL_BANDPASS_GAINLF
:
553 if(!(val
>= AL_BANDPASS_MIN_GAINLF
&& val
<= AL_BANDPASS_MAX_GAINLF
))
554 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Band-pass gainlf out of range");
555 filter
->GainLF
= val
;
559 alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass float property 0x%04x", param
);
562 static void ALbandpass_setParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
563 { ALbandpass_setParamf(filter
, context
, param
, vals
[0]); }
565 static void ALbandpass_getParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(val
))
566 { alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass integer property 0x%04x", param
); }
567 static void ALbandpass_getParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(vals
))
568 { alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass integer-vector property 0x%04x", param
); }
569 static void ALbandpass_getParamf(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
573 case AL_BANDPASS_GAIN
:
577 case AL_BANDPASS_GAINHF
:
578 *val
= filter
->GainHF
;
581 case AL_BANDPASS_GAINLF
:
582 *val
= filter
->GainLF
;
586 alSetError(context
, AL_INVALID_ENUM
, "Invalid band-pass float property 0x%04x", param
);
589 static void ALbandpass_getParamfv(ALfilter
*filter
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
590 { ALbandpass_getParamf(filter
, context
, param
, vals
); }
592 DEFINE_ALFILTER_VTABLE(ALbandpass
);
595 static void ALnullfilter_setParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
UNUSED(val
))
596 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
597 static void ALnullfilter_setParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, const ALint
*UNUSED(vals
))
598 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
599 static void ALnullfilter_setParamf(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALfloat
UNUSED(val
))
600 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
601 static void ALnullfilter_setParamfv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, const ALfloat
*UNUSED(vals
))
602 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
604 static void ALnullfilter_getParami(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(val
))
605 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
606 static void ALnullfilter_getParamiv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALint
*UNUSED(vals
))
607 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
608 static void ALnullfilter_getParamf(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALfloat
*UNUSED(val
))
609 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
610 static void ALnullfilter_getParamfv(ALfilter
*UNUSED(filter
), ALCcontext
*context
, ALenum param
, ALfloat
*UNUSED(vals
))
611 { alSetError(context
, AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
); }
613 DEFINE_ALFILTER_VTABLE(ALnullfilter
);
616 static ALfilter
*AllocFilter(ALCcontext
*context
)
618 ALCdevice
*device
= context
->Device
;
619 FilterSubList
*sublist
, *subend
;
620 ALfilter
*filter
= NULL
;
624 almtx_lock(&device
->FilterLock
);
625 sublist
= VECTOR_BEGIN(device
->FilterList
);
626 subend
= VECTOR_END(device
->FilterList
);
627 for(;sublist
!= subend
;++sublist
)
629 if(sublist
->FreeMask
)
631 slidx
= CTZ64(sublist
->FreeMask
);
632 filter
= sublist
->Filters
+ slidx
;
637 if(UNLIKELY(!filter
))
639 const FilterSubList empty_sublist
= { 0, NULL
};
640 /* Don't allocate so many list entries that the 32-bit ID could
643 if(UNLIKELY(VECTOR_SIZE(device
->FilterList
) >= 1<<25))
645 almtx_unlock(&device
->FilterLock
);
646 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many filters allocated");
649 lidx
= (ALsizei
)VECTOR_SIZE(device
->FilterList
);
650 VECTOR_PUSH_BACK(device
->FilterList
, empty_sublist
);
651 sublist
= &VECTOR_BACK(device
->FilterList
);
652 sublist
->FreeMask
= ~U64(0);
653 sublist
->Filters
= al_calloc(16, sizeof(ALfilter
)*64);
654 if(UNLIKELY(!sublist
->Filters
))
656 VECTOR_POP_BACK(device
->FilterList
);
657 almtx_unlock(&device
->FilterLock
);
658 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate filter batch");
663 filter
= sublist
->Filters
+ slidx
;
666 memset(filter
, 0, sizeof(*filter
));
667 InitFilterParams(filter
, AL_FILTER_NULL
);
669 /* Add 1 to avoid filter ID 0. */
670 filter
->id
= ((lidx
<<6) | slidx
) + 1;
672 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
673 almtx_unlock(&device
->FilterLock
);
678 static void FreeFilter(ALCdevice
*device
, ALfilter
*filter
)
680 ALuint id
= filter
->id
- 1;
681 ALsizei lidx
= id
>> 6;
682 ALsizei slidx
= id
& 0x3f;
684 memset(filter
, 0, sizeof(*filter
));
686 VECTOR_ELEM(device
->FilterList
, lidx
).FreeMask
|= U64(1) << slidx
;
689 void ReleaseALFilters(ALCdevice
*device
)
691 FilterSubList
*sublist
= VECTOR_BEGIN(device
->FilterList
);
692 FilterSubList
*subend
= VECTOR_END(device
->FilterList
);
694 for(;sublist
!= subend
;++sublist
)
696 ALuint64 usemask
= ~sublist
->FreeMask
;
699 ALsizei idx
= CTZ64(usemask
);
700 ALfilter
*filter
= sublist
->Filters
+ idx
;
702 memset(filter
, 0, sizeof(*filter
));
705 usemask
&= ~(U64(1) << idx
);
707 sublist
->FreeMask
= ~usemask
;
710 WARN("(%p) Deleted "SZFMT
" Filter%s\n", device
, leftover
, (leftover
==1)?"":"s");
714 static void InitFilterParams(ALfilter
*filter
, ALenum type
)
716 if(type
== AL_FILTER_LOWPASS
)
718 filter
->Gain
= AL_LOWPASS_DEFAULT_GAIN
;
719 filter
->GainHF
= AL_LOWPASS_DEFAULT_GAINHF
;
720 filter
->HFReference
= LOWPASSFREQREF
;
721 filter
->GainLF
= 1.0f
;
722 filter
->LFReference
= HIGHPASSFREQREF
;
723 filter
->vtab
= &ALlowpass_vtable
;
725 else if(type
== AL_FILTER_HIGHPASS
)
727 filter
->Gain
= AL_HIGHPASS_DEFAULT_GAIN
;
728 filter
->GainHF
= 1.0f
;
729 filter
->HFReference
= LOWPASSFREQREF
;
730 filter
->GainLF
= AL_HIGHPASS_DEFAULT_GAINLF
;
731 filter
->LFReference
= HIGHPASSFREQREF
;
732 filter
->vtab
= &ALhighpass_vtable
;
734 else if(type
== AL_FILTER_BANDPASS
)
736 filter
->Gain
= AL_BANDPASS_DEFAULT_GAIN
;
737 filter
->GainHF
= AL_BANDPASS_DEFAULT_GAINHF
;
738 filter
->HFReference
= LOWPASSFREQREF
;
739 filter
->GainLF
= AL_BANDPASS_DEFAULT_GAINLF
;
740 filter
->LFReference
= HIGHPASSFREQREF
;
741 filter
->vtab
= &ALbandpass_vtable
;
746 filter
->GainHF
= 1.0f
;
747 filter
->HFReference
= LOWPASSFREQREF
;
748 filter
->GainLF
= 1.0f
;
749 filter
->LFReference
= HIGHPASSFREQREF
;
750 filter
->vtab
= &ALnullfilter_vtable
;