context.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. #include "config.h"
  2. #include "context.h"
  3. #include <algorithm>
  4. #include <array>
  5. #include <cstddef>
  6. #include <functional>
  7. #include <iterator>
  8. #include <numeric>
  9. #include <optional>
  10. #include <string_view>
  11. #include <tuple>
  12. #include <utility>
  13. #include "AL/efx.h"
  14. #include "al/auxeffectslot.h"
  15. #include "al/debug.h"
  16. #include "al/source.h"
  17. #include "al/effect.h"
  18. #include "al/event.h"
  19. #include "al/listener.h"
  20. #include "albit.h"
  21. #include "alc/alu.h"
  22. #include "alc/backends/base.h"
  23. #include "alnumeric.h"
  24. #include "alspan.h"
  25. #include "atomic.h"
  26. #include "core/async_event.h"
  27. #include "core/devformat.h"
  28. #include "core/device.h"
  29. #include "core/effectslot.h"
  30. #include "core/logging.h"
  31. #include "core/voice_change.h"
  32. #include "device.h"
  33. #include "flexarray.h"
  34. #include "ringbuffer.h"
  35. #include "vecmat.h"
  36. #if ALSOFT_EAX
  37. #include "al/eax/call.h"
  38. #include "al/eax/globals.h"
  39. #endif // ALSOFT_EAX
  40. namespace {
  41. using namespace std::string_view_literals;
  42. using voidp = void*;
  43. /* Default context extensions */
  44. std::vector<std::string_view> getContextExtensions() noexcept
  45. {
  46. return std::vector<std::string_view>{
  47. "AL_EXT_ALAW"sv,
  48. "AL_EXT_BFORMAT"sv,
  49. "AL_EXT_debug"sv,
  50. "AL_EXT_direct_context"sv,
  51. "AL_EXT_DOUBLE"sv,
  52. "AL_EXT_EXPONENT_DISTANCE"sv,
  53. "AL_EXT_FLOAT32"sv,
  54. "AL_EXT_IMA4"sv,
  55. "AL_EXT_LINEAR_DISTANCE"sv,
  56. "AL_EXT_MCFORMATS"sv,
  57. "AL_EXT_MULAW"sv,
  58. "AL_EXT_MULAW_BFORMAT"sv,
  59. "AL_EXT_MULAW_MCFORMATS"sv,
  60. "AL_EXT_OFFSET"sv,
  61. "AL_EXT_source_distance_model"sv,
  62. "AL_EXT_SOURCE_RADIUS"sv,
  63. "AL_EXT_STATIC_BUFFER"sv,
  64. "AL_EXT_STEREO_ANGLES"sv,
  65. "AL_LOKI_quadriphonic"sv,
  66. "AL_SOFT_bformat_ex"sv,
  67. "AL_SOFT_bformat_hoa"sv,
  68. "AL_SOFT_block_alignment"sv,
  69. "AL_SOFT_buffer_length_query"sv,
  70. "AL_SOFT_callback_buffer"sv,
  71. "AL_SOFTX_convolution_effect"sv,
  72. "AL_SOFT_deferred_updates"sv,
  73. "AL_SOFT_direct_channels"sv,
  74. "AL_SOFT_direct_channels_remix"sv,
  75. "AL_SOFT_effect_target"sv,
  76. "AL_SOFT_events"sv,
  77. "AL_SOFT_gain_clamp_ex"sv,
  78. "AL_SOFTX_hold_on_disconnect"sv,
  79. "AL_SOFT_loop_points"sv,
  80. "AL_SOFTX_map_buffer"sv,
  81. "AL_SOFT_MSADPCM"sv,
  82. "AL_SOFT_source_latency"sv,
  83. "AL_SOFT_source_length"sv,
  84. "AL_SOFTX_source_panning"sv,
  85. "AL_SOFT_source_resampler"sv,
  86. "AL_SOFT_source_spatialize"sv,
  87. "AL_SOFT_source_start_delay"sv,
  88. "AL_SOFT_UHJ"sv,
  89. "AL_SOFT_UHJ_ex"sv,
  90. };
  91. }
  92. } // namespace
  93. std::atomic<bool> ALCcontext::sGlobalContextLock{false};
  94. std::atomic<ALCcontext*> ALCcontext::sGlobalContext{nullptr};
  95. ALCcontext::ThreadCtx::~ThreadCtx()
  96. {
  97. if(ALCcontext *ctx{std::exchange(ALCcontext::sLocalContext, nullptr)})
  98. {
  99. const bool result{ctx->releaseIfNoDelete()};
  100. ERR("Context {} current for thread being destroyed{}!", voidp{ctx},
  101. result ? "" : ", leak detected");
  102. }
  103. }
  104. thread_local ALCcontext::ThreadCtx ALCcontext::sThreadContext;
  105. ALeffect ALCcontext::sDefaultEffect;
  106. ALCcontext::ALCcontext(al::intrusive_ptr<al::Device> device, ContextFlagBitset flags)
  107. : ContextBase{device.get()}, mALDevice{std::move(device)}, mContextFlags{flags}
  108. {
  109. mDebugGroups.emplace_back(DebugSource::Other, 0, std::string{});
  110. mDebugEnabled.store(mContextFlags.test(ContextFlags::DebugBit), std::memory_order_relaxed);
  111. /* Low-severity debug messages are disabled by default. */
  112. alDebugMessageControlDirectEXT(this, AL_DONT_CARE_EXT, AL_DONT_CARE_EXT,
  113. AL_DEBUG_SEVERITY_LOW_EXT, 0, nullptr, AL_FALSE);
  114. }
  115. ALCcontext::~ALCcontext()
  116. {
  117. TRACE("Freeing context {}", voidp{this});
  118. size_t count{std::accumulate(mSourceList.cbegin(), mSourceList.cend(), 0_uz,
  119. [](size_t cur, const SourceSubList &sublist) noexcept -> size_t
  120. { return cur + static_cast<uint>(al::popcount(~sublist.FreeMask)); })};
  121. if(count > 0)
  122. WARN("{} Source{} not deleted", count, (count==1)?"":"s");
  123. mSourceList.clear();
  124. mNumSources = 0;
  125. #if ALSOFT_EAX
  126. eaxUninitialize();
  127. #endif // ALSOFT_EAX
  128. mDefaultSlot = nullptr;
  129. count = std::accumulate(mEffectSlotList.cbegin(), mEffectSlotList.cend(), 0_uz,
  130. [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t
  131. { return cur + static_cast<uint>(al::popcount(~sublist.FreeMask)); });
  132. if(count > 0)
  133. WARN("{} AuxiliaryEffectSlot{} not deleted", count, (count==1)?"":"s");
  134. mEffectSlotList.clear();
  135. mNumEffectSlots = 0;
  136. }
  137. void ALCcontext::init()
  138. {
  139. if(sDefaultEffect.type != AL_EFFECT_NULL && mDevice->Type == DeviceType::Playback)
  140. {
  141. mDefaultSlot = std::make_unique<ALeffectslot>(this);
  142. aluInitEffectPanning(mDefaultSlot->mSlot, this);
  143. }
  144. std::unique_ptr<EffectSlotArray> auxslots;
  145. if(!mDefaultSlot)
  146. auxslots = EffectSlot::CreatePtrArray(0);
  147. else
  148. {
  149. auxslots = EffectSlot::CreatePtrArray(2);
  150. (*auxslots)[0] = mDefaultSlot->mSlot;
  151. (*auxslots)[1] = mDefaultSlot->mSlot;
  152. mDefaultSlot->mState = SlotState::Playing;
  153. }
  154. mActiveAuxSlots.store(std::move(auxslots), std::memory_order_relaxed);
  155. allocVoiceChanges();
  156. {
  157. VoiceChange *cur{mVoiceChangeTail};
  158. while(VoiceChange *next{cur->mNext.load(std::memory_order_relaxed)})
  159. cur = next;
  160. mCurrentVoiceChange.store(cur, std::memory_order_relaxed);
  161. }
  162. mExtensions = getContextExtensions();
  163. if(sBufferSubDataCompat)
  164. {
  165. auto iter = std::find(mExtensions.begin(), mExtensions.end(), "AL_EXT_SOURCE_RADIUS"sv);
  166. if(iter != mExtensions.end()) mExtensions.erase(iter);
  167. /* Insert the AL_SOFT_buffer_sub_data extension string between
  168. * AL_SOFT_buffer_length_query and AL_SOFT_callback_buffer.
  169. */
  170. iter = std::find(mExtensions.begin(), mExtensions.end(), "AL_SOFT_callback_buffer"sv);
  171. mExtensions.emplace(iter, "AL_SOFT_buffer_sub_data"sv);
  172. }
  173. #if ALSOFT_EAX
  174. eax_initialize_extensions();
  175. #endif // ALSOFT_EAX
  176. if(!mExtensions.empty())
  177. {
  178. const size_t len{std::accumulate(mExtensions.cbegin()+1, mExtensions.cend(),
  179. mExtensions.front().length(),
  180. [](size_t current, std::string_view ext) noexcept
  181. { return current + ext.length() + 1; })};
  182. std::string extensions;
  183. extensions.reserve(len);
  184. extensions += mExtensions.front();
  185. for(std::string_view ext : al::span{mExtensions}.subspan<1>())
  186. {
  187. extensions += ' ';
  188. extensions += ext;
  189. }
  190. mExtensionsString = std::move(extensions);
  191. }
  192. #if ALSOFT_EAX
  193. eax_set_defaults();
  194. #endif
  195. mParams.Position = alu::Vector{0.0f, 0.0f, 0.0f, 1.0f};
  196. mParams.Matrix = alu::Matrix::Identity();
  197. mParams.Velocity = alu::Vector{};
  198. mParams.Gain = mListener.Gain;
  199. mParams.MetersPerUnit = mListener.mMetersPerUnit
  200. #if ALSOFT_EAX
  201. * eaxGetDistanceFactor()
  202. #endif
  203. ;
  204. mParams.AirAbsorptionGainHF = mAirAbsorptionGainHF;
  205. mParams.DopplerFactor = mDopplerFactor;
  206. mParams.SpeedOfSound = mSpeedOfSound * mDopplerVelocity
  207. #if ALSOFT_EAX
  208. / eaxGetDistanceFactor()
  209. #endif
  210. ;
  211. mParams.SourceDistanceModel = mSourceDistanceModel;
  212. mParams.mDistanceModel = mDistanceModel;
  213. mAsyncEvents = RingBuffer::Create(1024, sizeof(AsyncEvent), false);
  214. StartEventThrd(this);
  215. allocVoices(256);
  216. mActiveVoiceCount.store(64, std::memory_order_relaxed);
  217. }
  218. void ALCcontext::deinit()
  219. {
  220. if(sLocalContext == this)
  221. {
  222. WARN("{} released while current on thread", voidp{this});
  223. auto _ = ContextRef{sLocalContext};
  224. sThreadContext.set(nullptr);
  225. }
  226. if(ALCcontext *origctx{this}; sGlobalContext.compare_exchange_strong(origctx, nullptr))
  227. {
  228. auto _ = ContextRef{origctx};
  229. while(sGlobalContextLock.load()) {
  230. /* Wait to make sure another thread didn't get the context and is
  231. * trying to increment its refcount.
  232. */
  233. }
  234. }
  235. bool stopPlayback{};
  236. /* First make sure this context exists in the device's list. */
  237. auto oldarray = al::span{*mDevice->mContexts.load(std::memory_order_acquire)};
  238. if(auto toremove = static_cast<size_t>(std::count(oldarray.begin(), oldarray.end(), this)))
  239. {
  240. using ContextArray = al::FlexArray<ContextBase*>;
  241. const auto newsize = size_t{oldarray.size() - toremove};
  242. auto newarray = ContextArray::Create(newsize);
  243. /* Copy the current/old context handles to the new array, excluding the
  244. * given context.
  245. */
  246. std::copy_if(oldarray.begin(), oldarray.end(), newarray->begin(),
  247. [this](ContextBase *ctx) { return ctx != this; });
  248. /* Store the new context array in the device. Wait for any current mix
  249. * to finish before deleting the old array.
  250. */
  251. auto prevarray = mDevice->mContexts.exchange(std::move(newarray));
  252. std::ignore = mDevice->waitForMix();
  253. stopPlayback = (newsize == 0);
  254. }
  255. else
  256. stopPlayback = oldarray.empty();
  257. StopEventThrd(this);
  258. if(stopPlayback && mALDevice->mDeviceState == DeviceState::Playing)
  259. {
  260. mALDevice->Backend->stop();
  261. mALDevice->mDeviceState = DeviceState::Configured;
  262. }
  263. }
  264. void ALCcontext::applyAllUpdates()
  265. {
  266. /* Tell the mixer to stop applying updates, then wait for any active
  267. * updating to finish, before providing updates.
  268. */
  269. mHoldUpdates.store(true, std::memory_order_release);
  270. while((mUpdateCount.load(std::memory_order_acquire)&1) != 0) {
  271. /* busy-wait */
  272. }
  273. #if ALSOFT_EAX
  274. if(mEaxNeedsCommit)
  275. eaxCommit();
  276. #endif
  277. if(std::exchange(mPropsDirty, false))
  278. UpdateContextProps(this);
  279. UpdateAllEffectSlotProps(this);
  280. UpdateAllSourceProps(this);
  281. /* Now with all updates declared, let the mixer continue applying them so
  282. * they all happen at once.
  283. */
  284. mHoldUpdates.store(false, std::memory_order_release);
  285. }
  286. #if ALSOFT_EAX
  287. namespace {
  288. template<typename F>
  289. void ForEachSource(ALCcontext *context, F func)
  290. {
  291. for(auto &sublist : context->mSourceList)
  292. {
  293. uint64_t usemask{~sublist.FreeMask};
  294. while(usemask)
  295. {
  296. const auto idx = static_cast<uint>(al::countr_zero(usemask));
  297. usemask &= ~(1_u64 << idx);
  298. func((*sublist.Sources)[idx]);
  299. }
  300. }
  301. }
  302. } // namespace
  303. bool ALCcontext::eaxIsCapable() const noexcept
  304. {
  305. return eax_has_enough_aux_sends();
  306. }
  307. void ALCcontext::eaxUninitialize() noexcept
  308. {
  309. if(!mEaxIsInitialized)
  310. return;
  311. mEaxIsInitialized = false;
  312. mEaxIsTried = false;
  313. mEaxFxSlots.uninitialize();
  314. }
  315. ALenum ALCcontext::eax_eax_set(
  316. const GUID* property_set_id,
  317. ALuint property_id,
  318. ALuint property_source_id,
  319. ALvoid* property_value,
  320. ALuint property_value_size)
  321. {
  322. const auto call = create_eax_call(
  323. EaxCallType::set,
  324. property_set_id,
  325. property_id,
  326. property_source_id,
  327. property_value,
  328. property_value_size);
  329. eax_initialize();
  330. switch(call.get_property_set_id())
  331. {
  332. case EaxCallPropertySetId::context:
  333. eax_set(call);
  334. break;
  335. case EaxCallPropertySetId::fx_slot:
  336. case EaxCallPropertySetId::fx_slot_effect:
  337. eax_dispatch_fx_slot(call);
  338. break;
  339. case EaxCallPropertySetId::source:
  340. eax_dispatch_source(call);
  341. break;
  342. default:
  343. eax_fail_unknown_property_set_id();
  344. }
  345. mEaxNeedsCommit = true;
  346. if(!call.is_deferred())
  347. {
  348. eaxCommit();
  349. if(!mDeferUpdates)
  350. applyAllUpdates();
  351. }
  352. return AL_NO_ERROR;
  353. }
  354. ALenum ALCcontext::eax_eax_get(
  355. const GUID* property_set_id,
  356. ALuint property_id,
  357. ALuint property_source_id,
  358. ALvoid* property_value,
  359. ALuint property_value_size)
  360. {
  361. const auto call = create_eax_call(
  362. EaxCallType::get,
  363. property_set_id,
  364. property_id,
  365. property_source_id,
  366. property_value,
  367. property_value_size);
  368. eax_initialize();
  369. switch(call.get_property_set_id())
  370. {
  371. case EaxCallPropertySetId::context:
  372. eax_get(call);
  373. break;
  374. case EaxCallPropertySetId::fx_slot:
  375. case EaxCallPropertySetId::fx_slot_effect:
  376. eax_dispatch_fx_slot(call);
  377. break;
  378. case EaxCallPropertySetId::source:
  379. eax_dispatch_source(call);
  380. break;
  381. default:
  382. eax_fail_unknown_property_set_id();
  383. }
  384. return AL_NO_ERROR;
  385. }
  386. void ALCcontext::eaxSetLastError() noexcept
  387. {
  388. mEaxLastError = EAXERR_INVALID_OPERATION;
  389. }
  390. [[noreturn]] void ALCcontext::eax_fail(const char* message)
  391. {
  392. throw ContextException{message};
  393. }
  394. [[noreturn]] void ALCcontext::eax_fail_unknown_property_set_id()
  395. {
  396. eax_fail("Unknown property ID.");
  397. }
  398. [[noreturn]] void ALCcontext::eax_fail_unknown_primary_fx_slot_id()
  399. {
  400. eax_fail("Unknown primary FX Slot ID.");
  401. }
  402. [[noreturn]] void ALCcontext::eax_fail_unknown_property_id()
  403. {
  404. eax_fail("Unknown property ID.");
  405. }
  406. [[noreturn]] void ALCcontext::eax_fail_unknown_version()
  407. {
  408. eax_fail("Unknown version.");
  409. }
  410. void ALCcontext::eax_initialize_extensions()
  411. {
  412. if(!eax_g_is_enabled)
  413. return;
  414. mExtensions.emplace(mExtensions.begin(), "EAX-RAM"sv);
  415. if(eaxIsCapable())
  416. {
  417. mExtensions.emplace(mExtensions.begin(), "EAX5.0"sv);
  418. mExtensions.emplace(mExtensions.begin(), "EAX4.0"sv);
  419. mExtensions.emplace(mExtensions.begin(), "EAX3.0"sv);
  420. mExtensions.emplace(mExtensions.begin(), "EAX2.0"sv);
  421. mExtensions.emplace(mExtensions.begin(), "EAX"sv);
  422. }
  423. }
  424. void ALCcontext::eax_initialize()
  425. {
  426. if(mEaxIsInitialized)
  427. return;
  428. if(mEaxIsTried)
  429. eax_fail("No EAX.");
  430. mEaxIsTried = true;
  431. if(!eax_g_is_enabled)
  432. eax_fail("EAX disabled by a configuration.");
  433. eax_ensure_compatibility();
  434. eax_set_defaults();
  435. eax_context_commit_air_absorption_hf();
  436. eax_update_speaker_configuration();
  437. eax_initialize_fx_slots();
  438. mEaxIsInitialized = true;
  439. }
  440. bool ALCcontext::eax_has_no_default_effect_slot() const noexcept
  441. {
  442. return mDefaultSlot == nullptr;
  443. }
  444. void ALCcontext::eax_ensure_no_default_effect_slot() const
  445. {
  446. if(!eax_has_no_default_effect_slot())
  447. eax_fail("There is a default effect slot in the context.");
  448. }
  449. bool ALCcontext::eax_has_enough_aux_sends() const noexcept
  450. {
  451. return mALDevice->NumAuxSends >= EAX_MAX_FXSLOTS;
  452. }
  453. void ALCcontext::eax_ensure_enough_aux_sends() const
  454. {
  455. if(!eax_has_enough_aux_sends())
  456. eax_fail("Not enough aux sends.");
  457. }
  458. void ALCcontext::eax_ensure_compatibility()
  459. {
  460. eax_ensure_enough_aux_sends();
  461. }
  462. unsigned long ALCcontext::eax_detect_speaker_configuration() const
  463. {
  464. #define EAX_PREFIX "[EAX_DETECT_SPEAKER_CONFIG]"
  465. switch(mDevice->FmtChans)
  466. {
  467. case DevFmtMono: return SPEAKERS_2;
  468. case DevFmtStereo:
  469. /* Pretend 7.1 if using UHJ output, since they both provide full
  470. * horizontal surround.
  471. */
  472. if(mDevice->mUhjEncoder)
  473. return SPEAKERS_7;
  474. if(mDevice->Flags.test(DirectEar))
  475. return HEADPHONES;
  476. return SPEAKERS_2;
  477. case DevFmtQuad: return SPEAKERS_4;
  478. case DevFmtX51: return SPEAKERS_5;
  479. case DevFmtX61: return SPEAKERS_6;
  480. case DevFmtX71: return SPEAKERS_7;
  481. /* 7.1.4(.4) is compatible with 7.1. This could instead be HEADPHONES to
  482. * suggest with-height surround sound (like HRTF).
  483. */
  484. case DevFmtX714: return SPEAKERS_7;
  485. case DevFmtX7144: return SPEAKERS_7;
  486. /* 3D7.1 is only compatible with 5.1. This could instead be HEADPHONES to
  487. * suggest full-sphere surround sound (like HRTF).
  488. */
  489. case DevFmtX3D71: return SPEAKERS_5;
  490. /* This could also be HEADPHONES, since headphones-based HRTF and Ambi3D
  491. * provide full-sphere surround sound. Depends if apps are more likely to
  492. * consider headphones or 7.1 for surround sound support.
  493. */
  494. case DevFmtAmbi3D: return SPEAKERS_7;
  495. }
  496. ERR(EAX_PREFIX "Unexpected device channel format {:#x}.",
  497. uint{al::to_underlying(mDevice->FmtChans)});
  498. return HEADPHONES;
  499. #undef EAX_PREFIX
  500. }
  501. void ALCcontext::eax_update_speaker_configuration()
  502. {
  503. mEaxSpeakerConfig = eax_detect_speaker_configuration();
  504. }
  505. void ALCcontext::eax_set_last_error_defaults() noexcept
  506. {
  507. mEaxLastError = EAXCONTEXT_DEFAULTLASTERROR;
  508. }
  509. void ALCcontext::eax_session_set_defaults() noexcept
  510. {
  511. mEaxSession.ulEAXVersion = EAXCONTEXT_DEFAULTEAXSESSION;
  512. mEaxSession.ulMaxActiveSends = EAXCONTEXT_DEFAULTMAXACTIVESENDS;
  513. }
  514. void ALCcontext::eax4_context_set_defaults(Eax4Props& props) noexcept
  515. {
  516. props.guidPrimaryFXSlotID = EAX40CONTEXT_DEFAULTPRIMARYFXSLOTID;
  517. props.flDistanceFactor = EAXCONTEXT_DEFAULTDISTANCEFACTOR;
  518. props.flAirAbsorptionHF = EAXCONTEXT_DEFAULTAIRABSORPTIONHF;
  519. props.flHFReference = EAXCONTEXT_DEFAULTHFREFERENCE;
  520. }
  521. void ALCcontext::eax4_context_set_defaults(Eax4State& state) noexcept
  522. {
  523. eax4_context_set_defaults(state.i);
  524. state.d = state.i;
  525. }
  526. void ALCcontext::eax5_context_set_defaults(Eax5Props& props) noexcept
  527. {
  528. props.guidPrimaryFXSlotID = EAX50CONTEXT_DEFAULTPRIMARYFXSLOTID;
  529. props.flDistanceFactor = EAXCONTEXT_DEFAULTDISTANCEFACTOR;
  530. props.flAirAbsorptionHF = EAXCONTEXT_DEFAULTAIRABSORPTIONHF;
  531. props.flHFReference = EAXCONTEXT_DEFAULTHFREFERENCE;
  532. props.flMacroFXFactor = EAXCONTEXT_DEFAULTMACROFXFACTOR;
  533. }
  534. void ALCcontext::eax5_context_set_defaults(Eax5State& state) noexcept
  535. {
  536. eax5_context_set_defaults(state.i);
  537. state.d = state.i;
  538. }
  539. void ALCcontext::eax_context_set_defaults()
  540. {
  541. eax5_context_set_defaults(mEax123);
  542. eax4_context_set_defaults(mEax4);
  543. eax5_context_set_defaults(mEax5);
  544. mEax = mEax5.i;
  545. mEaxVersion = 5;
  546. mEaxDf.reset();
  547. }
  548. void ALCcontext::eax_set_defaults()
  549. {
  550. eax_set_last_error_defaults();
  551. eax_session_set_defaults();
  552. eax_context_set_defaults();
  553. }
  554. void ALCcontext::eax_dispatch_fx_slot(const EaxCall& call)
  555. {
  556. const auto fx_slot_index = call.get_fx_slot_index();
  557. if(!fx_slot_index.has_value())
  558. eax_fail("Invalid fx slot index.");
  559. auto& fx_slot = eaxGetFxSlot(*fx_slot_index);
  560. if(fx_slot.eax_dispatch(call))
  561. {
  562. std::lock_guard<std::mutex> source_lock{mSourceLock};
  563. ForEachSource(this, std::mem_fn(&ALsource::eaxMarkAsChanged));
  564. }
  565. }
  566. void ALCcontext::eax_dispatch_source(const EaxCall& call)
  567. {
  568. const auto source_id = call.get_property_al_name();
  569. std::lock_guard<std::mutex> source_lock{mSourceLock};
  570. const auto source = ALsource::EaxLookupSource(*this, source_id);
  571. if (source == nullptr)
  572. eax_fail("Source not found.");
  573. source->eaxDispatch(call);
  574. }
  575. void ALCcontext::eax_get_misc(const EaxCall& call)
  576. {
  577. switch(call.get_property_id())
  578. {
  579. case EAXCONTEXT_NONE:
  580. break;
  581. case EAXCONTEXT_LASTERROR:
  582. call.set_value<ContextException>(mEaxLastError);
  583. mEaxLastError = EAX_OK;
  584. break;
  585. case EAXCONTEXT_SPEAKERCONFIG:
  586. call.set_value<ContextException>(mEaxSpeakerConfig);
  587. break;
  588. case EAXCONTEXT_EAXSESSION:
  589. call.set_value<ContextException>(mEaxSession);
  590. break;
  591. default:
  592. eax_fail_unknown_property_id();
  593. }
  594. }
  595. void ALCcontext::eax4_get(const EaxCall& call, const Eax4Props& props)
  596. {
  597. switch(call.get_property_id())
  598. {
  599. case EAXCONTEXT_ALLPARAMETERS:
  600. call.set_value<ContextException>(props);
  601. break;
  602. case EAXCONTEXT_PRIMARYFXSLOTID:
  603. call.set_value<ContextException>(props.guidPrimaryFXSlotID);
  604. break;
  605. case EAXCONTEXT_DISTANCEFACTOR:
  606. call.set_value<ContextException>(props.flDistanceFactor);
  607. break;
  608. case EAXCONTEXT_AIRABSORPTIONHF:
  609. call.set_value<ContextException>(props.flAirAbsorptionHF);
  610. break;
  611. case EAXCONTEXT_HFREFERENCE:
  612. call.set_value<ContextException>(props.flHFReference);
  613. break;
  614. default:
  615. eax_get_misc(call);
  616. break;
  617. }
  618. }
  619. void ALCcontext::eax5_get(const EaxCall& call, const Eax5Props& props)
  620. {
  621. switch(call.get_property_id())
  622. {
  623. case EAXCONTEXT_ALLPARAMETERS:
  624. call.set_value<ContextException>(props);
  625. break;
  626. case EAXCONTEXT_PRIMARYFXSLOTID:
  627. call.set_value<ContextException>(props.guidPrimaryFXSlotID);
  628. break;
  629. case EAXCONTEXT_DISTANCEFACTOR:
  630. call.set_value<ContextException>(props.flDistanceFactor);
  631. break;
  632. case EAXCONTEXT_AIRABSORPTIONHF:
  633. call.set_value<ContextException>(props.flAirAbsorptionHF);
  634. break;
  635. case EAXCONTEXT_HFREFERENCE:
  636. call.set_value<ContextException>(props.flHFReference);
  637. break;
  638. case EAXCONTEXT_MACROFXFACTOR:
  639. call.set_value<ContextException>(props.flMacroFXFactor);
  640. break;
  641. default:
  642. eax_get_misc(call);
  643. break;
  644. }
  645. }
  646. void ALCcontext::eax_get(const EaxCall& call)
  647. {
  648. switch(call.get_version())
  649. {
  650. case 4: eax4_get(call, mEax4.i); break;
  651. case 5: eax5_get(call, mEax5.i); break;
  652. default: eax_fail_unknown_version();
  653. }
  654. }
  655. void ALCcontext::eax_context_commit_primary_fx_slot_id()
  656. {
  657. mEaxPrimaryFxSlotIndex = mEax.guidPrimaryFXSlotID;
  658. }
  659. void ALCcontext::eax_context_commit_distance_factor()
  660. {
  661. /* mEax.flDistanceFactor was changed, so the context props are dirty. */
  662. mPropsDirty = true;
  663. }
  664. void ALCcontext::eax_context_commit_air_absorption_hf()
  665. {
  666. const auto new_value = level_mb_to_gain(mEax.flAirAbsorptionHF);
  667. if(mAirAbsorptionGainHF == new_value)
  668. return;
  669. mAirAbsorptionGainHF = new_value;
  670. mPropsDirty = true;
  671. }
  672. void ALCcontext::eax_context_commit_hf_reference()
  673. {
  674. // TODO
  675. }
  676. void ALCcontext::eax_context_commit_macro_fx_factor()
  677. {
  678. // TODO
  679. }
  680. void ALCcontext::eax_initialize_fx_slots()
  681. {
  682. mEaxFxSlots.initialize(*this);
  683. mEaxPrimaryFxSlotIndex = mEax.guidPrimaryFXSlotID;
  684. }
  685. void ALCcontext::eax_update_sources()
  686. {
  687. std::unique_lock<std::mutex> source_lock{mSourceLock};
  688. auto update_source = [](ALsource &source)
  689. { source.eaxCommit(); };
  690. ForEachSource(this, update_source);
  691. }
  692. void ALCcontext::eax_set_misc(const EaxCall& call)
  693. {
  694. switch(call.get_property_id())
  695. {
  696. case EAXCONTEXT_NONE:
  697. break;
  698. case EAXCONTEXT_SPEAKERCONFIG:
  699. eax_set<Eax5SpeakerConfigValidator>(call, mEaxSpeakerConfig);
  700. break;
  701. case EAXCONTEXT_EAXSESSION:
  702. eax_set<Eax5SessionAllValidator>(call, mEaxSession);
  703. break;
  704. default:
  705. eax_fail_unknown_property_id();
  706. }
  707. }
  708. void ALCcontext::eax4_defer_all(const EaxCall& call, Eax4State& state)
  709. {
  710. const auto& src = call.get_value<ContextException, const EAX40CONTEXTPROPERTIES>();
  711. Eax4AllValidator{}(src);
  712. const auto& dst_i = state.i;
  713. auto& dst_d = state.d;
  714. dst_d = src;
  715. if(dst_i.guidPrimaryFXSlotID != dst_d.guidPrimaryFXSlotID)
  716. mEaxDf.set(eax_primary_fx_slot_id_dirty_bit);
  717. if(dst_i.flDistanceFactor != dst_d.flDistanceFactor)
  718. mEaxDf.set(eax_distance_factor_dirty_bit);
  719. if(dst_i.flAirAbsorptionHF != dst_d.flAirAbsorptionHF)
  720. mEaxDf.set(eax_air_absorption_hf_dirty_bit);
  721. if(dst_i.flHFReference != dst_d.flHFReference)
  722. mEaxDf.set(eax_hf_reference_dirty_bit);
  723. }
  724. void ALCcontext::eax4_defer(const EaxCall& call, Eax4State& state)
  725. {
  726. switch(call.get_property_id())
  727. {
  728. case EAXCONTEXT_ALLPARAMETERS:
  729. eax4_defer_all(call, state);
  730. break;
  731. case EAXCONTEXT_PRIMARYFXSLOTID:
  732. eax_defer<Eax4PrimaryFxSlotIdValidator, eax_primary_fx_slot_id_dirty_bit>(call, state,
  733. &EAX40CONTEXTPROPERTIES::guidPrimaryFXSlotID);
  734. break;
  735. case EAXCONTEXT_DISTANCEFACTOR:
  736. eax_defer<Eax4DistanceFactorValidator, eax_distance_factor_dirty_bit>(call, state,
  737. &EAX40CONTEXTPROPERTIES::flDistanceFactor);
  738. break;
  739. case EAXCONTEXT_AIRABSORPTIONHF:
  740. eax_defer<Eax4AirAbsorptionHfValidator, eax_air_absorption_hf_dirty_bit>(call, state,
  741. &EAX40CONTEXTPROPERTIES::flAirAbsorptionHF);
  742. break;
  743. case EAXCONTEXT_HFREFERENCE:
  744. eax_defer<Eax4HfReferenceValidator, eax_hf_reference_dirty_bit>(call, state,
  745. &EAX40CONTEXTPROPERTIES::flHFReference);
  746. break;
  747. default:
  748. eax_set_misc(call);
  749. break;
  750. }
  751. }
  752. void ALCcontext::eax5_defer_all(const EaxCall& call, Eax5State& state)
  753. {
  754. const auto& src = call.get_value<ContextException, const EAX50CONTEXTPROPERTIES>();
  755. Eax4AllValidator{}(src);
  756. const auto& dst_i = state.i;
  757. auto& dst_d = state.d;
  758. dst_d = src;
  759. if(dst_i.guidPrimaryFXSlotID != dst_d.guidPrimaryFXSlotID)
  760. mEaxDf.set(eax_primary_fx_slot_id_dirty_bit);
  761. if(dst_i.flDistanceFactor != dst_d.flDistanceFactor)
  762. mEaxDf.set(eax_distance_factor_dirty_bit);
  763. if(dst_i.flAirAbsorptionHF != dst_d.flAirAbsorptionHF)
  764. mEaxDf.set(eax_air_absorption_hf_dirty_bit);
  765. if(dst_i.flHFReference != dst_d.flHFReference)
  766. mEaxDf.set(eax_hf_reference_dirty_bit);
  767. if(dst_i.flMacroFXFactor != dst_d.flMacroFXFactor)
  768. mEaxDf.set(eax_macro_fx_factor_dirty_bit);
  769. }
  770. void ALCcontext::eax5_defer(const EaxCall& call, Eax5State& state)
  771. {
  772. switch(call.get_property_id())
  773. {
  774. case EAXCONTEXT_ALLPARAMETERS:
  775. eax5_defer_all(call, state);
  776. break;
  777. case EAXCONTEXT_PRIMARYFXSLOTID:
  778. eax_defer<Eax5PrimaryFxSlotIdValidator, eax_primary_fx_slot_id_dirty_bit>(call, state,
  779. &EAX50CONTEXTPROPERTIES::guidPrimaryFXSlotID);
  780. break;
  781. case EAXCONTEXT_DISTANCEFACTOR:
  782. eax_defer<Eax4DistanceFactorValidator, eax_distance_factor_dirty_bit>(call, state,
  783. &EAX50CONTEXTPROPERTIES::flDistanceFactor);
  784. break;
  785. case EAXCONTEXT_AIRABSORPTIONHF:
  786. eax_defer<Eax4AirAbsorptionHfValidator, eax_air_absorption_hf_dirty_bit>(call, state,
  787. &EAX50CONTEXTPROPERTIES::flAirAbsorptionHF);
  788. break;
  789. case EAXCONTEXT_HFREFERENCE:
  790. eax_defer<Eax4HfReferenceValidator, eax_hf_reference_dirty_bit>(call, state,
  791. &EAX50CONTEXTPROPERTIES::flHFReference);
  792. break;
  793. case EAXCONTEXT_MACROFXFACTOR:
  794. eax_defer<Eax5MacroFxFactorValidator, eax_macro_fx_factor_dirty_bit>(call, state,
  795. &EAX50CONTEXTPROPERTIES::flMacroFXFactor);
  796. break;
  797. default:
  798. eax_set_misc(call);
  799. break;
  800. }
  801. }
  802. void ALCcontext::eax_set(const EaxCall& call)
  803. {
  804. const auto version = call.get_version();
  805. switch(version)
  806. {
  807. case 4: eax4_defer(call, mEax4); break;
  808. case 5: eax5_defer(call, mEax5); break;
  809. default: eax_fail_unknown_version();
  810. }
  811. if(version != mEaxVersion)
  812. mEaxDf.set();
  813. mEaxVersion = version;
  814. }
  815. void ALCcontext::eax4_context_commit(Eax4State& state, std::bitset<eax_dirty_bit_count>& dst_df)
  816. {
  817. if(mEaxDf.none())
  818. return;
  819. eax_context_commit_property<eax_primary_fx_slot_id_dirty_bit>(state, dst_df,
  820. &EAX40CONTEXTPROPERTIES::guidPrimaryFXSlotID);
  821. eax_context_commit_property<eax_distance_factor_dirty_bit>(state, dst_df,
  822. &EAX40CONTEXTPROPERTIES::flDistanceFactor);
  823. eax_context_commit_property<eax_air_absorption_hf_dirty_bit>(state, dst_df,
  824. &EAX40CONTEXTPROPERTIES::flAirAbsorptionHF);
  825. eax_context_commit_property<eax_hf_reference_dirty_bit>(state, dst_df,
  826. &EAX40CONTEXTPROPERTIES::flHFReference);
  827. mEaxDf.reset();
  828. }
  829. void ALCcontext::eax5_context_commit(Eax5State& state, std::bitset<eax_dirty_bit_count>& dst_df)
  830. {
  831. if(mEaxDf.none())
  832. return;
  833. eax_context_commit_property<eax_primary_fx_slot_id_dirty_bit>(state, dst_df,
  834. &EAX50CONTEXTPROPERTIES::guidPrimaryFXSlotID);
  835. eax_context_commit_property<eax_distance_factor_dirty_bit>(state, dst_df,
  836. &EAX50CONTEXTPROPERTIES::flDistanceFactor);
  837. eax_context_commit_property<eax_air_absorption_hf_dirty_bit>(state, dst_df,
  838. &EAX50CONTEXTPROPERTIES::flAirAbsorptionHF);
  839. eax_context_commit_property<eax_hf_reference_dirty_bit>(state, dst_df,
  840. &EAX50CONTEXTPROPERTIES::flHFReference);
  841. eax_context_commit_property<eax_macro_fx_factor_dirty_bit>(state, dst_df,
  842. &EAX50CONTEXTPROPERTIES::flMacroFXFactor);
  843. mEaxDf.reset();
  844. }
  845. void ALCcontext::eax_context_commit()
  846. {
  847. auto dst_df = std::bitset<eax_dirty_bit_count>{};
  848. switch(mEaxVersion)
  849. {
  850. case 1:
  851. case 2:
  852. case 3:
  853. eax5_context_commit(mEax123, dst_df);
  854. break;
  855. case 4:
  856. eax4_context_commit(mEax4, dst_df);
  857. break;
  858. case 5:
  859. eax5_context_commit(mEax5, dst_df);
  860. break;
  861. }
  862. if(dst_df.none())
  863. return;
  864. if(dst_df.test(eax_primary_fx_slot_id_dirty_bit))
  865. eax_context_commit_primary_fx_slot_id();
  866. if(dst_df.test(eax_distance_factor_dirty_bit))
  867. eax_context_commit_distance_factor();
  868. if(dst_df.test(eax_air_absorption_hf_dirty_bit))
  869. eax_context_commit_air_absorption_hf();
  870. if(dst_df.test(eax_hf_reference_dirty_bit))
  871. eax_context_commit_hf_reference();
  872. if(dst_df.test(eax_macro_fx_factor_dirty_bit))
  873. eax_context_commit_macro_fx_factor();
  874. if(dst_df.test(eax_primary_fx_slot_id_dirty_bit))
  875. eax_update_sources();
  876. }
  877. void ALCcontext::eaxCommit()
  878. {
  879. mEaxNeedsCommit = false;
  880. eax_context_commit();
  881. eaxCommitFxSlots();
  882. eax_update_sources();
  883. }
  884. FORCE_ALIGN auto AL_APIENTRY EAXSet(const GUID *property_set_id, ALuint property_id,
  885. ALuint source_id, ALvoid *value, ALuint value_size) noexcept -> ALenum
  886. {
  887. auto context = GetContextRef();
  888. if(!context) UNLIKELY return AL_INVALID_OPERATION;
  889. return EAXSetDirect(context.get(), property_set_id, property_id, source_id, value, value_size);
  890. }
  891. FORCE_ALIGN auto AL_APIENTRY EAXSetDirect(ALCcontext *context, const GUID *property_set_id,
  892. ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) noexcept -> ALenum
  893. try
  894. {
  895. std::lock_guard<std::mutex> prop_lock{context->mPropLock};
  896. return context->eax_eax_set(property_set_id, property_id, source_id, value, value_size);
  897. }
  898. catch(...)
  899. {
  900. context->eaxSetLastError();
  901. eax_log_exception(std::data(__func__));
  902. return AL_INVALID_OPERATION;
  903. }
  904. FORCE_ALIGN auto AL_APIENTRY EAXGet(const GUID *property_set_id, ALuint property_id,
  905. ALuint source_id, ALvoid *value, ALuint value_size) noexcept -> ALenum
  906. {
  907. auto context = GetContextRef();
  908. if(!context) UNLIKELY return AL_INVALID_OPERATION;
  909. return EAXGetDirect(context.get(), property_set_id, property_id, source_id, value, value_size);
  910. }
  911. FORCE_ALIGN auto AL_APIENTRY EAXGetDirect(ALCcontext *context, const GUID *property_set_id,
  912. ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) noexcept -> ALenum
  913. try
  914. {
  915. std::lock_guard<std::mutex> prop_lock{context->mPropLock};
  916. return context->eax_eax_get(property_set_id, property_id, source_id, value, value_size);
  917. }
  918. catch(...)
  919. {
  920. context->eaxSetLastError();
  921. eax_log_exception(std::data(__func__));
  922. return AL_INVALID_OPERATION;
  923. }
  924. #endif // ALSOFT_EAX