🛠️🐜 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.

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