🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

717 lines
22 KiB

  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 <new>
  30. #include <numeric>
  31. #include "AL/al.h"
  32. #include "AL/alc.h"
  33. #include "AL/efx.h"
  34. #include "albit.h"
  35. #include "alc/context.h"
  36. #include "alc/device.h"
  37. #include "almalloc.h"
  38. #include "alnumeric.h"
  39. #include "core/except.h"
  40. #include "opthelpers.h"
  41. #include "vector.h"
  42. namespace {
  43. class filter_exception final : public al::base_exception {
  44. ALenum mErrorCode;
  45. public:
  46. #ifdef __USE_MINGW_ANSI_STDIO
  47. [[gnu::format(gnu_printf, 3, 4)]]
  48. #else
  49. [[gnu::format(printf, 3, 4)]]
  50. #endif
  51. filter_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
  52. {
  53. std::va_list args;
  54. va_start(args, msg);
  55. setMessage(msg, args);
  56. va_end(args);
  57. }
  58. ALenum errorCode() const noexcept { return mErrorCode; }
  59. };
  60. #define DEFINE_ALFILTER_VTABLE(T) \
  61. const ALfilter::Vtable T##_vtable = { \
  62. T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \
  63. T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \
  64. }
  65. void ALlowpass_setParami(ALfilter*, ALenum param, int)
  66. { throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
  67. void ALlowpass_setParamiv(ALfilter*, ALenum param, const int*)
  68. {
  69. throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
  70. param};
  71. }
  72. void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val)
  73. {
  74. switch(param)
  75. {
  76. case AL_LOWPASS_GAIN:
  77. if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
  78. throw filter_exception{AL_INVALID_VALUE, "Low-pass gain %f out of range", val};
  79. filter->Gain = val;
  80. break;
  81. case AL_LOWPASS_GAINHF:
  82. if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
  83. throw filter_exception{AL_INVALID_VALUE, "Low-pass gainhf %f out of range", val};
  84. filter->GainHF = val;
  85. break;
  86. default:
  87. throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
  88. }
  89. }
  90. void ALlowpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
  91. { ALlowpass_setParamf(filter, param, vals[0]); }
  92. void ALlowpass_getParami(const ALfilter*, ALenum param, int*)
  93. { throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
  94. void ALlowpass_getParamiv(const ALfilter*, ALenum param, int*)
  95. {
  96. throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
  97. param};
  98. }
  99. void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val)
  100. {
  101. switch(param)
  102. {
  103. case AL_LOWPASS_GAIN:
  104. *val = filter->Gain;
  105. break;
  106. case AL_LOWPASS_GAINHF:
  107. *val = filter->GainHF;
  108. break;
  109. default:
  110. throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
  111. }
  112. }
  113. void ALlowpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
  114. { ALlowpass_getParamf(filter, param, vals); }
  115. DEFINE_ALFILTER_VTABLE(ALlowpass);
  116. void ALhighpass_setParami(ALfilter*, ALenum param, int)
  117. { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
  118. void ALhighpass_setParamiv(ALfilter*, ALenum param, const int*)
  119. {
  120. throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
  121. param};
  122. }
  123. void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val)
  124. {
  125. switch(param)
  126. {
  127. case AL_HIGHPASS_GAIN:
  128. if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
  129. throw filter_exception{AL_INVALID_VALUE, "High-pass gain %f out of range", val};
  130. filter->Gain = val;
  131. break;
  132. case AL_HIGHPASS_GAINLF:
  133. if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
  134. throw filter_exception{AL_INVALID_VALUE, "High-pass gainlf %f out of range", val};
  135. filter->GainLF = val;
  136. break;
  137. default:
  138. throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
  139. }
  140. }
  141. void ALhighpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
  142. { ALhighpass_setParamf(filter, param, vals[0]); }
  143. void ALhighpass_getParami(const ALfilter*, ALenum param, int*)
  144. { throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
  145. void ALhighpass_getParamiv(const ALfilter*, ALenum param, int*)
  146. {
  147. throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
  148. param};
  149. }
  150. void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val)
  151. {
  152. switch(param)
  153. {
  154. case AL_HIGHPASS_GAIN:
  155. *val = filter->Gain;
  156. break;
  157. case AL_HIGHPASS_GAINLF:
  158. *val = filter->GainLF;
  159. break;
  160. default:
  161. throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
  162. }
  163. }
  164. void ALhighpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
  165. { ALhighpass_getParamf(filter, param, vals); }
  166. DEFINE_ALFILTER_VTABLE(ALhighpass);
  167. void ALbandpass_setParami(ALfilter*, ALenum param, int)
  168. { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
  169. void ALbandpass_setParamiv(ALfilter*, ALenum param, const int*)
  170. {
  171. throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
  172. param};
  173. }
  174. void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val)
  175. {
  176. switch(param)
  177. {
  178. case AL_BANDPASS_GAIN:
  179. if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
  180. throw filter_exception{AL_INVALID_VALUE, "Band-pass gain %f out of range", val};
  181. filter->Gain = val;
  182. break;
  183. case AL_BANDPASS_GAINHF:
  184. if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
  185. throw filter_exception{AL_INVALID_VALUE, "Band-pass gainhf %f out of range", val};
  186. filter->GainHF = val;
  187. break;
  188. case AL_BANDPASS_GAINLF:
  189. if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
  190. throw filter_exception{AL_INVALID_VALUE, "Band-pass gainlf %f out of range", val};
  191. filter->GainLF = val;
  192. break;
  193. default:
  194. throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
  195. }
  196. }
  197. void ALbandpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
  198. { ALbandpass_setParamf(filter, param, vals[0]); }
  199. void ALbandpass_getParami(const ALfilter*, ALenum param, int*)
  200. { throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
  201. void ALbandpass_getParamiv(const ALfilter*, ALenum param, int*)
  202. {
  203. throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
  204. param};
  205. }
  206. void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val)
  207. {
  208. switch(param)
  209. {
  210. case AL_BANDPASS_GAIN:
  211. *val = filter->Gain;
  212. break;
  213. case AL_BANDPASS_GAINHF:
  214. *val = filter->GainHF;
  215. break;
  216. case AL_BANDPASS_GAINLF:
  217. *val = filter->GainLF;
  218. break;
  219. default:
  220. throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
  221. }
  222. }
  223. void ALbandpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
  224. { ALbandpass_getParamf(filter, param, vals); }
  225. DEFINE_ALFILTER_VTABLE(ALbandpass);
  226. void ALnullfilter_setParami(ALfilter*, ALenum param, int)
  227. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  228. void ALnullfilter_setParamiv(ALfilter*, ALenum param, const int*)
  229. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  230. void ALnullfilter_setParamf(ALfilter*, ALenum param, float)
  231. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  232. void ALnullfilter_setParamfv(ALfilter*, ALenum param, const float*)
  233. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  234. void ALnullfilter_getParami(const ALfilter*, ALenum param, int*)
  235. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  236. void ALnullfilter_getParamiv(const ALfilter*, ALenum param, int*)
  237. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  238. void ALnullfilter_getParamf(const ALfilter*, ALenum param, float*)
  239. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  240. void ALnullfilter_getParamfv(const ALfilter*, ALenum param, float*)
  241. { throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
  242. DEFINE_ALFILTER_VTABLE(ALnullfilter);
  243. void InitFilterParams(ALfilter *filter, ALenum type)
  244. {
  245. if(type == AL_FILTER_LOWPASS)
  246. {
  247. filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
  248. filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
  249. filter->HFReference = LOWPASSFREQREF;
  250. filter->GainLF = 1.0f;
  251. filter->LFReference = HIGHPASSFREQREF;
  252. filter->vtab = &ALlowpass_vtable;
  253. }
  254. else if(type == AL_FILTER_HIGHPASS)
  255. {
  256. filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
  257. filter->GainHF = 1.0f;
  258. filter->HFReference = LOWPASSFREQREF;
  259. filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
  260. filter->LFReference = HIGHPASSFREQREF;
  261. filter->vtab = &ALhighpass_vtable;
  262. }
  263. else if(type == AL_FILTER_BANDPASS)
  264. {
  265. filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
  266. filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
  267. filter->HFReference = LOWPASSFREQREF;
  268. filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
  269. filter->LFReference = HIGHPASSFREQREF;
  270. filter->vtab = &ALbandpass_vtable;
  271. }
  272. else
  273. {
  274. filter->Gain = 1.0f;
  275. filter->GainHF = 1.0f;
  276. filter->HFReference = LOWPASSFREQREF;
  277. filter->GainLF = 1.0f;
  278. filter->LFReference = HIGHPASSFREQREF;
  279. filter->vtab = &ALnullfilter_vtable;
  280. }
  281. filter->type = type;
  282. }
  283. bool EnsureFilters(ALCdevice *device, size_t needed)
  284. {
  285. size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0},
  286. [](size_t cur, const FilterSubList &sublist) noexcept -> size_t
  287. { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
  288. while(needed > count)
  289. {
  290. if UNLIKELY(device->FilterList.size() >= 1<<25)
  291. return false;
  292. device->FilterList.emplace_back();
  293. auto sublist = device->FilterList.end() - 1;
  294. sublist->FreeMask = ~0_u64;
  295. sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64));
  296. if UNLIKELY(!sublist->Filters)
  297. {
  298. device->FilterList.pop_back();
  299. return false;
  300. }
  301. count += 64;
  302. }
  303. return true;
  304. }
  305. ALfilter *AllocFilter(ALCdevice *device)
  306. {
  307. auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(),
  308. [](const FilterSubList &entry) noexcept -> bool
  309. { return entry.FreeMask != 0; });
  310. auto lidx = static_cast<ALuint>(std::distance(device->FilterList.begin(), sublist));
  311. auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
  312. ASSUME(slidx < 64);
  313. ALfilter *filter{al::construct_at(sublist->Filters + slidx)};
  314. InitFilterParams(filter, AL_FILTER_NULL);
  315. /* Add 1 to avoid filter ID 0. */
  316. filter->id = ((lidx<<6) | slidx) + 1;
  317. sublist->FreeMask &= ~(1_u64 << slidx);
  318. return filter;
  319. }
  320. void FreeFilter(ALCdevice *device, ALfilter *filter)
  321. {
  322. const ALuint id{filter->id - 1};
  323. const size_t lidx{id >> 6};
  324. const ALuint slidx{id & 0x3f};
  325. al::destroy_at(filter);
  326. device->FilterList[lidx].FreeMask |= 1_u64 << slidx;
  327. }
  328. inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
  329. {
  330. const size_t lidx{(id-1) >> 6};
  331. const ALuint slidx{(id-1) & 0x3f};
  332. if UNLIKELY(lidx >= device->FilterList.size())
  333. return nullptr;
  334. FilterSubList &sublist = device->FilterList[lidx];
  335. if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
  336. return nullptr;
  337. return sublist.Filters + slidx;
  338. }
  339. } // namespace
  340. AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
  341. START_API_FUNC
  342. {
  343. ContextRef context{GetContextRef()};
  344. if UNLIKELY(!context) return;
  345. if UNLIKELY(n < 0)
  346. context->setError(AL_INVALID_VALUE, "Generating %d filters", n);
  347. if UNLIKELY(n <= 0) return;
  348. ALCdevice *device{context->mALDevice.get()};
  349. std::lock_guard<std::mutex> _{device->FilterLock};
  350. if(!EnsureFilters(device, static_cast<ALuint>(n)))
  351. {
  352. context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d filter%s", n, (n==1)?"":"s");
  353. return;
  354. }
  355. if LIKELY(n == 1)
  356. {
  357. /* Special handling for the easy and normal case. */
  358. ALfilter *filter{AllocFilter(device)};
  359. if(filter) filters[0] = filter->id;
  360. }
  361. else
  362. {
  363. /* Store the allocated buffer IDs in a separate local list, to avoid
  364. * modifying the user storage in case of failure.
  365. */
  366. al::vector<ALuint> ids;
  367. ids.reserve(static_cast<ALuint>(n));
  368. do {
  369. ALfilter *filter{AllocFilter(device)};
  370. ids.emplace_back(filter->id);
  371. } while(--n);
  372. std::copy(ids.begin(), ids.end(), filters);
  373. }
  374. }
  375. END_API_FUNC
  376. AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
  377. START_API_FUNC
  378. {
  379. ContextRef context{GetContextRef()};
  380. if UNLIKELY(!context) return;
  381. if UNLIKELY(n < 0)
  382. context->setError(AL_INVALID_VALUE, "Deleting %d filters", n);
  383. if UNLIKELY(n <= 0) return;
  384. ALCdevice *device{context->mALDevice.get()};
  385. std::lock_guard<std::mutex> _{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; };
  389. const ALuint *filters_end = filters + n;
  390. auto invflt = std::find_if_not(filters, filters_end, validate_filter);
  391. if UNLIKELY(invflt != filters_end)
  392. {
  393. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", *invflt);
  394. return;
  395. }
  396. /* All good. Delete non-0 filter IDs. */
  397. auto delete_filter = [device](const ALuint fid) -> void
  398. {
  399. ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr};
  400. if(filter) FreeFilter(device, filter);
  401. };
  402. std::for_each(filters, filters_end, delete_filter);
  403. }
  404. END_API_FUNC
  405. AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
  406. START_API_FUNC
  407. {
  408. ContextRef context{GetContextRef()};
  409. if LIKELY(context)
  410. {
  411. ALCdevice *device{context->mALDevice.get()};
  412. std::lock_guard<std::mutex> _{device->FilterLock};
  413. if(!filter || LookupFilter(device, filter))
  414. return AL_TRUE;
  415. }
  416. return AL_FALSE;
  417. }
  418. END_API_FUNC
  419. AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
  420. START_API_FUNC
  421. {
  422. ContextRef context{GetContextRef()};
  423. if UNLIKELY(!context) return;
  424. ALCdevice *device{context->mALDevice.get()};
  425. std::lock_guard<std::mutex> _{device->FilterLock};
  426. ALfilter *alfilt{LookupFilter(device, filter)};
  427. if UNLIKELY(!alfilt)
  428. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  429. else
  430. {
  431. if(param == AL_FILTER_TYPE)
  432. {
  433. if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS
  434. || value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
  435. InitFilterParams(alfilt, value);
  436. else
  437. context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
  438. }
  439. else try
  440. {
  441. /* Call the appropriate handler */
  442. alfilt->setParami(param, value);
  443. }
  444. catch(filter_exception &e) {
  445. context->setError(e.errorCode(), "%s", e.what());
  446. }
  447. }
  448. }
  449. END_API_FUNC
  450. AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
  451. START_API_FUNC
  452. {
  453. switch(param)
  454. {
  455. case AL_FILTER_TYPE:
  456. alFilteri(filter, param, values[0]);
  457. return;
  458. }
  459. ContextRef context{GetContextRef()};
  460. if UNLIKELY(!context) return;
  461. ALCdevice *device{context->mALDevice.get()};
  462. std::lock_guard<std::mutex> _{device->FilterLock};
  463. ALfilter *alfilt{LookupFilter(device, filter)};
  464. if UNLIKELY(!alfilt)
  465. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  466. else try
  467. {
  468. /* Call the appropriate handler */
  469. alfilt->setParamiv(param, values);
  470. }
  471. catch(filter_exception &e) {
  472. context->setError(e.errorCode(), "%s", e.what());
  473. }
  474. }
  475. END_API_FUNC
  476. AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
  477. START_API_FUNC
  478. {
  479. ContextRef context{GetContextRef()};
  480. if UNLIKELY(!context) return;
  481. ALCdevice *device{context->mALDevice.get()};
  482. std::lock_guard<std::mutex> _{device->FilterLock};
  483. ALfilter *alfilt{LookupFilter(device, filter)};
  484. if UNLIKELY(!alfilt)
  485. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  486. else try
  487. {
  488. /* Call the appropriate handler */
  489. alfilt->setParamf(param, value);
  490. }
  491. catch(filter_exception &e) {
  492. context->setError(e.errorCode(), "%s", e.what());
  493. }
  494. }
  495. END_API_FUNC
  496. AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
  497. START_API_FUNC
  498. {
  499. ContextRef context{GetContextRef()};
  500. if UNLIKELY(!context) return;
  501. ALCdevice *device{context->mALDevice.get()};
  502. std::lock_guard<std::mutex> _{device->FilterLock};
  503. ALfilter *alfilt{LookupFilter(device, filter)};
  504. if UNLIKELY(!alfilt)
  505. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  506. else try
  507. {
  508. /* Call the appropriate handler */
  509. alfilt->setParamfv(param, values);
  510. }
  511. catch(filter_exception &e) {
  512. context->setError(e.errorCode(), "%s", e.what());
  513. }
  514. }
  515. END_API_FUNC
  516. AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
  517. START_API_FUNC
  518. {
  519. ContextRef context{GetContextRef()};
  520. if UNLIKELY(!context) return;
  521. ALCdevice *device{context->mALDevice.get()};
  522. std::lock_guard<std::mutex> _{device->FilterLock};
  523. const ALfilter *alfilt{LookupFilter(device, filter)};
  524. if UNLIKELY(!alfilt)
  525. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  526. else
  527. {
  528. if(param == AL_FILTER_TYPE)
  529. *value = alfilt->type;
  530. else try
  531. {
  532. /* Call the appropriate handler */
  533. alfilt->getParami(param, value);
  534. }
  535. catch(filter_exception &e) {
  536. context->setError(e.errorCode(), "%s", e.what());
  537. }
  538. }
  539. }
  540. END_API_FUNC
  541. AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
  542. START_API_FUNC
  543. {
  544. switch(param)
  545. {
  546. case AL_FILTER_TYPE:
  547. alGetFilteri(filter, param, values);
  548. return;
  549. }
  550. ContextRef context{GetContextRef()};
  551. if UNLIKELY(!context) return;
  552. ALCdevice *device{context->mALDevice.get()};
  553. std::lock_guard<std::mutex> _{device->FilterLock};
  554. const ALfilter *alfilt{LookupFilter(device, filter)};
  555. if UNLIKELY(!alfilt)
  556. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  557. else try
  558. {
  559. /* Call the appropriate handler */
  560. alfilt->getParamiv(param, values);
  561. }
  562. catch(filter_exception &e) {
  563. context->setError(e.errorCode(), "%s", e.what());
  564. }
  565. }
  566. END_API_FUNC
  567. AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
  568. START_API_FUNC
  569. {
  570. ContextRef context{GetContextRef()};
  571. if UNLIKELY(!context) return;
  572. ALCdevice *device{context->mALDevice.get()};
  573. std::lock_guard<std::mutex> _{device->FilterLock};
  574. const ALfilter *alfilt{LookupFilter(device, filter)};
  575. if UNLIKELY(!alfilt)
  576. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  577. else try
  578. {
  579. /* Call the appropriate handler */
  580. alfilt->getParamf(param, value);
  581. }
  582. catch(filter_exception &e) {
  583. context->setError(e.errorCode(), "%s", e.what());
  584. }
  585. }
  586. END_API_FUNC
  587. AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
  588. START_API_FUNC
  589. {
  590. ContextRef context{GetContextRef()};
  591. if UNLIKELY(!context) return;
  592. ALCdevice *device{context->mALDevice.get()};
  593. std::lock_guard<std::mutex> _{device->FilterLock};
  594. const ALfilter *alfilt{LookupFilter(device, filter)};
  595. if UNLIKELY(!alfilt)
  596. context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
  597. else try
  598. {
  599. /* Call the appropriate handler */
  600. alfilt->getParamfv(param, values);
  601. }
  602. catch(filter_exception &e) {
  603. context->setError(e.errorCode(), "%s", e.what());
  604. }
  605. }
  606. END_API_FUNC
  607. FilterSubList::~FilterSubList()
  608. {
  609. uint64_t usemask{~FreeMask};
  610. while(usemask)
  611. {
  612. const int idx{al::countr_zero(usemask)};
  613. al::destroy_at(Filters+idx);
  614. usemask &= ~(1_u64 << idx);
  615. }
  616. FreeMask = ~usemask;
  617. al_free(Filters);
  618. Filters = nullptr;
  619. }