filter.cpp 21 KB

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