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
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
)))
52 sublist
= &VECTOR_ELEM(device
->FilterList
, lidx
);
53 if(UNLIKELY(sublist
->FreeMask
& (U64(1)<<slidx
)))
55 return sublist
->Filters
+ slidx
;
59 AL_API ALvoid AL_APIENTRY
alGenFilters(ALsizei n
, ALuint
*filters
)
64 context
= GetContextRef();
68 alSetError(context
, AL_INVALID_VALUE
, "Generating %d filters", n
);
69 else for(cur
= 0;cur
< n
;cur
++)
71 ALfilter
*filter
= AllocFilter(context
);
74 alDeleteFilters(cur
, filters
);
78 filters
[cur
] = filter
->id
;
81 ALCcontext_DecRef(context
);
84 AL_API ALvoid AL_APIENTRY
alDeleteFilters(ALsizei n
, const ALuint
*filters
)
91 context
= GetContextRef();
94 device
= context
->Device
;
95 LockFilterList(device
);
97 SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Deleting %d filters", n
);
100 if(filters
[i
] && LookupFilter(device
, filters
[i
]) == NULL
)
101 SETERR_GOTO(context
, AL_INVALID_NAME
, done
, "Invalid filter ID %u", filters
[i
]);
105 if((filter
=LookupFilter(device
, filters
[i
])) != NULL
)
106 FreeFilter(device
, filter
);
110 UnlockFilterList(device
);
111 ALCcontext_DecRef(context
);
114 AL_API ALboolean AL_APIENTRY
alIsFilter(ALuint filter
)
119 Context
= GetContextRef();
120 if(!Context
) return AL_FALSE
;
122 LockFilterList(Context
->Device
);
123 result
= ((!filter
|| LookupFilter(Context
->Device
, filter
)) ?
125 UnlockFilterList(Context
->Device
);
127 ALCcontext_DecRef(Context
);
132 AL_API ALvoid AL_APIENTRY
alFilteri(ALuint filter
, ALenum param
, ALint value
)
138 Context
= GetContextRef();
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
);
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
);
153 alSetError(Context
, AL_INVALID_VALUE
, "Invalid filter type 0x%04x", value
);
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
)
175 alFilteri(filter
, param
, values
[0]);
179 Context
= GetContextRef();
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
);
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
)
202 Context
= GetContextRef();
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
);
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
)
225 Context
= GetContextRef();
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
);
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
)
248 Context
= GetContextRef();
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
);
257 if(param
== AL_FILTER_TYPE
)
258 *value
= ALFilter
->type
;
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
)
279 alGetFilteri(filter
, param
, values
);
283 Context
= GetContextRef();
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
);
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
)
306 Context
= GetContextRef();
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
);
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
)
329 Context
= GetContextRef();
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
);
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
);
360 alpha
= sin_w0
/2.0f
* rcpQ
;
362 /* Calculate filter coefficients depending on filter 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
;
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
;
383 case ALfilterType_Peaking
:
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
;
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
;
398 a
[1] = -2.0f
* cos_w0
;
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
;
406 a
[1] = -2.0f
* cos_w0
;
409 case ALfilterType_BandPass
:
414 a
[1] = -2.0f
* cos_w0
;
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
)
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
);
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
;
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
)
462 case AL_LOWPASS_GAIN
:
466 case AL_LOWPASS_GAINHF
:
467 *val
= filter
->GainHF
;
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
)
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");
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
;
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
)
515 case AL_HIGHPASS_GAIN
:
519 case AL_HIGHPASS_GAINLF
:
520 *val
= filter
->GainLF
;
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
)
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");
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
;
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
;
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
)
574 case AL_BANDPASS_GAIN
:
578 case AL_BANDPASS_GAINHF
:
579 *val
= filter
->GainHF
;
582 case AL_BANDPASS_GAINLF
:
583 *val
= filter
->GainLF
;
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
;
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
;
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
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");
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");
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
);
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
);
695 for(;sublist
!= subend
;++sublist
)
697 ALuint64 usemask
= ~sublist
->FreeMask
;
700 ALsizei idx
= CTZ64(usemask
);
701 ALfilter
*filter
= sublist
->Filters
+ idx
;
703 memset(filter
, 0, sizeof(*filter
));
706 usemask
&= ~(U64(1) << idx
);
708 sublist
->FreeMask
= ~usemask
;
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
;
747 filter
->GainHF
= 1.0f
;
748 filter
->HFReference
= LOWPASSFREQREF
;
749 filter
->GainLF
= 1.0f
;
750 filter
->LFReference
= HIGHPASSFREQREF
;
751 filter
->vtbl
= &ALnullfilter_vtable
;