Inline a couple dispatch calls
[openal-soft.git] / al / filter.cpp
blobf4b0ac9de008dc7bb555fcbc0772a51a09f2a086
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 "filter.h"
25 #include <algorithm>
26 #include <cstdarg>
27 #include <cstdint>
28 #include <cstdio>
29 #include <iterator>
30 #include <memory>
31 #include <mutex>
32 #include <new>
33 #include <numeric>
35 #include "AL/al.h"
36 #include "AL/alc.h"
37 #include "AL/efx.h"
39 #include "albit.h"
40 #include "alc/context.h"
41 #include "alc/device.h"
42 #include "almalloc.h"
43 #include "alnumeric.h"
44 #include "core/except.h"
45 #include "opthelpers.h"
46 #include "vector.h"
49 namespace {
51 class filter_exception final : public al::base_exception {
52 ALenum mErrorCode;
54 public:
55 #ifdef __USE_MINGW_ANSI_STDIO
56 [[gnu::format(gnu_printf, 3, 4)]]
57 #else
58 [[gnu::format(printf, 3, 4)]]
59 #endif
60 filter_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
62 std::va_list args;
63 va_start(args, msg);
64 setMessage(msg, args);
65 va_end(args);
67 ALenum errorCode() const noexcept { return mErrorCode; }
71 #define DEFINE_ALFILTER_VTABLE(T) \
72 const ALfilter::Vtable T##_vtable = { \
73 T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \
74 T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \
77 void ALlowpass_setParami(ALfilter*, ALenum param, int)
78 { throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
79 void ALlowpass_setParamiv(ALfilter*, ALenum param, const int*)
81 throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
82 param};
84 void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val)
86 switch(param)
88 case AL_LOWPASS_GAIN:
89 if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
90 throw filter_exception{AL_INVALID_VALUE, "Low-pass gain %f out of range", val};
91 filter->Gain = val;
92 break;
94 case AL_LOWPASS_GAINHF:
95 if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
96 throw filter_exception{AL_INVALID_VALUE, "Low-pass gainhf %f out of range", val};
97 filter->GainHF = val;
98 break;
100 default:
101 throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
104 void ALlowpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
105 { ALlowpass_setParamf(filter, param, vals[0]); }
107 void ALlowpass_getParami(const ALfilter*, ALenum param, int*)
108 { throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
109 void ALlowpass_getParamiv(const ALfilter*, ALenum param, int*)
111 throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
112 param};
114 void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val)
116 switch(param)
118 case AL_LOWPASS_GAIN:
119 *val = filter->Gain;
120 break;
122 case AL_LOWPASS_GAINHF:
123 *val = filter->GainHF;
124 break;
126 default:
127 throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
130 void ALlowpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
131 { ALlowpass_getParamf(filter, param, vals); }
133 DEFINE_ALFILTER_VTABLE(ALlowpass);
136 void ALhighpass_setParami(ALfilter*, ALenum param, int)
137 { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
138 void ALhighpass_setParamiv(ALfilter*, ALenum param, const int*)
140 throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
141 param};
143 void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val)
145 switch(param)
147 case AL_HIGHPASS_GAIN:
148 if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
149 throw filter_exception{AL_INVALID_VALUE, "High-pass gain %f out of range", val};
150 filter->Gain = val;
151 break;
153 case AL_HIGHPASS_GAINLF:
154 if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
155 throw filter_exception{AL_INVALID_VALUE, "High-pass gainlf %f out of range", val};
156 filter->GainLF = val;
157 break;
159 default:
160 throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
163 void ALhighpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
164 { ALhighpass_setParamf(filter, param, vals[0]); }
166 void ALhighpass_getParami(const ALfilter*, ALenum param, int*)
167 { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
168 void ALhighpass_getParamiv(const ALfilter*, ALenum param, int*)
170 throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
171 param};
173 void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val)
175 switch(param)
177 case AL_HIGHPASS_GAIN:
178 *val = filter->Gain;
179 break;
181 case AL_HIGHPASS_GAINLF:
182 *val = filter->GainLF;
183 break;
185 default:
186 throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
189 void ALhighpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
190 { ALhighpass_getParamf(filter, param, vals); }
192 DEFINE_ALFILTER_VTABLE(ALhighpass);
195 void ALbandpass_setParami(ALfilter*, ALenum param, int)
196 { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
197 void ALbandpass_setParamiv(ALfilter*, ALenum param, const int*)
199 throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
200 param};
202 void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val)
204 switch(param)
206 case AL_BANDPASS_GAIN:
207 if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
208 throw filter_exception{AL_INVALID_VALUE, "Band-pass gain %f out of range", val};
209 filter->Gain = val;
210 break;
212 case AL_BANDPASS_GAINHF:
213 if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
214 throw filter_exception{AL_INVALID_VALUE, "Band-pass gainhf %f out of range", val};
215 filter->GainHF = val;
216 break;
218 case AL_BANDPASS_GAINLF:
219 if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
220 throw filter_exception{AL_INVALID_VALUE, "Band-pass gainlf %f out of range", val};
221 filter->GainLF = val;
222 break;
224 default:
225 throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
228 void ALbandpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
229 { ALbandpass_setParamf(filter, param, vals[0]); }
231 void ALbandpass_getParami(const ALfilter*, ALenum param, int*)
232 { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
233 void ALbandpass_getParamiv(const ALfilter*, ALenum param, int*)
235 throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
236 param};
238 void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val)
240 switch(param)
242 case AL_BANDPASS_GAIN:
243 *val = filter->Gain;
244 break;
246 case AL_BANDPASS_GAINHF:
247 *val = filter->GainHF;
248 break;
250 case AL_BANDPASS_GAINLF:
251 *val = filter->GainLF;
252 break;
254 default:
255 throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
258 void ALbandpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
259 { ALbandpass_getParamf(filter, param, vals); }
261 DEFINE_ALFILTER_VTABLE(ALbandpass);
264 void ALnullfilter_setParami(ALfilter*, ALenum param, int)
265 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
266 void ALnullfilter_setParamiv(ALfilter*, ALenum param, const int*)
267 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
268 void ALnullfilter_setParamf(ALfilter*, ALenum param, float)
269 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
270 void ALnullfilter_setParamfv(ALfilter*, ALenum param, const float*)
271 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
273 void ALnullfilter_getParami(const ALfilter*, ALenum param, int*)
274 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
275 void ALnullfilter_getParamiv(const ALfilter*, ALenum param, int*)
276 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
277 void ALnullfilter_getParamf(const ALfilter*, ALenum param, float*)
278 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
279 void ALnullfilter_getParamfv(const ALfilter*, ALenum param, float*)
280 { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
282 DEFINE_ALFILTER_VTABLE(ALnullfilter);
285 void InitFilterParams(ALfilter *filter, ALenum type)
287 if(type == AL_FILTER_LOWPASS)
289 filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
290 filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
291 filter->HFReference = LOWPASSFREQREF;
292 filter->GainLF = 1.0f;
293 filter->LFReference = HIGHPASSFREQREF;
294 filter->vtab = &ALlowpass_vtable;
296 else if(type == AL_FILTER_HIGHPASS)
298 filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
299 filter->GainHF = 1.0f;
300 filter->HFReference = LOWPASSFREQREF;
301 filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
302 filter->LFReference = HIGHPASSFREQREF;
303 filter->vtab = &ALhighpass_vtable;
305 else if(type == AL_FILTER_BANDPASS)
307 filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
308 filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
309 filter->HFReference = LOWPASSFREQREF;
310 filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
311 filter->LFReference = HIGHPASSFREQREF;
312 filter->vtab = &ALbandpass_vtable;
314 else
316 filter->Gain = 1.0f;
317 filter->GainHF = 1.0f;
318 filter->HFReference = LOWPASSFREQREF;
319 filter->GainLF = 1.0f;
320 filter->LFReference = HIGHPASSFREQREF;
321 filter->vtab = &ALnullfilter_vtable;
323 filter->type = type;
326 bool EnsureFilters(ALCdevice *device, size_t needed)
328 size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0},
329 [](size_t cur, const FilterSubList &sublist) noexcept -> size_t
330 { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
332 while(needed > count)
334 if UNLIKELY(device->FilterList.size() >= 1<<25)
335 return false;
337 device->FilterList.emplace_back();
338 auto sublist = device->FilterList.end() - 1;
339 sublist->FreeMask = ~0_u64;
340 sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64));
341 if UNLIKELY(!sublist->Filters)
343 device->FilterList.pop_back();
344 return false;
346 count += 64;
348 return true;
352 ALfilter *AllocFilter(ALCdevice *device)
354 auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
355 [](const FilterSubList &entry) noexcept -> bool
356 { return entry.FreeMask != 0; });
357 auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist));
358 auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
359 ASSUME(slidx < 64);
361 ALfilter *filter{al::construct_at(sublist->Filters + slidx)};
362 InitFilterParams(filter, AL_FILTER_NULL);
364 /* Add 1 to avoid filter ID 0. */
365 filter->id = ((lidx<<6) | slidx) + 1;
367 sublist->FreeMask &= ~(1_u64 << slidx);
369 return filter;
372 void FreeFilter(ALCdevice *device, ALfilter *filter)
374 const ALuint id{filter->id - 1};
375 const size_t lidx{id >> 6};
376 const ALuint slidx{id & 0x3f};
378 al::destroy_at(filter);
380 device->FilterList[lidx].FreeMask |= 1_u64 << slidx;
384 inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
386 const size_t lidx{(id-1) >> 6};
387 const ALuint slidx{(id-1) & 0x3f};
389 if UNLIKELY(lidx >= device->FilterList.size())
390 return nullptr;
391 FilterSubList &sublist = device->FilterList[lidx];
392 if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
393 return nullptr;
394 return sublist.Filters + slidx;
397 } // namespace
399 AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
400 START_API_FUNC
402 ContextRef context{GetContextRef()};
403 if UNLIKELY(!context) return;
405 if UNLIKELY(n < 0)
406 context->setError(AL_INVALID_VALUE, "Generating %d filters", n);
407 if UNLIKELY(n <= 0) return;
409 ALCdevice *device{context->mALDevice.get()};
410 std::lock_guard<std::mutex> _{device->FilterLock};
411 if(!EnsureFilters(device, static_cast<ALuint>(n)))
413 context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d filter%s", n, (n==1)?"":"s");
414 return;
417 if LIKELY(n == 1)
419 /* Special handling for the easy and normal case. */
420 ALfilter *filter{AllocFilter(device)};
421 if(filter) filters[0] = filter->id;
423 else
425 /* Store the allocated buffer IDs in a separate local list, to avoid
426 * modifying the user storage in case of failure.
428 al::vector<ALuint> ids;
429 ids.reserve(static_cast<ALuint>(n));
430 do {
431 ALfilter *filter{AllocFilter(device)};
432 ids.emplace_back(filter->id);
433 } while(--n);
434 std::copy(ids.begin(), ids.end(), filters);
437 END_API_FUNC
439 AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
440 START_API_FUNC
442 ContextRef context{GetContextRef()};
443 if UNLIKELY(!context) return;
445 if UNLIKELY(n < 0)
446 context->setError(AL_INVALID_VALUE, "Deleting %d filters", n);
447 if UNLIKELY(n <= 0) return;
449 ALCdevice *device{context->mALDevice.get()};
450 std::lock_guard<std::mutex> _{device->FilterLock};
452 /* First try to find any filters that are invalid. */
453 auto validate_filter = [device](const ALuint fid) -> bool
454 { return !fid || LookupFilter(device, fid) != nullptr; };
456 const ALuint *filters_end = filters + n;
457 auto invflt = std::find_if_not(filters, filters_end, validate_filter);
458 if UNLIKELY(invflt != filters_end)
460 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", *invflt);
461 return;
464 /* All good. Delete non-0 filter IDs. */
465 auto delete_filter = [device](const ALuint fid) -> void
467 ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr};
468 if(filter) FreeFilter(device, filter);
470 std::for_each(filters, filters_end, delete_filter);
472 END_API_FUNC
474 AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
475 START_API_FUNC
477 ContextRef context{GetContextRef()};
478 if LIKELY(context)
480 ALCdevice *device{context->mALDevice.get()};
481 std::lock_guard<std::mutex> _{device->FilterLock};
482 if(!filter || LookupFilter(device, filter))
483 return AL_TRUE;
485 return AL_FALSE;
487 END_API_FUNC
490 AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
491 START_API_FUNC
493 ContextRef context{GetContextRef()};
494 if UNLIKELY(!context) return;
496 ALCdevice *device{context->mALDevice.get()};
497 std::lock_guard<std::mutex> _{device->FilterLock};
499 ALfilter *alfilt{LookupFilter(device, filter)};
500 if UNLIKELY(!alfilt)
501 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
502 else
504 if(param == AL_FILTER_TYPE)
506 if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS
507 || value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
508 InitFilterParams(alfilt, value);
509 else
510 context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
512 else try
514 /* Call the appropriate handler */
515 alfilt->setParami(param, value);
517 catch(filter_exception &e) {
518 context->setError(e.errorCode(), "%s", e.what());
522 END_API_FUNC
524 AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
525 START_API_FUNC
527 switch(param)
529 case AL_FILTER_TYPE:
530 alFilteri(filter, param, values[0]);
531 return;
534 ContextRef context{GetContextRef()};
535 if UNLIKELY(!context) return;
537 ALCdevice *device{context->mALDevice.get()};
538 std::lock_guard<std::mutex> _{device->FilterLock};
540 ALfilter *alfilt{LookupFilter(device, filter)};
541 if UNLIKELY(!alfilt)
542 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
543 else try
545 /* Call the appropriate handler */
546 alfilt->setParamiv(param, values);
548 catch(filter_exception &e) {
549 context->setError(e.errorCode(), "%s", e.what());
552 END_API_FUNC
554 AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
555 START_API_FUNC
557 ContextRef context{GetContextRef()};
558 if UNLIKELY(!context) return;
560 ALCdevice *device{context->mALDevice.get()};
561 std::lock_guard<std::mutex> _{device->FilterLock};
563 ALfilter *alfilt{LookupFilter(device, filter)};
564 if UNLIKELY(!alfilt)
565 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
566 else try
568 /* Call the appropriate handler */
569 alfilt->setParamf(param, value);
571 catch(filter_exception &e) {
572 context->setError(e.errorCode(), "%s", e.what());
575 END_API_FUNC
577 AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
578 START_API_FUNC
580 ContextRef context{GetContextRef()};
581 if UNLIKELY(!context) return;
583 ALCdevice *device{context->mALDevice.get()};
584 std::lock_guard<std::mutex> _{device->FilterLock};
586 ALfilter *alfilt{LookupFilter(device, filter)};
587 if UNLIKELY(!alfilt)
588 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
589 else try
591 /* Call the appropriate handler */
592 alfilt->setParamfv(param, values);
594 catch(filter_exception &e) {
595 context->setError(e.errorCode(), "%s", e.what());
598 END_API_FUNC
600 AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
601 START_API_FUNC
603 ContextRef context{GetContextRef()};
604 if UNLIKELY(!context) return;
606 ALCdevice *device{context->mALDevice.get()};
607 std::lock_guard<std::mutex> _{device->FilterLock};
609 const ALfilter *alfilt{LookupFilter(device, filter)};
610 if UNLIKELY(!alfilt)
611 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
612 else
614 if(param == AL_FILTER_TYPE)
615 *value = alfilt->type;
616 else try
618 /* Call the appropriate handler */
619 alfilt->getParami(param, value);
621 catch(filter_exception &e) {
622 context->setError(e.errorCode(), "%s", e.what());
626 END_API_FUNC
628 AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
629 START_API_FUNC
631 switch(param)
633 case AL_FILTER_TYPE:
634 alGetFilteri(filter, param, values);
635 return;
638 ContextRef context{GetContextRef()};
639 if UNLIKELY(!context) return;
641 ALCdevice *device{context->mALDevice.get()};
642 std::lock_guard<std::mutex> _{device->FilterLock};
644 const ALfilter *alfilt{LookupFilter(device, filter)};
645 if UNLIKELY(!alfilt)
646 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
647 else try
649 /* Call the appropriate handler */
650 alfilt->getParamiv(param, values);
652 catch(filter_exception &e) {
653 context->setError(e.errorCode(), "%s", e.what());
656 END_API_FUNC
658 AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
659 START_API_FUNC
661 ContextRef context{GetContextRef()};
662 if UNLIKELY(!context) return;
664 ALCdevice *device{context->mALDevice.get()};
665 std::lock_guard<std::mutex> _{device->FilterLock};
667 const ALfilter *alfilt{LookupFilter(device, filter)};
668 if UNLIKELY(!alfilt)
669 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
670 else try
672 /* Call the appropriate handler */
673 alfilt->getParamf(param, value);
675 catch(filter_exception &e) {
676 context->setError(e.errorCode(), "%s", e.what());
679 END_API_FUNC
681 AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
682 START_API_FUNC
684 ContextRef context{GetContextRef()};
685 if UNLIKELY(!context) return;
687 ALCdevice *device{context->mALDevice.get()};
688 std::lock_guard<std::mutex> _{device->FilterLock};
690 const ALfilter *alfilt{LookupFilter(device, filter)};
691 if UNLIKELY(!alfilt)
692 context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
693 else try
695 /* Call the appropriate handler */
696 alfilt->getParamfv(param, values);
698 catch(filter_exception &e) {
699 context->setError(e.errorCode(), "%s", e.what());
702 END_API_FUNC
705 FilterSubList::~FilterSubList()
707 uint64_t usemask{~FreeMask};
708 while(usemask)
710 const int idx{al::countr_zero(usemask)};
711 al::destroy_at(Filters+idx);
712 usemask &= ~(1_u64 << idx);
714 FreeMask = ~usemask;
715 al_free(Filters);
716 Filters = nullptr;