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