filter.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  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.
  8. *
  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.
  13. *
  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
  19. */
  20. #include "config.h"
  21. #include "filter.h"
  22. #include <algorithm>
  23. #include <cstdarg>
  24. #include <cstdint>
  25. #include <cstdio>
  26. #include <iterator>
  27. #include <memory>
  28. #include <mutex>
  29. #include <numeric>
  30. #include <string>
  31. #include <unordered_map>
  32. #include <vector>
  33. #include "AL/al.h"
  34. #include "AL/alc.h"
  35. #include "AL/efx.h"
  36. #include "albit.h"
  37. #include "alc/context.h"
  38. #include "alc/device.h"
  39. #include "alc/inprogext.h"
  40. #include "almalloc.h"
  41. #include "alnumeric.h"
  42. #include "alspan.h"
  43. #include "direct_defs.h"
  44. #include "error.h"
  45. #include "intrusive_ptr.h"
  46. #include "opthelpers.h"
  47. namespace {
  48. using SubListAllocator = al::allocator<std::array<ALfilter,64>>;
  49. void InitFilterParams(ALfilter *filter, ALenum type)
  50. {
  51. if(type == AL_FILTER_LOWPASS)
  52. {
  53. filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
  54. filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
  55. filter->HFReference = LowPassFreqRef;
  56. filter->GainLF = 1.0f;
  57. filter->LFReference = HighPassFreqRef;
  58. filter->mTypeVariant.emplace<LowpassFilterTable>();
  59. }
  60. else if(type == AL_FILTER_HIGHPASS)
  61. {
  62. filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
  63. filter->GainHF = 1.0f;
  64. filter->HFReference = LowPassFreqRef;
  65. filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
  66. filter->LFReference = HighPassFreqRef;
  67. filter->mTypeVariant.emplace<HighpassFilterTable>();
  68. }
  69. else if(type == AL_FILTER_BANDPASS)
  70. {
  71. filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
  72. filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
  73. filter->HFReference = LowPassFreqRef;
  74. filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
  75. filter->LFReference = HighPassFreqRef;
  76. filter->mTypeVariant.emplace<BandpassFilterTable>();
  77. }
  78. else
  79. {
  80. filter->Gain = 1.0f;
  81. filter->GainHF = 1.0f;
  82. filter->HFReference = LowPassFreqRef;
  83. filter->GainLF = 1.0f;
  84. filter->LFReference = HighPassFreqRef;
  85. filter->mTypeVariant.emplace<NullFilterTable>();
  86. }
  87. filter->type = type;
  88. }
  89. auto EnsureFilters(ALCdevice *device, size_t needed) noexcept -> bool
  90. try {
  91. size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), 0_uz,
  92. [](size_t cur, const FilterSubList &sublist) noexcept -> size_t
  93. { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
  94. while(needed > count)
  95. {
  96. if(device->FilterList.size() >= 1<<25) UNLIKELY
  97. return false;
  98. FilterSubList sublist{};
  99. sublist.FreeMask = ~0_u64;
  100. sublist.Filters = SubListAllocator{}.allocate(1);
  101. device->FilterList.emplace_back(std::move(sublist));
  102. count += std::tuple_size_v<SubListAllocator::value_type>;
  103. }
  104. return true;
  105. }
  106. catch(...) {
  107. return false;
  108. }
  109. ALfilter *AllocFilter(ALCdevice *device) noexcept
  110. {
  111. auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
  112. [](const FilterSubList &entry) noexcept -> bool
  113. { return entry.FreeMask != 0; });
  114. auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist));
  115. auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
  116. ASSUME(slidx < 64);
  117. ALfilter *filter{al::construct_at(al::to_address(sublist->Filters->begin() + slidx))};
  118. InitFilterParams(filter, AL_FILTER_NULL);
  119. /* Add 1 to avoid filter ID 0. */
  120. filter->id = ((lidx<<6) | slidx) + 1;
  121. sublist->FreeMask &= ~(1_u64 << slidx);
  122. return filter;
  123. }
  124. void FreeFilter(ALCdevice *device, ALfilter *filter)
  125. {
  126. device->mFilterNames.erase(filter->id);
  127. const ALuint id{filter->id - 1};
  128. const size_t lidx{id >> 6};
  129. const ALuint slidx{id & 0x3f};
  130. std::destroy_at(filter);
  131. device->FilterList[lidx].FreeMask |= 1_u64 << slidx;
  132. }
  133. inline auto LookupFilter(ALCdevice *device, ALuint id) noexcept -> ALfilter*
  134. {
  135. const size_t lidx{(id-1) >> 6};
  136. const ALuint slidx{(id-1) & 0x3f};
  137. if(lidx >= device->FilterList.size()) UNLIKELY
  138. return nullptr;
  139. FilterSubList &sublist = device->FilterList[lidx];
  140. if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
  141. return nullptr;
  142. return al::to_address(sublist.Filters->begin() + slidx);
  143. }
  144. } // namespace
  145. /* Null filter parameter handlers */
  146. template<>
  147. void FilterTable<NullFilterTable>::setParami(ALfilter*, ALenum param, int)
  148. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  149. template<>
  150. void FilterTable<NullFilterTable>::setParamiv(ALfilter*, ALenum param, const int*)
  151. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  152. template<>
  153. void FilterTable<NullFilterTable>::setParamf(ALfilter*, ALenum param, float)
  154. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  155. template<>
  156. void FilterTable<NullFilterTable>::setParamfv(ALfilter*, ALenum param, const float*)
  157. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  158. template<>
  159. void FilterTable<NullFilterTable>::getParami(const ALfilter*, ALenum param, int*)
  160. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  161. template<>
  162. void FilterTable<NullFilterTable>::getParamiv(const ALfilter*, ALenum param, int*)
  163. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  164. template<>
  165. void FilterTable<NullFilterTable>::getParamf(const ALfilter*, ALenum param, float*)
  166. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  167. template<>
  168. void FilterTable<NullFilterTable>::getParamfv(const ALfilter*, ALenum param, float*)
  169. { throw al::context_error{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  170. /* Lowpass parameter handlers */
  171. template<>
  172. void FilterTable<LowpassFilterTable>::setParami(ALfilter*, ALenum param, int)
  173. { throw al::context_error{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
  174. template<>
  175. void FilterTable<LowpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values)
  176. { setParami(filter, param, *values); }
  177. template<>
  178. void FilterTable<LowpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val)
  179. {
  180. switch(param)
  181. {
  182. case AL_LOWPASS_GAIN:
  183. if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
  184. throw al::context_error{AL_INVALID_VALUE, "Low-pass gain %f out of range", val};
  185. filter->Gain = val;
  186. return;
  187. case AL_LOWPASS_GAINHF:
  188. if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
  189. throw al::context_error{AL_INVALID_VALUE, "Low-pass gainhf %f out of range", val};
  190. filter->GainHF = val;
  191. return;
  192. }
  193. throw al::context_error{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
  194. }
  195. template<>
  196. void FilterTable<LowpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals)
  197. { setParamf(filter, param, *vals); }
  198. template<>
  199. void FilterTable<LowpassFilterTable>::getParami(const ALfilter*, ALenum param, int*)
  200. { throw al::context_error{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
  201. template<>
  202. void FilterTable<LowpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values)
  203. { getParami(filter, param, values); }
  204. template<>
  205. void FilterTable<LowpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val)
  206. {
  207. switch(param)
  208. {
  209. case AL_LOWPASS_GAIN: *val = filter->Gain; return;
  210. case AL_LOWPASS_GAINHF: *val = filter->GainHF; return;
  211. }
  212. throw al::context_error{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
  213. }
  214. template<>
  215. void FilterTable<LowpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals)
  216. { getParamf(filter, param, vals); }
  217. /* Highpass parameter handlers */
  218. template<>
  219. void FilterTable<HighpassFilterTable>::setParami(ALfilter*, ALenum param, int)
  220. { throw al::context_error{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
  221. template<>
  222. void FilterTable<HighpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values)
  223. { setParami(filter, param, *values); }
  224. template<>
  225. void FilterTable<HighpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val)
  226. {
  227. switch(param)
  228. {
  229. case AL_HIGHPASS_GAIN:
  230. if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
  231. throw al::context_error{AL_INVALID_VALUE, "High-pass gain %f out of range", val};
  232. filter->Gain = val;
  233. return;
  234. case AL_HIGHPASS_GAINLF:
  235. if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
  236. throw al::context_error{AL_INVALID_VALUE, "High-pass gainlf %f out of range", val};
  237. filter->GainLF = val;
  238. return;
  239. }
  240. throw al::context_error{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
  241. }
  242. template<>
  243. void FilterTable<HighpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals)
  244. { setParamf(filter, param, *vals); }
  245. template<>
  246. void FilterTable<HighpassFilterTable>::getParami(const ALfilter*, ALenum param, int*)
  247. { throw al::context_error{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
  248. template<>
  249. void FilterTable<HighpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values)
  250. { getParami(filter, param, values); }
  251. template<>
  252. void FilterTable<HighpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val)
  253. {
  254. switch(param)
  255. {
  256. case AL_HIGHPASS_GAIN: *val = filter->Gain; return;
  257. case AL_HIGHPASS_GAINLF: *val = filter->GainLF; return;
  258. }
  259. throw al::context_error{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
  260. }
  261. template<>
  262. void FilterTable<HighpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals)
  263. { getParamf(filter, param, vals); }
  264. /* Bandpass parameter handlers */
  265. template<>
  266. void FilterTable<BandpassFilterTable>::setParami(ALfilter*, ALenum param, int)
  267. { throw al::context_error{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
  268. template<>
  269. void FilterTable<BandpassFilterTable>::setParamiv(ALfilter *filter, ALenum param, const int *values)
  270. { setParami(filter, param, *values); }
  271. template<>
  272. void FilterTable<BandpassFilterTable>::setParamf(ALfilter *filter, ALenum param, float val)
  273. {
  274. switch(param)
  275. {
  276. case AL_BANDPASS_GAIN:
  277. if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
  278. throw al::context_error{AL_INVALID_VALUE, "Band-pass gain %f out of range", val};
  279. filter->Gain = val;
  280. return;
  281. case AL_BANDPASS_GAINHF:
  282. if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
  283. throw al::context_error{AL_INVALID_VALUE, "Band-pass gainhf %f out of range", val};
  284. filter->GainHF = val;
  285. return;
  286. case AL_BANDPASS_GAINLF:
  287. if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
  288. throw al::context_error{AL_INVALID_VALUE, "Band-pass gainlf %f out of range", val};
  289. filter->GainLF = val;
  290. return;
  291. }
  292. throw al::context_error{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
  293. }
  294. template<>
  295. void FilterTable<BandpassFilterTable>::setParamfv(ALfilter *filter, ALenum param, const float *vals)
  296. { setParamf(filter, param, *vals); }
  297. template<>
  298. void FilterTable<BandpassFilterTable>::getParami(const ALfilter*, ALenum param, int*)
  299. { throw al::context_error{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
  300. template<>
  301. void FilterTable<BandpassFilterTable>::getParamiv(const ALfilter *filter, ALenum param, int *values)
  302. { getParami(filter, param, values); }
  303. template<>
  304. void FilterTable<BandpassFilterTable>::getParamf(const ALfilter *filter, ALenum param, float *val)
  305. {
  306. switch(param)
  307. {
  308. case AL_BANDPASS_GAIN: *val = filter->Gain; return;
  309. case AL_BANDPASS_GAINHF: *val = filter->GainHF; return;
  310. case AL_BANDPASS_GAINLF: *val = filter->GainLF; return;
  311. }
  312. throw al::context_error{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
  313. }
  314. template<>
  315. void FilterTable<BandpassFilterTable>::getParamfv(const ALfilter *filter, ALenum param, float *vals)
  316. { getParamf(filter, param, vals); }
  317. AL_API DECL_FUNC2(void, alGenFilters, ALsizei,n, ALuint*,filters)
  318. FORCE_ALIGN void AL_APIENTRY alGenFiltersDirect(ALCcontext *context, ALsizei n, ALuint *filters) noexcept
  319. try {
  320. if(n < 0)
  321. throw al::context_error{AL_INVALID_VALUE, "Generating %d filters", n};
  322. if(n <= 0) UNLIKELY return;
  323. ALCdevice *device{context->mALDevice.get()};
  324. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  325. const al::span fids{filters, static_cast<ALuint>(n)};
  326. if(!EnsureFilters(device, fids.size()))
  327. throw al::context_error{AL_OUT_OF_MEMORY, "Failed to allocate %d filter%s", n,
  328. (n == 1) ? "" : "s"};
  329. std::generate(fids.begin(), fids.end(), [device]{ return AllocFilter(device)->id; });
  330. }
  331. catch(al::context_error& e) {
  332. context->setError(e.errorCode(), "%s", e.what());
  333. }
  334. AL_API DECL_FUNC2(void, alDeleteFilters, ALsizei,n, const ALuint*,filters)
  335. FORCE_ALIGN void AL_APIENTRY alDeleteFiltersDirect(ALCcontext *context, ALsizei n,
  336. const ALuint *filters) noexcept
  337. try {
  338. if(n < 0)
  339. throw al::context_error{AL_INVALID_VALUE, "Deleting %d filters", n};
  340. if(n <= 0) UNLIKELY return;
  341. ALCdevice *device{context->mALDevice.get()};
  342. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  343. /* First try to find any filters that are invalid. */
  344. auto validate_filter = [device](const ALuint fid) -> bool
  345. { return !fid || LookupFilter(device, fid) != nullptr; };
  346. const al::span fids{filters, static_cast<ALuint>(n)};
  347. auto invflt = std::find_if_not(fids.begin(), fids.end(), validate_filter);
  348. if(invflt != fids.end())
  349. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", *invflt};
  350. /* All good. Delete non-0 filter IDs. */
  351. auto delete_filter = [device](const ALuint fid) -> void
  352. {
  353. if(ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr})
  354. FreeFilter(device, filter);
  355. };
  356. std::for_each(fids.begin(), fids.end(), delete_filter);
  357. }
  358. catch(al::context_error& e) {
  359. context->setError(e.errorCode(), "%s", e.what());
  360. }
  361. AL_API DECL_FUNC1(ALboolean, alIsFilter, ALuint,filter)
  362. FORCE_ALIGN ALboolean AL_APIENTRY alIsFilterDirect(ALCcontext *context, ALuint filter) noexcept
  363. {
  364. ALCdevice *device{context->mALDevice.get()};
  365. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  366. if(!filter || LookupFilter(device, filter))
  367. return AL_TRUE;
  368. return AL_FALSE;
  369. }
  370. AL_API DECL_FUNC3(void, alFilteri, ALuint,filter, ALenum,param, ALint,value)
  371. FORCE_ALIGN void AL_APIENTRY alFilteriDirect(ALCcontext *context, ALuint filter, ALenum param,
  372. ALint value) noexcept
  373. try {
  374. ALCdevice *device{context->mALDevice.get()};
  375. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  376. ALfilter *alfilt{LookupFilter(device, filter)};
  377. if(!alfilt)
  378. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  379. switch(param)
  380. {
  381. case AL_FILTER_TYPE:
  382. if(!(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS
  383. || value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS))
  384. throw al::context_error{AL_INVALID_VALUE, "Invalid filter type 0x%04x", value};
  385. InitFilterParams(alfilt, value);
  386. return;
  387. }
  388. /* Call the appropriate handler */
  389. std::visit([alfilt,param,value](auto&& thunk){thunk.setParami(alfilt, param, value);},
  390. alfilt->mTypeVariant);
  391. }
  392. catch(al::context_error& e) {
  393. context->setError(e.errorCode(), "%s", e.what());
  394. }
  395. AL_API DECL_FUNC3(void, alFilteriv, ALuint,filter, ALenum,param, const ALint*,values)
  396. FORCE_ALIGN void AL_APIENTRY alFilterivDirect(ALCcontext *context, ALuint filter, ALenum param,
  397. const ALint *values) noexcept
  398. try {
  399. switch(param)
  400. {
  401. case AL_FILTER_TYPE:
  402. alFilteriDirect(context, filter, param, *values);
  403. return;
  404. }
  405. ALCdevice *device{context->mALDevice.get()};
  406. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  407. ALfilter *alfilt{LookupFilter(device, filter)};
  408. if(!alfilt)
  409. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  410. /* Call the appropriate handler */
  411. std::visit([alfilt,param,values](auto&& thunk){thunk.setParamiv(alfilt, param, values);},
  412. alfilt->mTypeVariant);
  413. }
  414. catch(al::context_error& e) {
  415. context->setError(e.errorCode(), "%s", e.what());
  416. }
  417. AL_API DECL_FUNC3(void, alFilterf, ALuint,filter, ALenum,param, ALfloat,value)
  418. FORCE_ALIGN void AL_APIENTRY alFilterfDirect(ALCcontext *context, ALuint filter, ALenum param,
  419. ALfloat value) noexcept
  420. try {
  421. ALCdevice *device{context->mALDevice.get()};
  422. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  423. ALfilter *alfilt{LookupFilter(device, filter)};
  424. if(!alfilt)
  425. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  426. /* Call the appropriate handler */
  427. std::visit([alfilt,param,value](auto&& thunk){thunk.setParamf(alfilt, param, value);},
  428. alfilt->mTypeVariant);
  429. }
  430. catch(al::context_error& e) {
  431. context->setError(e.errorCode(), "%s", e.what());
  432. }
  433. AL_API DECL_FUNC3(void, alFilterfv, ALuint,filter, ALenum,param, const ALfloat*,values)
  434. FORCE_ALIGN void AL_APIENTRY alFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param,
  435. const ALfloat *values) noexcept
  436. try {
  437. ALCdevice *device{context->mALDevice.get()};
  438. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  439. ALfilter *alfilt{LookupFilter(device, filter)};
  440. if(!alfilt)
  441. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  442. /* Call the appropriate handler */
  443. std::visit([alfilt,param,values](auto&& thunk){thunk.setParamfv(alfilt, param, values);},
  444. alfilt->mTypeVariant);
  445. }
  446. catch(al::context_error& e) {
  447. context->setError(e.errorCode(), "%s", e.what());
  448. }
  449. AL_API DECL_FUNC3(void, alGetFilteri, ALuint,filter, ALenum,param, ALint*,value)
  450. FORCE_ALIGN void AL_APIENTRY alGetFilteriDirect(ALCcontext *context, ALuint filter, ALenum param,
  451. ALint *value) noexcept
  452. try {
  453. ALCdevice *device{context->mALDevice.get()};
  454. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  455. const ALfilter *alfilt{LookupFilter(device, filter)};
  456. if(!alfilt)
  457. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  458. switch(param)
  459. {
  460. case AL_FILTER_TYPE:
  461. *value = alfilt->type;
  462. return;
  463. }
  464. /* Call the appropriate handler */
  465. std::visit([alfilt,param,value](auto&& thunk){thunk.getParami(alfilt, param, value);},
  466. alfilt->mTypeVariant);
  467. }
  468. catch(al::context_error& e) {
  469. context->setError(e.errorCode(), "%s", e.what());
  470. }
  471. AL_API DECL_FUNC3(void, alGetFilteriv, ALuint,filter, ALenum,param, ALint*,values)
  472. FORCE_ALIGN void AL_APIENTRY alGetFilterivDirect(ALCcontext *context, ALuint filter, ALenum param,
  473. ALint *values) noexcept
  474. try {
  475. switch(param)
  476. {
  477. case AL_FILTER_TYPE:
  478. alGetFilteriDirect(context, filter, param, values);
  479. return;
  480. }
  481. ALCdevice *device{context->mALDevice.get()};
  482. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  483. const ALfilter *alfilt{LookupFilter(device, filter)};
  484. if(!alfilt)
  485. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  486. /* Call the appropriate handler */
  487. std::visit([alfilt,param,values](auto&& thunk){thunk.getParamiv(alfilt, param, values);},
  488. alfilt->mTypeVariant);
  489. }
  490. catch(al::context_error& e) {
  491. context->setError(e.errorCode(), "%s", e.what());
  492. }
  493. AL_API DECL_FUNC3(void, alGetFilterf, ALuint,filter, ALenum,param, ALfloat*,value)
  494. FORCE_ALIGN void AL_APIENTRY alGetFilterfDirect(ALCcontext *context, ALuint filter, ALenum param,
  495. ALfloat *value) noexcept
  496. try {
  497. ALCdevice *device{context->mALDevice.get()};
  498. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  499. const ALfilter *alfilt{LookupFilter(device, filter)};
  500. if(!alfilt) UNLIKELY
  501. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  502. /* Call the appropriate handler */
  503. std::visit([alfilt,param,value](auto&& thunk){thunk.getParamf(alfilt, param, value);},
  504. alfilt->mTypeVariant);
  505. }
  506. catch(al::context_error& e) {
  507. context->setError(e.errorCode(), "%s", e.what());
  508. }
  509. AL_API DECL_FUNC3(void, alGetFilterfv, ALuint,filter, ALenum,param, ALfloat*,values)
  510. FORCE_ALIGN void AL_APIENTRY alGetFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param,
  511. ALfloat *values) noexcept
  512. try {
  513. ALCdevice *device{context->mALDevice.get()};
  514. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  515. const ALfilter *alfilt{LookupFilter(device, filter)};
  516. if(!alfilt) UNLIKELY
  517. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", filter};
  518. /* Call the appropriate handler */
  519. std::visit([alfilt,param,values](auto&& thunk){thunk.getParamfv(alfilt, param, values);},
  520. alfilt->mTypeVariant);
  521. }
  522. catch(al::context_error& e) {
  523. context->setError(e.errorCode(), "%s", e.what());
  524. }
  525. void ALfilter::SetName(ALCcontext *context, ALuint id, std::string_view name)
  526. {
  527. ALCdevice *device{context->mALDevice.get()};
  528. std::lock_guard<std::mutex> filterlock{device->FilterLock};
  529. auto filter = LookupFilter(device, id);
  530. if(!filter)
  531. throw al::context_error{AL_INVALID_NAME, "Invalid filter ID %u", id};
  532. device->mFilterNames.insert_or_assign(id, name);
  533. }
  534. FilterSubList::~FilterSubList()
  535. {
  536. if(!Filters)
  537. return;
  538. uint64_t usemask{~FreeMask};
  539. while(usemask)
  540. {
  541. const int idx{al::countr_zero(usemask)};
  542. std::destroy_at(al::to_address(Filters->begin() + idx));
  543. usemask &= ~(1_u64 << idx);
  544. }
  545. FreeMask = ~usemask;
  546. SubListAllocator{}.deallocate(Filters, 1);
  547. Filters = nullptr;
  548. }