Automatically clean up buffers with ther sublist
[openal-soft.git] / OpenAL32 / alFilter.cpp
blob5b15e7e02f107be5430d3af6975aa05162c1f386
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 <algorithm>
27 #include "alMain.h"
28 #include "alcontext.h"
29 #include "alu.h"
30 #include "alFilter.h"
31 #include "alError.h"
34 namespace {
36 #define FILTER_MIN_GAIN 0.0f
37 #define FILTER_MAX_GAIN 4.0f /* +12dB */
39 void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
40 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
41 void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
42 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
43 void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
45 switch(param)
47 case AL_LOWPASS_GAIN:
48 if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
49 SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val);
50 filter->Gain = val;
51 break;
53 case AL_LOWPASS_GAINHF:
54 if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
55 SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val);
56 filter->GainHF = val;
57 break;
59 default:
60 alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
63 void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
64 { ALlowpass_setParamf(filter, context, param, vals[0]); }
66 void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
67 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
68 void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
69 { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
70 void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
72 switch(param)
74 case AL_LOWPASS_GAIN:
75 *val = filter->Gain;
76 break;
78 case AL_LOWPASS_GAINHF:
79 *val = filter->GainHF;
80 break;
82 default:
83 alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
86 void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
87 { ALlowpass_getParamf(filter, context, param, vals); }
89 DEFINE_ALFILTER_VTABLE(ALlowpass);
92 void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
93 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
94 void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
95 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
96 void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
98 switch(param)
100 case AL_HIGHPASS_GAIN:
101 if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
102 SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range");
103 filter->Gain = val;
104 break;
106 case AL_HIGHPASS_GAINLF:
107 if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
108 SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range");
109 filter->GainLF = val;
110 break;
112 default:
113 alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
116 void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
117 { ALhighpass_setParamf(filter, context, param, vals[0]); }
119 void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
120 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
121 void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
122 { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
123 void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
125 switch(param)
127 case AL_HIGHPASS_GAIN:
128 *val = filter->Gain;
129 break;
131 case AL_HIGHPASS_GAINLF:
132 *val = filter->GainLF;
133 break;
135 default:
136 alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
139 void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
140 { ALhighpass_getParamf(filter, context, param, vals); }
142 DEFINE_ALFILTER_VTABLE(ALhighpass);
145 void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
146 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
147 void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
148 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
149 void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
151 switch(param)
153 case AL_BANDPASS_GAIN:
154 if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
155 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range");
156 filter->Gain = val;
157 break;
159 case AL_BANDPASS_GAINHF:
160 if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
161 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range");
162 filter->GainHF = val;
163 break;
165 case AL_BANDPASS_GAINLF:
166 if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
167 SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range");
168 filter->GainLF = val;
169 break;
171 default:
172 alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
175 void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
176 { ALbandpass_setParamf(filter, context, param, vals[0]); }
178 void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
179 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
180 void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
181 { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
182 void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
184 switch(param)
186 case AL_BANDPASS_GAIN:
187 *val = filter->Gain;
188 break;
190 case AL_BANDPASS_GAINHF:
191 *val = filter->GainHF;
192 break;
194 case AL_BANDPASS_GAINLF:
195 *val = filter->GainLF;
196 break;
198 default:
199 alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
202 void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
203 { ALbandpass_getParamf(filter, context, param, vals); }
205 DEFINE_ALFILTER_VTABLE(ALbandpass);
208 void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val))
209 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
210 void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
211 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
212 void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
213 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
214 void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals))
215 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
217 void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val))
218 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
219 void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
220 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
221 void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val))
222 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
223 void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals))
224 { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
226 DEFINE_ALFILTER_VTABLE(ALnullfilter);
229 void InitFilterParams(ALfilter *filter, ALenum type)
231 if(type == AL_FILTER_LOWPASS)
233 filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
234 filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
235 filter->HFReference = LOWPASSFREQREF;
236 filter->GainLF = 1.0f;
237 filter->LFReference = HIGHPASSFREQREF;
238 filter->vtab = &ALlowpass_vtable;
240 else if(type == AL_FILTER_HIGHPASS)
242 filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
243 filter->GainHF = 1.0f;
244 filter->HFReference = LOWPASSFREQREF;
245 filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
246 filter->LFReference = HIGHPASSFREQREF;
247 filter->vtab = &ALhighpass_vtable;
249 else if(type == AL_FILTER_BANDPASS)
251 filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
252 filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
253 filter->HFReference = LOWPASSFREQREF;
254 filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
255 filter->LFReference = HIGHPASSFREQREF;
256 filter->vtab = &ALbandpass_vtable;
258 else
260 filter->Gain = 1.0f;
261 filter->GainHF = 1.0f;
262 filter->HFReference = LOWPASSFREQREF;
263 filter->GainLF = 1.0f;
264 filter->LFReference = HIGHPASSFREQREF;
265 filter->vtab = &ALnullfilter_vtable;
267 filter->type = type;
270 ALfilter *AllocFilter(ALCcontext *context)
272 ALCdevice *device = context->Device;
273 almtx_lock(&device->FilterLock);
275 auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
276 [](const FilterSubList &entry) noexcept -> bool
277 { return entry.FreeMask != 0; }
280 auto lidx = std::distance(device->FilterList.begin(), sublist);
281 ALfilter *filter{nullptr};
282 ALsizei slidx{0};
283 if(LIKELY(sublist != device->FilterList.end()))
285 slidx = CTZ64(sublist->FreeMask);
286 filter = sublist->Filters + slidx;
288 else
290 /* Don't allocate so many list entries that the 32-bit ID could
291 * overflow...
293 if(UNLIKELY(device->FilterList.size() >= 1<<25))
295 almtx_unlock(&device->FilterLock);
296 alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated");
297 return NULL;
299 device->FilterList.emplace_back();
300 sublist = device->FilterList.end() - 1;
301 sublist->FreeMask = ~U64(0);
302 sublist->Filters = static_cast<ALfilter*>(al_calloc(16, sizeof(ALfilter)*64));
303 if(UNLIKELY(!sublist->Filters))
305 device->FilterList.pop_back();
306 almtx_unlock(&device->FilterLock);
307 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch");
308 return NULL;
311 slidx = 0;
312 filter = sublist->Filters + slidx;
315 filter = new (filter) ALfilter{};
316 InitFilterParams(filter, AL_FILTER_NULL);
318 /* Add 1 to avoid filter ID 0. */
319 filter->id = ((lidx<<6) | slidx) + 1;
321 sublist->FreeMask &= ~(U64(1)<<slidx);
322 almtx_unlock(&device->FilterLock);
324 return filter;
327 void FreeFilter(ALCdevice *device, ALfilter *filter)
329 ALuint id = filter->id - 1;
330 ALsizei lidx = id >> 6;
331 ALsizei slidx = id & 0x3f;
333 filter->~ALfilter();
335 device->FilterList[lidx].FreeMask |= U64(1) << slidx;
339 inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
341 ALuint lidx = (id-1) >> 6;
342 ALsizei slidx = (id-1) & 0x3f;
344 if(UNLIKELY(lidx >= device->FilterList.size()))
345 return nullptr;
346 FilterSubList &sublist = device->FilterList[lidx];
347 if(UNLIKELY(sublist.FreeMask & (U64(1)<<slidx)))
348 return nullptr;
349 return sublist.Filters + slidx;
352 } // namespace
354 AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
356 ContextRef context{GetContextRef()};
357 if(UNLIKELY(!context)) return;
359 if(UNLIKELY(n < 0))
361 alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n);
362 return;
365 if(LIKELY(n == 1))
367 /* Special handling for the easy and normal case. */
368 ALfilter *filter = AllocFilter(context.get());
369 if(filter) filters[0] = filter->id;
371 else if(n > 1)
373 /* Store the allocated buffer IDs in a separate local list, to avoid
374 * modifying the user storage in case of failure.
376 al::vector<ALuint> ids;
377 ids.reserve(n);
378 do {
379 ALfilter *filter = AllocFilter(context.get());
380 if(!filter)
382 alDeleteFilters(ids.size(), ids.data());
383 return;
386 ids.emplace_back(filter->id);
387 } while(--n);
388 std::copy(ids.begin(), ids.end(), filters);
392 AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
394 ContextRef context{GetContextRef()};
395 if(UNLIKELY(!context)) return;
397 if(UNLIKELY(n < 0))
399 alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n);
400 return;
402 if(UNLIKELY(n == 0))
403 return;
405 ALCdevice *device{context->Device};
406 std::lock_guard<almtx_t> _{device->FilterLock};
408 /* First try to find any filters that are invalid. */
409 const ALuint *filters_end = filters + n;
410 auto invflt = std::find_if(filters, filters_end,
411 [device, &context](ALuint fid) -> bool
413 if(!fid) return false;
414 ALfilter *filter{LookupFilter(device, fid)};
415 if(UNLIKELY(!filter))
417 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid);
418 return true;
420 return false;
423 if(LIKELY(invflt == filters_end))
425 /* All good. Delete non-0 filter IDs. */
426 std::for_each(filters, filters_end,
427 [device](ALuint fid) -> void
429 ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr};
430 if(filter) FreeFilter(device, filter);
436 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
438 ContextRef context{GetContextRef()};
439 if(LIKELY(context))
441 ALCdevice *device{context->Device};
442 std::lock_guard<almtx_t> _{device->FilterLock};
443 if(!filter || LookupFilter(device, filter))
444 return AL_TRUE;
446 return AL_FALSE;
450 AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
452 ContextRef context{GetContextRef()};
453 if(UNLIKELY(!context)) return;
455 ALCdevice *device{context->Device};
456 std::lock_guard<almtx_t> _{device->FilterLock};
458 ALfilter *alfilt{LookupFilter(device, filter)};
459 if(UNLIKELY(!alfilt))
460 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
461 else
463 if(param == AL_FILTER_TYPE)
465 if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS ||
466 value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
467 InitFilterParams(alfilt, value);
468 else
469 alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
471 else
473 /* Call the appropriate handler */
474 ALfilter_setParami(alfilt, context.get(), param, value);
479 AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
481 switch(param)
483 case AL_FILTER_TYPE:
484 alFilteri(filter, param, values[0]);
485 return;
488 ContextRef context{GetContextRef()};
489 if(UNLIKELY(!context)) return;
491 ALCdevice *device{context->Device};
492 std::lock_guard<almtx_t> _{device->FilterLock};
494 ALfilter *alfilt{LookupFilter(device, filter)};
495 if(UNLIKELY(!alfilt))
496 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
497 else
499 /* Call the appropriate handler */
500 ALfilter_setParamiv(alfilt, context.get(), param, values);
504 AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
506 ContextRef context{GetContextRef()};
507 if(UNLIKELY(!context)) return;
509 ALCdevice *device{context->Device};
510 std::lock_guard<almtx_t> _{device->FilterLock};
512 ALfilter *alfilt{LookupFilter(device, filter)};
513 if(UNLIKELY(!alfilt))
514 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
515 else
517 /* Call the appropriate handler */
518 ALfilter_setParamf(alfilt, context.get(), param, value);
522 AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
524 ContextRef context{GetContextRef()};
525 if(UNLIKELY(!context)) return;
527 ALCdevice *device{context->Device};
528 std::lock_guard<almtx_t> _{device->FilterLock};
530 ALfilter *alfilt{LookupFilter(device, filter)};
531 if(UNLIKELY(!alfilt))
532 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
533 else
535 /* Call the appropriate handler */
536 ALfilter_setParamfv(alfilt, context.get(), param, values);
540 AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
542 ContextRef context{GetContextRef()};
543 if(UNLIKELY(!context)) return;
545 ALCdevice *device{context->Device};
546 std::lock_guard<almtx_t> _{device->FilterLock};
548 ALfilter *alfilt{LookupFilter(device, filter)};
549 if(UNLIKELY(!alfilt))
550 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
551 else
553 if(param == AL_FILTER_TYPE)
554 *value = alfilt->type;
555 else
557 /* Call the appropriate handler */
558 ALfilter_getParami(alfilt, context.get(), param, value);
563 AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
565 switch(param)
567 case AL_FILTER_TYPE:
568 alGetFilteri(filter, param, values);
569 return;
572 ContextRef context{GetContextRef()};
573 if(UNLIKELY(!context)) return;
575 ALCdevice *device{context->Device};
576 std::lock_guard<almtx_t> _{device->FilterLock};
578 ALfilter *alfilt{LookupFilter(device, filter)};
579 if(UNLIKELY(!alfilt))
580 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
581 else
583 /* Call the appropriate handler */
584 ALfilter_getParamiv(alfilt, context.get(), param, values);
588 AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
590 ContextRef context{GetContextRef()};
591 if(UNLIKELY(!context)) return;
593 ALCdevice *device{context->Device};
594 std::lock_guard<almtx_t> _{device->FilterLock};
596 ALfilter *alfilt{LookupFilter(device, filter)};
597 if(UNLIKELY(!alfilt))
598 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
599 else
601 /* Call the appropriate handler */
602 ALfilter_getParamf(alfilt, context.get(), param, value);
606 AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
608 ContextRef context{GetContextRef()};
609 if(UNLIKELY(!context)) return;
611 ALCdevice *device{context->Device};
612 std::lock_guard<almtx_t> _{device->FilterLock};
614 ALfilter *alfilt{LookupFilter(device, filter)};
615 if(UNLIKELY(!alfilt))
616 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
617 else
619 /* Call the appropriate handler */
620 ALfilter_getParamfv(alfilt, context.get(), param, values);
625 void ReleaseALFilters(ALCdevice *device)
627 size_t leftover = 0;
628 for(auto &sublist : device->FilterList)
630 ALuint64 usemask = ~sublist.FreeMask;
631 while(usemask)
633 ALsizei idx = CTZ64(usemask);
634 ALfilter *filter = sublist.Filters + idx;
636 filter->~ALfilter();
637 ++leftover;
639 usemask &= ~(U64(1) << idx);
641 sublist.FreeMask = ~usemask;
643 if(leftover > 0)
644 WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s");