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
34 #include <unordered_map>
42 #include "alc/context.h"
43 #include "alc/device.h"
44 #include "alc/inprogext.h"
46 #include "alnumeric.h"
48 #include "direct_defs.h"
50 #include "intrusive_ptr.h"
51 #include "opthelpers.h"
56 using SubListAllocator
= al::allocator
<std::array
<ALfilter
,64>>;
59 void InitFilterParams(ALfilter
*filter
, ALenum type
)
61 if(type
== AL_FILTER_LOWPASS
)
63 filter
->Gain
= AL_LOWPASS_DEFAULT_GAIN
;
64 filter
->GainHF
= AL_LOWPASS_DEFAULT_GAINHF
;
65 filter
->HFReference
= LowPassFreqRef
;
66 filter
->GainLF
= 1.0f
;
67 filter
->LFReference
= HighPassFreqRef
;
68 filter
->mTypeVariant
.emplace
<LowpassFilterTable
>();
70 else if(type
== AL_FILTER_HIGHPASS
)
72 filter
->Gain
= AL_HIGHPASS_DEFAULT_GAIN
;
73 filter
->GainHF
= 1.0f
;
74 filter
->HFReference
= LowPassFreqRef
;
75 filter
->GainLF
= AL_HIGHPASS_DEFAULT_GAINLF
;
76 filter
->LFReference
= HighPassFreqRef
;
77 filter
->mTypeVariant
.emplace
<HighpassFilterTable
>();
79 else if(type
== AL_FILTER_BANDPASS
)
81 filter
->Gain
= AL_BANDPASS_DEFAULT_GAIN
;
82 filter
->GainHF
= AL_BANDPASS_DEFAULT_GAINHF
;
83 filter
->HFReference
= LowPassFreqRef
;
84 filter
->GainLF
= AL_BANDPASS_DEFAULT_GAINLF
;
85 filter
->LFReference
= HighPassFreqRef
;
86 filter
->mTypeVariant
.emplace
<BandpassFilterTable
>();
91 filter
->GainHF
= 1.0f
;
92 filter
->HFReference
= LowPassFreqRef
;
93 filter
->GainLF
= 1.0f
;
94 filter
->LFReference
= HighPassFreqRef
;
95 filter
->mTypeVariant
.emplace
<NullFilterTable
>();
100 auto EnsureFilters(ALCdevice
*device
, size_t needed
) noexcept
-> bool
102 size_t count
{std::accumulate(device
->FilterList
.cbegin(), device
->FilterList
.cend(), 0_uz
,
103 [](size_t cur
, const FilterSubList
&sublist
) noexcept
-> size_t
104 { return cur
+ static_cast<ALuint
>(al::popcount(sublist
.FreeMask
)); })};
106 while(needed
> count
)
108 if(device
->FilterList
.size() >= 1<<25) UNLIKELY
111 FilterSubList sublist
{};
112 sublist
.FreeMask
= ~0_u64
;
113 sublist
.Filters
= SubListAllocator
{}.allocate(1);
114 device
->FilterList
.emplace_back(std::move(sublist
));
115 count
+= std::tuple_size_v
<SubListAllocator::value_type
>;
124 ALfilter
*AllocFilter(ALCdevice
*device
) noexcept
126 auto sublist
= std::find_if(device
->FilterList
.begin(), device
->FilterList
.end(),
127 [](const FilterSubList
&entry
) noexcept
-> bool
128 { return entry
.FreeMask
!= 0; });
129 auto lidx
= static_cast<ALuint
>(std::distance(device
->FilterList
.begin(), sublist
));
130 auto slidx
= static_cast<ALuint
>(al::countr_zero(sublist
->FreeMask
));
133 ALfilter
*filter
{al::construct_at(al::to_address(sublist
->Filters
->begin() + slidx
))};
134 InitFilterParams(filter
, AL_FILTER_NULL
);
136 /* Add 1 to avoid filter ID 0. */
137 filter
->id
= ((lidx
<<6) | slidx
) + 1;
139 sublist
->FreeMask
&= ~(1_u64
<< slidx
);
144 void FreeFilter(ALCdevice
*device
, ALfilter
*filter
)
146 device
->mFilterNames
.erase(filter
->id
);
148 const ALuint id
{filter
->id
- 1};
149 const size_t lidx
{id
>> 6};
150 const ALuint slidx
{id
& 0x3f};
152 std::destroy_at(filter
);
154 device
->FilterList
[lidx
].FreeMask
|= 1_u64
<< slidx
;
158 auto LookupFilter(ALCdevice
*device
, ALuint id
) noexcept
-> ALfilter
*
160 const size_t lidx
{(id
-1) >> 6};
161 const ALuint slidx
{(id
-1) & 0x3f};
163 if(lidx
>= device
->FilterList
.size()) UNLIKELY
165 FilterSubList
&sublist
= device
->FilterList
[lidx
];
166 if(sublist
.FreeMask
& (1_u64
<< slidx
)) UNLIKELY
168 return al::to_address(sublist
.Filters
->begin() + slidx
);
173 /* Null filter parameter handlers */
175 void FilterTable
<NullFilterTable
>::setParami(ALfilter
*, ALenum param
, int)
176 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
178 void FilterTable
<NullFilterTable
>::setParamiv(ALfilter
*, ALenum param
, const int*)
179 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
181 void FilterTable
<NullFilterTable
>::setParamf(ALfilter
*, ALenum param
, float)
182 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
184 void FilterTable
<NullFilterTable
>::setParamfv(ALfilter
*, ALenum param
, const float*)
185 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
187 void FilterTable
<NullFilterTable
>::getParami(const ALfilter
*, ALenum param
, int*)
188 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
190 void FilterTable
<NullFilterTable
>::getParamiv(const ALfilter
*, ALenum param
, int*)
191 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
193 void FilterTable
<NullFilterTable
>::getParamf(const ALfilter
*, ALenum param
, float*)
194 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
196 void FilterTable
<NullFilterTable
>::getParamfv(const ALfilter
*, ALenum param
, float*)
197 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid null filter property 0x%04x", param
}; }
199 /* Lowpass parameter handlers */
201 void FilterTable
<LowpassFilterTable
>::setParami(ALfilter
*, ALenum param
, int)
202 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid low-pass integer property 0x%04x", param
}; }
204 void FilterTable
<LowpassFilterTable
>::setParamiv(ALfilter
*filter
, ALenum param
, const int *values
)
205 { setParami(filter
, param
, *values
); }
207 void FilterTable
<LowpassFilterTable
>::setParamf(ALfilter
*filter
, ALenum param
, float val
)
211 case AL_LOWPASS_GAIN
:
212 if(!(val
>= AL_LOWPASS_MIN_GAIN
&& val
<= AL_LOWPASS_MAX_GAIN
))
213 throw al::context_error
{AL_INVALID_VALUE
, "Low-pass gain %f out of range", val
};
217 case AL_LOWPASS_GAINHF
:
218 if(!(val
>= AL_LOWPASS_MIN_GAINHF
&& val
<= AL_LOWPASS_MAX_GAINHF
))
219 throw al::context_error
{AL_INVALID_VALUE
, "Low-pass gainhf %f out of range", val
};
220 filter
->GainHF
= val
;
223 throw al::context_error
{AL_INVALID_ENUM
, "Invalid low-pass float property 0x%04x", param
};
226 void FilterTable
<LowpassFilterTable
>::setParamfv(ALfilter
*filter
, ALenum param
, const float *vals
)
227 { setParamf(filter
, param
, *vals
); }
229 void FilterTable
<LowpassFilterTable
>::getParami(const ALfilter
*, ALenum param
, int*)
230 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid low-pass integer property 0x%04x", param
}; }
232 void FilterTable
<LowpassFilterTable
>::getParamiv(const ALfilter
*filter
, ALenum param
, int *values
)
233 { getParami(filter
, param
, values
); }
235 void FilterTable
<LowpassFilterTable
>::getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
239 case AL_LOWPASS_GAIN
: *val
= filter
->Gain
; return;
240 case AL_LOWPASS_GAINHF
: *val
= filter
->GainHF
; return;
242 throw al::context_error
{AL_INVALID_ENUM
, "Invalid low-pass float property 0x%04x", param
};
245 void FilterTable
<LowpassFilterTable
>::getParamfv(const ALfilter
*filter
, ALenum param
, float *vals
)
246 { getParamf(filter
, param
, vals
); }
248 /* Highpass parameter handlers */
250 void FilterTable
<HighpassFilterTable
>::setParami(ALfilter
*, ALenum param
, int)
251 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid high-pass integer property 0x%04x", param
}; }
253 void FilterTable
<HighpassFilterTable
>::setParamiv(ALfilter
*filter
, ALenum param
, const int *values
)
254 { setParami(filter
, param
, *values
); }
256 void FilterTable
<HighpassFilterTable
>::setParamf(ALfilter
*filter
, ALenum param
, float val
)
260 case AL_HIGHPASS_GAIN
:
261 if(!(val
>= AL_HIGHPASS_MIN_GAIN
&& val
<= AL_HIGHPASS_MAX_GAIN
))
262 throw al::context_error
{AL_INVALID_VALUE
, "High-pass gain %f out of range", val
};
266 case AL_HIGHPASS_GAINLF
:
267 if(!(val
>= AL_HIGHPASS_MIN_GAINLF
&& val
<= AL_HIGHPASS_MAX_GAINLF
))
268 throw al::context_error
{AL_INVALID_VALUE
, "High-pass gainlf %f out of range", val
};
269 filter
->GainLF
= val
;
272 throw al::context_error
{AL_INVALID_ENUM
, "Invalid high-pass float property 0x%04x", param
};
275 void FilterTable
<HighpassFilterTable
>::setParamfv(ALfilter
*filter
, ALenum param
, const float *vals
)
276 { setParamf(filter
, param
, *vals
); }
278 void FilterTable
<HighpassFilterTable
>::getParami(const ALfilter
*, ALenum param
, int*)
279 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid high-pass integer property 0x%04x", param
}; }
281 void FilterTable
<HighpassFilterTable
>::getParamiv(const ALfilter
*filter
, ALenum param
, int *values
)
282 { getParami(filter
, param
, values
); }
284 void FilterTable
<HighpassFilterTable
>::getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
288 case AL_HIGHPASS_GAIN
: *val
= filter
->Gain
; return;
289 case AL_HIGHPASS_GAINLF
: *val
= filter
->GainLF
; return;
291 throw al::context_error
{AL_INVALID_ENUM
, "Invalid high-pass float property 0x%04x", param
};
294 void FilterTable
<HighpassFilterTable
>::getParamfv(const ALfilter
*filter
, ALenum param
, float *vals
)
295 { getParamf(filter
, param
, vals
); }
297 /* Bandpass parameter handlers */
299 void FilterTable
<BandpassFilterTable
>::setParami(ALfilter
*, ALenum param
, int)
300 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid band-pass integer property 0x%04x", param
}; }
302 void FilterTable
<BandpassFilterTable
>::setParamiv(ALfilter
*filter
, ALenum param
, const int *values
)
303 { setParami(filter
, param
, *values
); }
305 void FilterTable
<BandpassFilterTable
>::setParamf(ALfilter
*filter
, ALenum param
, float val
)
309 case AL_BANDPASS_GAIN
:
310 if(!(val
>= AL_BANDPASS_MIN_GAIN
&& val
<= AL_BANDPASS_MAX_GAIN
))
311 throw al::context_error
{AL_INVALID_VALUE
, "Band-pass gain %f out of range", val
};
315 case AL_BANDPASS_GAINHF
:
316 if(!(val
>= AL_BANDPASS_MIN_GAINHF
&& val
<= AL_BANDPASS_MAX_GAINHF
))
317 throw al::context_error
{AL_INVALID_VALUE
, "Band-pass gainhf %f out of range", val
};
318 filter
->GainHF
= val
;
321 case AL_BANDPASS_GAINLF
:
322 if(!(val
>= AL_BANDPASS_MIN_GAINLF
&& val
<= AL_BANDPASS_MAX_GAINLF
))
323 throw al::context_error
{AL_INVALID_VALUE
, "Band-pass gainlf %f out of range", val
};
324 filter
->GainLF
= val
;
327 throw al::context_error
{AL_INVALID_ENUM
, "Invalid band-pass float property 0x%04x", param
};
330 void FilterTable
<BandpassFilterTable
>::setParamfv(ALfilter
*filter
, ALenum param
, const float *vals
)
331 { setParamf(filter
, param
, *vals
); }
333 void FilterTable
<BandpassFilterTable
>::getParami(const ALfilter
*, ALenum param
, int*)
334 { throw al::context_error
{AL_INVALID_ENUM
, "Invalid band-pass integer property 0x%04x", param
}; }
336 void FilterTable
<BandpassFilterTable
>::getParamiv(const ALfilter
*filter
, ALenum param
, int *values
)
337 { getParami(filter
, param
, values
); }
339 void FilterTable
<BandpassFilterTable
>::getParamf(const ALfilter
*filter
, ALenum param
, float *val
)
343 case AL_BANDPASS_GAIN
: *val
= filter
->Gain
; return;
344 case AL_BANDPASS_GAINHF
: *val
= filter
->GainHF
; return;
345 case AL_BANDPASS_GAINLF
: *val
= filter
->GainLF
; return;
347 throw al::context_error
{AL_INVALID_ENUM
, "Invalid band-pass float property 0x%04x", param
};
350 void FilterTable
<BandpassFilterTable
>::getParamfv(const ALfilter
*filter
, ALenum param
, float *vals
)
351 { getParamf(filter
, param
, vals
); }
354 AL_API
DECL_FUNC2(void, alGenFilters
, ALsizei
,n
, ALuint
*,filters
)
355 FORCE_ALIGN
void AL_APIENTRY
alGenFiltersDirect(ALCcontext
*context
, ALsizei n
, ALuint
*filters
) noexcept
358 throw al::context_error
{AL_INVALID_VALUE
, "Generating %d filters", n
};
359 if(n
<= 0) UNLIKELY
return;
361 ALCdevice
*device
{context
->mALDevice
.get()};
362 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
364 const al::span fids
{filters
, static_cast<ALuint
>(n
)};
365 if(!EnsureFilters(device
, fids
.size()))
366 throw al::context_error
{AL_OUT_OF_MEMORY
, "Failed to allocate %d filter%s", n
,
367 (n
== 1) ? "" : "s"};
369 std::generate(fids
.begin(), fids
.end(), [device
]{ return AllocFilter(device
)->id
; });
371 catch(al::context_error
& e
) {
372 context
->setError(e
.errorCode(), "%s", e
.what());
375 AL_API
DECL_FUNC2(void, alDeleteFilters
, ALsizei
,n
, const ALuint
*,filters
)
376 FORCE_ALIGN
void AL_APIENTRY
alDeleteFiltersDirect(ALCcontext
*context
, ALsizei n
,
377 const ALuint
*filters
) noexcept
380 throw al::context_error
{AL_INVALID_VALUE
, "Deleting %d filters", n
};
381 if(n
<= 0) UNLIKELY
return;
383 ALCdevice
*device
{context
->mALDevice
.get()};
384 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
386 /* First try to find any filters that are invalid. */
387 auto validate_filter
= [device
](const ALuint fid
) -> bool
388 { return !fid
|| LookupFilter(device
, fid
) != nullptr; };
390 const al::span fids
{filters
, static_cast<ALuint
>(n
)};
391 auto invflt
= std::find_if_not(fids
.begin(), fids
.end(), validate_filter
);
392 if(invflt
!= fids
.end())
393 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", *invflt
};
395 /* All good. Delete non-0 filter IDs. */
396 auto delete_filter
= [device
](const ALuint fid
) -> void
398 if(ALfilter
*filter
{fid
? LookupFilter(device
, fid
) : nullptr})
399 FreeFilter(device
, filter
);
401 std::for_each(fids
.begin(), fids
.end(), delete_filter
);
403 catch(al::context_error
& e
) {
404 context
->setError(e
.errorCode(), "%s", e
.what());
407 AL_API
DECL_FUNC1(ALboolean
, alIsFilter
, ALuint
,filter
)
408 FORCE_ALIGN ALboolean AL_APIENTRY
alIsFilterDirect(ALCcontext
*context
, ALuint filter
) noexcept
410 ALCdevice
*device
{context
->mALDevice
.get()};
411 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
412 if(!filter
|| LookupFilter(device
, filter
))
418 AL_API
DECL_FUNC3(void, alFilteri
, ALuint
,filter
, ALenum
,param
, ALint
,value
)
419 FORCE_ALIGN
void AL_APIENTRY
alFilteriDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
420 ALint value
) noexcept
422 ALCdevice
*device
{context
->mALDevice
.get()};
423 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
425 ALfilter
*alfilt
{LookupFilter(device
, filter
)};
427 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
432 if(!(value
== AL_FILTER_NULL
|| value
== AL_FILTER_LOWPASS
433 || value
== AL_FILTER_HIGHPASS
|| value
== AL_FILTER_BANDPASS
))
434 throw al::context_error
{AL_INVALID_VALUE
, "Invalid filter type 0x%04x", value
};
435 InitFilterParams(alfilt
, value
);
439 /* Call the appropriate handler */
440 std::visit([alfilt
,param
,value
](auto&& thunk
){thunk
.setParami(alfilt
, param
, value
);},
441 alfilt
->mTypeVariant
);
443 catch(al::context_error
& e
) {
444 context
->setError(e
.errorCode(), "%s", e
.what());
447 AL_API
DECL_FUNC3(void, alFilteriv
, ALuint
,filter
, ALenum
,param
, const ALint
*,values
)
448 FORCE_ALIGN
void AL_APIENTRY
alFilterivDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
449 const ALint
*values
) noexcept
454 alFilteriDirect(context
, filter
, param
, *values
);
458 ALCdevice
*device
{context
->mALDevice
.get()};
459 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
461 ALfilter
*alfilt
{LookupFilter(device
, filter
)};
463 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
465 /* Call the appropriate handler */
466 std::visit([alfilt
,param
,values
](auto&& thunk
){thunk
.setParamiv(alfilt
, param
, values
);},
467 alfilt
->mTypeVariant
);
469 catch(al::context_error
& e
) {
470 context
->setError(e
.errorCode(), "%s", e
.what());
473 AL_API
DECL_FUNC3(void, alFilterf
, ALuint
,filter
, ALenum
,param
, ALfloat
,value
)
474 FORCE_ALIGN
void AL_APIENTRY
alFilterfDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
475 ALfloat value
) noexcept
477 ALCdevice
*device
{context
->mALDevice
.get()};
478 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
480 ALfilter
*alfilt
{LookupFilter(device
, filter
)};
482 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
484 /* Call the appropriate handler */
485 std::visit([alfilt
,param
,value
](auto&& thunk
){thunk
.setParamf(alfilt
, param
, value
);},
486 alfilt
->mTypeVariant
);
488 catch(al::context_error
& e
) {
489 context
->setError(e
.errorCode(), "%s", e
.what());
492 AL_API
DECL_FUNC3(void, alFilterfv
, ALuint
,filter
, ALenum
,param
, const ALfloat
*,values
)
493 FORCE_ALIGN
void AL_APIENTRY
alFilterfvDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
494 const ALfloat
*values
) noexcept
496 ALCdevice
*device
{context
->mALDevice
.get()};
497 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
499 ALfilter
*alfilt
{LookupFilter(device
, filter
)};
501 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
503 /* Call the appropriate handler */
504 std::visit([alfilt
,param
,values
](auto&& thunk
){thunk
.setParamfv(alfilt
, param
, values
);},
505 alfilt
->mTypeVariant
);
507 catch(al::context_error
& e
) {
508 context
->setError(e
.errorCode(), "%s", e
.what());
511 AL_API
DECL_FUNC3(void, alGetFilteri
, ALuint
,filter
, ALenum
,param
, ALint
*,value
)
512 FORCE_ALIGN
void AL_APIENTRY
alGetFilteriDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
513 ALint
*value
) noexcept
515 ALCdevice
*device
{context
->mALDevice
.get()};
516 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
518 const ALfilter
*alfilt
{LookupFilter(device
, filter
)};
520 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
525 *value
= alfilt
->type
;
529 /* Call the appropriate handler */
530 std::visit([alfilt
,param
,value
](auto&& thunk
){thunk
.getParami(alfilt
, param
, value
);},
531 alfilt
->mTypeVariant
);
533 catch(al::context_error
& e
) {
534 context
->setError(e
.errorCode(), "%s", e
.what());
537 AL_API
DECL_FUNC3(void, alGetFilteriv
, ALuint
,filter
, ALenum
,param
, ALint
*,values
)
538 FORCE_ALIGN
void AL_APIENTRY
alGetFilterivDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
539 ALint
*values
) noexcept
544 alGetFilteriDirect(context
, filter
, param
, values
);
548 ALCdevice
*device
{context
->mALDevice
.get()};
549 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
551 const ALfilter
*alfilt
{LookupFilter(device
, filter
)};
553 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
555 /* Call the appropriate handler */
556 std::visit([alfilt
,param
,values
](auto&& thunk
){thunk
.getParamiv(alfilt
, param
, values
);},
557 alfilt
->mTypeVariant
);
559 catch(al::context_error
& e
) {
560 context
->setError(e
.errorCode(), "%s", e
.what());
563 AL_API
DECL_FUNC3(void, alGetFilterf
, ALuint
,filter
, ALenum
,param
, ALfloat
*,value
)
564 FORCE_ALIGN
void AL_APIENTRY
alGetFilterfDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
565 ALfloat
*value
) noexcept
567 ALCdevice
*device
{context
->mALDevice
.get()};
568 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
570 const ALfilter
*alfilt
{LookupFilter(device
, filter
)};
572 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
574 /* Call the appropriate handler */
575 std::visit([alfilt
,param
,value
](auto&& thunk
){thunk
.getParamf(alfilt
, param
, value
);},
576 alfilt
->mTypeVariant
);
578 catch(al::context_error
& e
) {
579 context
->setError(e
.errorCode(), "%s", e
.what());
582 AL_API
DECL_FUNC3(void, alGetFilterfv
, ALuint
,filter
, ALenum
,param
, ALfloat
*,values
)
583 FORCE_ALIGN
void AL_APIENTRY
alGetFilterfvDirect(ALCcontext
*context
, ALuint filter
, ALenum param
,
584 ALfloat
*values
) noexcept
586 ALCdevice
*device
{context
->mALDevice
.get()};
587 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
589 const ALfilter
*alfilt
{LookupFilter(device
, filter
)};
591 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", filter
};
593 /* Call the appropriate handler */
594 std::visit([alfilt
,param
,values
](auto&& thunk
){thunk
.getParamfv(alfilt
, param
, values
);},
595 alfilt
->mTypeVariant
);
597 catch(al::context_error
& e
) {
598 context
->setError(e
.errorCode(), "%s", e
.what());
602 void ALfilter::SetName(ALCcontext
*context
, ALuint id
, std::string_view name
)
604 ALCdevice
*device
{context
->mALDevice
.get()};
605 std::lock_guard
<std::mutex
> filterlock
{device
->FilterLock
};
607 auto filter
= LookupFilter(device
, id
);
609 throw al::context_error
{AL_INVALID_NAME
, "Invalid filter ID %u", id
};
611 device
->mFilterNames
.insert_or_assign(id
, name
);
615 FilterSubList::~FilterSubList()
620 uint64_t usemask
{~FreeMask
};
623 const int idx
{al::countr_zero(usemask
)};
624 std::destroy_at(al::to_address(Filters
->begin() + idx
));
625 usemask
&= ~(1_u64
<< idx
);
628 SubListAllocator
{}.deallocate(Filters
, 1);