listener.cpp 14 KB

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