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

449 lines
14 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2000 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 <cmath>
  22. #include "alMain.h"
  23. #include "alcontext.h"
  24. #include "alu.h"
  25. #include "alError.h"
  26. #include "alListener.h"
  27. #include "alSource.h"
  28. #include "alexcpt.h"
  29. #define DO_UPDATEPROPS() do { \
  30. if(!context->DeferUpdates.load(std::memory_order_acquire)) \
  31. UpdateListenerProps(context.get()); \
  32. else \
  33. listener.PropsClean.clear(std::memory_order_release); \
  34. } while(0)
  35. AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
  36. START_API_FUNC
  37. {
  38. ContextRef context{GetContextRef()};
  39. if(UNLIKELY(!context)) return;
  40. ALlistener &listener = context->Listener;
  41. std::lock_guard<std::mutex> _{context->PropLock};
  42. switch(param)
  43. {
  44. case AL_GAIN:
  45. if(!(value >= 0.0f && std::isfinite(value)))
  46. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range");
  47. listener.Gain = value;
  48. DO_UPDATEPROPS();
  49. break;
  50. case AL_METERS_PER_UNIT:
  51. if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
  52. SETERR_RETURN(context.get(), AL_INVALID_VALUE,,
  53. "Listener meters per unit out of range");
  54. context->MetersPerUnit = value;
  55. if(!context->DeferUpdates.load(std::memory_order_acquire))
  56. UpdateContextProps(context.get());
  57. else
  58. context->PropsClean.clear(std::memory_order_release);
  59. break;
  60. default:
  61. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property");
  62. }
  63. }
  64. END_API_FUNC
  65. AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
  66. START_API_FUNC
  67. {
  68. ContextRef context{GetContextRef()};
  69. if(UNLIKELY(!context)) return;
  70. ALlistener &listener = context->Listener;
  71. std::lock_guard<std::mutex> _{context->PropLock};
  72. switch(param)
  73. {
  74. case AL_POSITION:
  75. if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
  76. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range");
  77. listener.Position[0] = value1;
  78. listener.Position[1] = value2;
  79. listener.Position[2] = value3;
  80. DO_UPDATEPROPS();
  81. break;
  82. case AL_VELOCITY:
  83. if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
  84. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range");
  85. listener.Velocity[0] = value1;
  86. listener.Velocity[1] = value2;
  87. listener.Velocity[2] = value3;
  88. DO_UPDATEPROPS();
  89. break;
  90. default:
  91. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property");
  92. }
  93. }
  94. END_API_FUNC
  95. AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
  96. START_API_FUNC
  97. {
  98. if(values)
  99. {
  100. switch(param)
  101. {
  102. case AL_GAIN:
  103. case AL_METERS_PER_UNIT:
  104. alListenerf(param, values[0]);
  105. return;
  106. case AL_POSITION:
  107. case AL_VELOCITY:
  108. alListener3f(param, values[0], values[1], values[2]);
  109. return;
  110. }
  111. }
  112. ContextRef context{GetContextRef()};
  113. if(UNLIKELY(!context)) return;
  114. ALlistener &listener = context->Listener;
  115. std::lock_guard<std::mutex> _{context->PropLock};
  116. if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer");
  117. switch(param)
  118. {
  119. case AL_ORIENTATION:
  120. if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
  121. std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])))
  122. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range");
  123. /* AT then UP */
  124. listener.OrientAt[0] = values[0];
  125. listener.OrientAt[1] = values[1];
  126. listener.OrientAt[2] = values[2];
  127. listener.OrientUp[0] = values[3];
  128. listener.OrientUp[1] = values[4];
  129. listener.OrientUp[2] = values[5];
  130. DO_UPDATEPROPS();
  131. break;
  132. default:
  133. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property");
  134. }
  135. }
  136. END_API_FUNC
  137. AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
  138. START_API_FUNC
  139. {
  140. ContextRef context{GetContextRef()};
  141. if(UNLIKELY(!context)) return;
  142. std::lock_guard<std::mutex> _{context->PropLock};
  143. switch(param)
  144. {
  145. default:
  146. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property");
  147. }
  148. }
  149. END_API_FUNC
  150. AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
  151. START_API_FUNC
  152. {
  153. switch(param)
  154. {
  155. case AL_POSITION:
  156. case AL_VELOCITY:
  157. alListener3f(param, static_cast<ALfloat>(value1), static_cast<ALfloat>(value2), static_cast<ALfloat>(value3));
  158. return;
  159. }
  160. ContextRef context{GetContextRef()};
  161. if(UNLIKELY(!context)) return;
  162. std::lock_guard<std::mutex> _{context->PropLock};
  163. switch(param)
  164. {
  165. default:
  166. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property");
  167. }
  168. }
  169. END_API_FUNC
  170. AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
  171. START_API_FUNC
  172. {
  173. if(values)
  174. {
  175. ALfloat fvals[6];
  176. switch(param)
  177. {
  178. case AL_POSITION:
  179. case AL_VELOCITY:
  180. alListener3f(param, static_cast<ALfloat>(values[0]), static_cast<ALfloat>(values[1]), static_cast<ALfloat>(values[2]));
  181. return;
  182. case AL_ORIENTATION:
  183. fvals[0] = static_cast<ALfloat>(values[0]);
  184. fvals[1] = static_cast<ALfloat>(values[1]);
  185. fvals[2] = static_cast<ALfloat>(values[2]);
  186. fvals[3] = static_cast<ALfloat>(values[3]);
  187. fvals[4] = static_cast<ALfloat>(values[4]);
  188. fvals[5] = static_cast<ALfloat>(values[5]);
  189. alListenerfv(param, fvals);
  190. return;
  191. }
  192. }
  193. ContextRef context{GetContextRef()};
  194. if(UNLIKELY(!context)) return;
  195. std::lock_guard<std::mutex> _{context->PropLock};
  196. if(!values)
  197. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  198. else switch(param)
  199. {
  200. default:
  201. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property");
  202. }
  203. }
  204. END_API_FUNC
  205. AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
  206. START_API_FUNC
  207. {
  208. ContextRef context{GetContextRef()};
  209. if(UNLIKELY(!context)) return;
  210. ALlistener &listener = context->Listener;
  211. std::lock_guard<std::mutex> _{context->PropLock};
  212. if(!value)
  213. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  214. else switch(param)
  215. {
  216. case AL_GAIN:
  217. *value = listener.Gain;
  218. break;
  219. case AL_METERS_PER_UNIT:
  220. *value = context->MetersPerUnit;
  221. break;
  222. default:
  223. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property");
  224. }
  225. }
  226. END_API_FUNC
  227. AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
  228. START_API_FUNC
  229. {
  230. ContextRef context{GetContextRef()};
  231. if(UNLIKELY(!context)) return;
  232. ALlistener &listener = context->Listener;
  233. std::lock_guard<std::mutex> _{context->PropLock};
  234. if(!value1 || !value2 || !value3)
  235. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  236. else switch(param)
  237. {
  238. case AL_POSITION:
  239. *value1 = listener.Position[0];
  240. *value2 = listener.Position[1];
  241. *value3 = listener.Position[2];
  242. break;
  243. case AL_VELOCITY:
  244. *value1 = listener.Velocity[0];
  245. *value2 = listener.Velocity[1];
  246. *value3 = listener.Velocity[2];
  247. break;
  248. default:
  249. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property");
  250. }
  251. }
  252. END_API_FUNC
  253. AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
  254. START_API_FUNC
  255. {
  256. switch(param)
  257. {
  258. case AL_GAIN:
  259. case AL_METERS_PER_UNIT:
  260. alGetListenerf(param, values);
  261. return;
  262. case AL_POSITION:
  263. case AL_VELOCITY:
  264. alGetListener3f(param, values+0, values+1, values+2);
  265. return;
  266. }
  267. ContextRef context{GetContextRef()};
  268. if(UNLIKELY(!context)) return;
  269. ALlistener &listener = context->Listener;
  270. std::lock_guard<std::mutex> _{context->PropLock};
  271. if(!values)
  272. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  273. else switch(param)
  274. {
  275. case AL_ORIENTATION:
  276. // AT then UP
  277. values[0] = listener.OrientAt[0];
  278. values[1] = listener.OrientAt[1];
  279. values[2] = listener.OrientAt[2];
  280. values[3] = listener.OrientUp[0];
  281. values[4] = listener.OrientUp[1];
  282. values[5] = listener.OrientUp[2];
  283. break;
  284. default:
  285. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property");
  286. }
  287. }
  288. END_API_FUNC
  289. AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
  290. START_API_FUNC
  291. {
  292. ContextRef context{GetContextRef()};
  293. if(UNLIKELY(!context)) return;
  294. std::lock_guard<std::mutex> _{context->PropLock};
  295. if(!value)
  296. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  297. else switch(param)
  298. {
  299. default:
  300. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property");
  301. }
  302. }
  303. END_API_FUNC
  304. AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
  305. START_API_FUNC
  306. {
  307. ContextRef context{GetContextRef()};
  308. if(UNLIKELY(!context)) return;
  309. ALlistener &listener = context->Listener;
  310. std::lock_guard<std::mutex> _{context->PropLock};
  311. if(!value1 || !value2 || !value3)
  312. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  313. else switch(param)
  314. {
  315. case AL_POSITION:
  316. *value1 = static_cast<ALint>(listener.Position[0]);
  317. *value2 = static_cast<ALint>(listener.Position[1]);
  318. *value3 = static_cast<ALint>(listener.Position[2]);
  319. break;
  320. case AL_VELOCITY:
  321. *value1 = static_cast<ALint>(listener.Velocity[0]);
  322. *value2 = static_cast<ALint>(listener.Velocity[1]);
  323. *value3 = static_cast<ALint>(listener.Velocity[2]);
  324. break;
  325. default:
  326. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property");
  327. }
  328. }
  329. END_API_FUNC
  330. AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
  331. START_API_FUNC
  332. {
  333. switch(param)
  334. {
  335. case AL_POSITION:
  336. case AL_VELOCITY:
  337. alGetListener3i(param, values+0, values+1, values+2);
  338. return;
  339. }
  340. ContextRef context{GetContextRef()};
  341. if(UNLIKELY(!context)) return;
  342. ALlistener &listener = context->Listener;
  343. std::lock_guard<std::mutex> _{context->PropLock};
  344. if(!values)
  345. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  346. else switch(param)
  347. {
  348. case AL_ORIENTATION:
  349. // AT then UP
  350. values[0] = static_cast<ALint>(listener.OrientAt[0]);
  351. values[1] = static_cast<ALint>(listener.OrientAt[1]);
  352. values[2] = static_cast<ALint>(listener.OrientAt[2]);
  353. values[3] = static_cast<ALint>(listener.OrientUp[0]);
  354. values[4] = static_cast<ALint>(listener.OrientUp[1]);
  355. values[5] = static_cast<ALint>(listener.OrientUp[2]);
  356. break;
  357. default:
  358. alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property");
  359. }
  360. }
  361. END_API_FUNC
  362. void UpdateListenerProps(ALCcontext *context)
  363. {
  364. /* Get an unused proprty container, or allocate a new one as needed. */
  365. ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)};
  366. if(!props)
  367. props = static_cast<ALlistenerProps*>(al_calloc(16, sizeof(*props)));
  368. else
  369. {
  370. ALlistenerProps *next;
  371. do {
  372. next = props->next.load(std::memory_order_relaxed);
  373. } while(context->FreeListenerProps.compare_exchange_weak(props, next,
  374. std::memory_order_seq_cst, std::memory_order_acquire) == 0);
  375. }
  376. /* Copy in current property values. */
  377. ALlistener &listener = context->Listener;
  378. props->Position = listener.Position;
  379. props->Velocity = listener.Velocity;
  380. props->OrientAt = listener.OrientAt;
  381. props->OrientUp = listener.OrientUp;
  382. props->Gain = listener.Gain;
  383. /* Set the new container for updating internal parameters. */
  384. props = listener.Update.exchange(props, std::memory_order_acq_rel);
  385. if(props)
  386. {
  387. /* If there was an unused update container, put it back in the
  388. * freelist.
  389. */
  390. AtomicReplaceHead(context->FreeListenerProps, props);
  391. }
  392. }