Add missing include
[openal-soft.git] / OpenAL32 / alFilter.cpp
blob5213556937851b9142d36ad609b7adda8811bf47
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 std::lock_guard<std::mutex> _{device->FilterLock};
274 auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
275 [](const FilterSubList &entry) noexcept -> bool
276 { return entry.FreeMask != 0; }
279 auto lidx = std::distance(device->FilterList.begin(), sublist);
280 ALfilter *filter{nullptr};
281 ALsizei slidx{0};
282 if(LIKELY(sublist != device->FilterList.end()))
284 slidx = CTZ64(sublist->FreeMask);
285 filter = sublist->Filters + slidx;
287 else
289 /* Don't allocate so many list entries that the 32-bit ID could
290 * overflow...
292 if(UNLIKELY(device->FilterList.size() >= 1<<25))
294 alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated");
295 return NULL;
297 device->FilterList.emplace_back();
298 sublist = device->FilterList.end() - 1;
299 sublist->FreeMask = ~U64(0);
300 sublist->Filters = static_cast<ALfilter*>(al_calloc(16, sizeof(ALfilter)*64));
301 if(UNLIKELY(!sublist->Filters))
303 device->FilterList.pop_back();
304 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch");
305 return NULL;
308 slidx = 0;
309 filter = sublist->Filters + slidx;
312 filter = new (filter) ALfilter{};
313 InitFilterParams(filter, AL_FILTER_NULL);
315 /* Add 1 to avoid filter ID 0. */
316 filter->id = ((lidx<<6) | slidx) + 1;
318 sublist->FreeMask &= ~(U64(1)<<slidx);
320 return filter;
323 void FreeFilter(ALCdevice *device, ALfilter *filter)
325 ALuint id = filter->id - 1;
326 ALsizei lidx = id >> 6;
327 ALsizei slidx = id & 0x3f;
329 filter->~ALfilter();
331 device->FilterList[lidx].FreeMask |= U64(1) << slidx;
335 inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
337 ALuint lidx = (id-1) >> 6;
338 ALsizei slidx = (id-1) & 0x3f;
340 if(UNLIKELY(lidx >= device->FilterList.size()))
341 return nullptr;
342 FilterSubList &sublist = device->FilterList[lidx];
343 if(UNLIKELY(sublist.FreeMask & (U64(1)<<slidx)))
344 return nullptr;
345 return sublist.Filters + slidx;
348 } // namespace
350 AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
352 ContextRef context{GetContextRef()};
353 if(UNLIKELY(!context)) return;
355 if(UNLIKELY(n < 0))
357 alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n);
358 return;
361 if(LIKELY(n == 1))
363 /* Special handling for the easy and normal case. */
364 ALfilter *filter = AllocFilter(context.get());
365 if(filter) filters[0] = filter->id;
367 else if(n > 1)
369 /* Store the allocated buffer IDs in a separate local list, to avoid
370 * modifying the user storage in case of failure.
372 al::vector<ALuint> ids;
373 ids.reserve(n);
374 do {
375 ALfilter *filter = AllocFilter(context.get());
376 if(!filter)
378 alDeleteFilters(ids.size(), ids.data());
379 return;
382 ids.emplace_back(filter->id);
383 } while(--n);
384 std::copy(ids.begin(), ids.end(), filters);
388 AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
390 ContextRef context{GetContextRef()};
391 if(UNLIKELY(!context)) return;
393 if(UNLIKELY(n < 0))
395 alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n);
396 return;
398 if(UNLIKELY(n == 0))
399 return;
401 ALCdevice *device{context->Device};
402 std::lock_guard<std::mutex> _{device->FilterLock};
404 /* First try to find any filters that are invalid. */
405 const ALuint *filters_end = filters + n;
406 auto invflt = std::find_if(filters, filters_end,
407 [device, &context](ALuint fid) -> bool
409 if(!fid) return false;
410 ALfilter *filter{LookupFilter(device, fid)};
411 if(UNLIKELY(!filter))
413 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid);
414 return true;
416 return false;
419 if(LIKELY(invflt == filters_end))
421 /* All good. Delete non-0 filter IDs. */
422 std::for_each(filters, filters_end,
423 [device](ALuint fid) -> void
425 ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr};
426 if(filter) FreeFilter(device, filter);
432 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
434 ContextRef context{GetContextRef()};
435 if(LIKELY(context))
437 ALCdevice *device{context->Device};
438 std::lock_guard<std::mutex> _{device->FilterLock};
439 if(!filter || LookupFilter(device, filter))
440 return AL_TRUE;
442 return AL_FALSE;
446 AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
448 ContextRef context{GetContextRef()};
449 if(UNLIKELY(!context)) return;
451 ALCdevice *device{context->Device};
452 std::lock_guard<std::mutex> _{device->FilterLock};
454 ALfilter *alfilt{LookupFilter(device, filter)};
455 if(UNLIKELY(!alfilt))
456 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
457 else
459 if(param == AL_FILTER_TYPE)
461 if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS ||
462 value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
463 InitFilterParams(alfilt, value);
464 else
465 alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
467 else
469 /* Call the appropriate handler */
470 ALfilter_setParami(alfilt, context.get(), param, value);
475 AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
477 switch(param)
479 case AL_FILTER_TYPE:
480 alFilteri(filter, param, values[0]);
481 return;
484 ContextRef context{GetContextRef()};
485 if(UNLIKELY(!context)) return;
487 ALCdevice *device{context->Device};
488 std::lock_guard<std::mutex> _{device->FilterLock};
490 ALfilter *alfilt{LookupFilter(device, filter)};
491 if(UNLIKELY(!alfilt))
492 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
493 else
495 /* Call the appropriate handler */
496 ALfilter_setParamiv(alfilt, context.get(), param, values);
500 AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
502 ContextRef context{GetContextRef()};
503 if(UNLIKELY(!context)) return;
505 ALCdevice *device{context->Device};
506 std::lock_guard<std::mutex> _{device->FilterLock};
508 ALfilter *alfilt{LookupFilter(device, filter)};
509 if(UNLIKELY(!alfilt))
510 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
511 else
513 /* Call the appropriate handler */
514 ALfilter_setParamf(alfilt, context.get(), param, value);
518 AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
520 ContextRef context{GetContextRef()};
521 if(UNLIKELY(!context)) return;
523 ALCdevice *device{context->Device};
524 std::lock_guard<std::mutex> _{device->FilterLock};
526 ALfilter *alfilt{LookupFilter(device, filter)};
527 if(UNLIKELY(!alfilt))
528 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
529 else
531 /* Call the appropriate handler */
532 ALfilter_setParamfv(alfilt, context.get(), param, values);
536 AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
538 ContextRef context{GetContextRef()};
539 if(UNLIKELY(!context)) return;
541 ALCdevice *device{context->Device};
542 std::lock_guard<std::mutex> _{device->FilterLock};
544 ALfilter *alfilt{LookupFilter(device, filter)};
545 if(UNLIKELY(!alfilt))
546 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
547 else
549 if(param == AL_FILTER_TYPE)
550 *value = alfilt->type;
551 else
553 /* Call the appropriate handler */
554 ALfilter_getParami(alfilt, context.get(), param, value);
559 AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
561 switch(param)
563 case AL_FILTER_TYPE:
564 alGetFilteri(filter, param, values);
565 return;
568 ContextRef context{GetContextRef()};
569 if(UNLIKELY(!context)) return;
571 ALCdevice *device{context->Device};
572 std::lock_guard<std::mutex> _{device->FilterLock};
574 ALfilter *alfilt{LookupFilter(device, filter)};
575 if(UNLIKELY(!alfilt))
576 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
577 else
579 /* Call the appropriate handler */
580 ALfilter_getParamiv(alfilt, context.get(), param, values);
584 AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
586 ContextRef context{GetContextRef()};
587 if(UNLIKELY(!context)) return;
589 ALCdevice *device{context->Device};
590 std::lock_guard<std::mutex> _{device->FilterLock};
592 ALfilter *alfilt{LookupFilter(device, filter)};
593 if(UNLIKELY(!alfilt))
594 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
595 else
597 /* Call the appropriate handler */
598 ALfilter_getParamf(alfilt, context.get(), param, value);
602 AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
604 ContextRef context{GetContextRef()};
605 if(UNLIKELY(!context)) return;
607 ALCdevice *device{context->Device};
608 std::lock_guard<std::mutex> _{device->FilterLock};
610 ALfilter *alfilt{LookupFilter(device, filter)};
611 if(UNLIKELY(!alfilt))
612 alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter);
613 else
615 /* Call the appropriate handler */
616 ALfilter_getParamfv(alfilt, context.get(), param, values);
621 FilterSubList::~FilterSubList()
623 ALuint64 usemask = ~FreeMask;
624 while(usemask)
626 ALsizei idx = CTZ64(usemask);
627 Filters[idx].~ALfilter();
628 usemask &= ~(U64(1) << idx);
630 FreeMask = ~usemask;
631 al_free(Filters);
632 Filters = nullptr;