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
40 #include "alc/context.h"
41 #include "alc/device.h"
43 #include "alnumeric.h"
44 #include "core/except.h"
45 #include "opthelpers.h"
51 class filter_exception final
: public al::base_exception
{
55 #ifdef __USE_MINGW_ANSI_STDIO
56 [[gnu::format(gnu_printf
, 3, 4)]]
58 [[gnu::format(printf
, 3, 4)]]
60 filter_exception(ALenum code
, const char *msg
, ...) : mErrorCode
{code
}
64 setMessage(msg
, 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",
84 void ALlowpass_setParamf(ALfilter
*filter
, ALenum param
, float val
)
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
};
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
};
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",
114 void ALlowpass_getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
118 case AL_LOWPASS_GAIN
:
122 case AL_LOWPASS_GAINHF
:
123 *val
= filter
->GainHF
;
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",
143 void ALhighpass_setParamf(ALfilter
*filter
, ALenum param
, float val
)
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
};
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
;
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",
173 void ALhighpass_getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
177 case AL_HIGHPASS_GAIN
:
181 case AL_HIGHPASS_GAINLF
:
182 *val
= filter
->GainLF
;
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",
202 void ALbandpass_setParamf(ALfilter
*filter
, ALenum param
, float val
)
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
};
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
;
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
;
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",
238 void ALbandpass_getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
242 case AL_BANDPASS_GAIN
:
246 case AL_BANDPASS_GAINHF
:
247 *val
= filter
->GainHF
;
250 case AL_BANDPASS_GAINLF
:
251 *val
= filter
->GainLF
;
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
;
317 filter
->GainHF
= 1.0f
;
318 filter
->HFReference
= LOWPASSFREQREF
;
319 filter
->GainLF
= 1.0f
;
320 filter
->LFReference
= HIGHPASSFREQREF
;
321 filter
->vtab
= &ALnullfilter_vtable
;
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)
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();
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
));
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
);
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())
391 FilterSubList
&sublist
= device
->FilterList
[lidx
];
392 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
394 return sublist
.Filters
+ slidx
;
399 AL_API
void AL_APIENTRY
alGenFilters(ALsizei n
, ALuint
*filters
)
402 ContextRef context
{GetContextRef()};
403 if UNLIKELY(!context
) return;
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");
419 /* Special handling for the easy and normal case. */
420 ALfilter
*filter
{AllocFilter(device
)};
421 if(filter
) filters
[0] = filter
->id
;
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
));
431 ALfilter
*filter
{AllocFilter(device
)};
432 ids
.emplace_back(filter
->id
);
434 std::copy(ids
.begin(), ids
.end(), filters
);
439 AL_API
void AL_APIENTRY
alDeleteFilters(ALsizei n
, const ALuint
*filters
)
442 ContextRef context
{GetContextRef()};
443 if UNLIKELY(!context
) return;
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
);
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
);
474 AL_API ALboolean AL_APIENTRY
alIsFilter(ALuint filter
)
477 ContextRef context
{GetContextRef()};
480 ALCdevice
*device
{context
->mALDevice
.get()};
481 std::lock_guard
<std::mutex
> _
{device
->FilterLock
};
482 if(!filter
|| LookupFilter(device
, filter
))
490 AL_API
void AL_APIENTRY
alFilteri(ALuint filter
, ALenum param
, ALint value
)
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
)};
501 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
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
);
510 context
->setError(AL_INVALID_VALUE
, "Invalid filter type 0x%04x", value
);
514 /* Call the appropriate handler */
515 alfilt
->setParami(param
, value
);
517 catch(filter_exception
&e
) {
518 context
->setError(e
.errorCode(), "%s", e
.what());
524 AL_API
void AL_APIENTRY
alFilteriv(ALuint filter
, ALenum param
, const ALint
*values
)
530 alFilteri(filter
, param
, values
[0]);
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
)};
542 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
545 /* Call the appropriate handler */
546 alfilt
->setParamiv(param
, values
);
548 catch(filter_exception
&e
) {
549 context
->setError(e
.errorCode(), "%s", e
.what());
554 AL_API
void AL_APIENTRY
alFilterf(ALuint filter
, ALenum param
, ALfloat value
)
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
)};
565 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
568 /* Call the appropriate handler */
569 alfilt
->setParamf(param
, value
);
571 catch(filter_exception
&e
) {
572 context
->setError(e
.errorCode(), "%s", e
.what());
577 AL_API
void AL_APIENTRY
alFilterfv(ALuint filter
, ALenum param
, const ALfloat
*values
)
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
)};
588 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
591 /* Call the appropriate handler */
592 alfilt
->setParamfv(param
, values
);
594 catch(filter_exception
&e
) {
595 context
->setError(e
.errorCode(), "%s", e
.what());
600 AL_API
void AL_APIENTRY
alGetFilteri(ALuint filter
, ALenum param
, ALint
*value
)
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
)};
611 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
614 if(param
== AL_FILTER_TYPE
)
615 *value
= alfilt
->type
;
618 /* Call the appropriate handler */
619 alfilt
->getParami(param
, value
);
621 catch(filter_exception
&e
) {
622 context
->setError(e
.errorCode(), "%s", e
.what());
628 AL_API
void AL_APIENTRY
alGetFilteriv(ALuint filter
, ALenum param
, ALint
*values
)
634 alGetFilteri(filter
, param
, values
);
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
)};
646 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
649 /* Call the appropriate handler */
650 alfilt
->getParamiv(param
, values
);
652 catch(filter_exception
&e
) {
653 context
->setError(e
.errorCode(), "%s", e
.what());
658 AL_API
void AL_APIENTRY
alGetFilterf(ALuint filter
, ALenum param
, ALfloat
*value
)
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
)};
669 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
672 /* Call the appropriate handler */
673 alfilt
->getParamf(param
, value
);
675 catch(filter_exception
&e
) {
676 context
->setError(e
.errorCode(), "%s", e
.what());
681 AL_API
void AL_APIENTRY
alGetFilterfv(ALuint filter
, ALenum param
, ALfloat
*values
)
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
)};
692 context
->setError(AL_INVALID_NAME
, "Invalid filter ID %u", filter
);
695 /* Call the appropriate handler */
696 alfilt
->getParamfv(param
, values
);
698 catch(filter_exception
&e
) {
699 context
->setError(e
.errorCode(), "%s", e
.what());
705 FilterSubList::~FilterSubList()
707 uint64_t usemask
{~FreeMask
};
710 const int idx
{al::countr_zero(usemask
)};
711 al::destroy_at(Filters
+idx
);
712 usemask
&= ~(1_u64
<< idx
);