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

1051 lines
35 KiB

  1. #ifndef AL_SOURCE_H
  2. #define AL_SOURCE_H
  3. #include <array>
  4. #include <atomic>
  5. #include <cstddef>
  6. #include <iterator>
  7. #include <limits>
  8. #include <deque>
  9. #include "AL/al.h"
  10. #include "AL/alc.h"
  11. #include "alc/alu.h"
  12. #include "alc/context.h"
  13. #include "alc/inprogext.h"
  14. #include "aldeque.h"
  15. #include "almalloc.h"
  16. #include "alnumeric.h"
  17. #include "atomic.h"
  18. #include "core/voice.h"
  19. #include "vector.h"
  20. #ifdef ALSOFT_EAX
  21. #include "eax/call.h"
  22. #include "eax/exception.h"
  23. #include "eax/fx_slot_index.h"
  24. #include "eax/utils.h"
  25. #endif // ALSOFT_EAX
  26. struct ALbuffer;
  27. struct ALeffectslot;
  28. enum class SourceStereo : bool {
  29. Normal = AL_NORMAL_SOFT,
  30. Enhanced = AL_SUPER_STEREO_SOFT
  31. };
  32. #define DEFAULT_SENDS 2
  33. #define INVALID_VOICE_IDX static_cast<ALuint>(-1)
  34. struct ALbufferQueueItem : public VoiceBufferItem {
  35. ALbuffer *mBuffer{nullptr};
  36. DISABLE_ALLOC()
  37. };
  38. #ifdef ALSOFT_EAX
  39. class EaxSourceException : public EaxException {
  40. public:
  41. explicit EaxSourceException(const char* message)
  42. : EaxException{"EAX_SOURCE", message}
  43. {}
  44. };
  45. #endif // ALSOFT_EAX
  46. struct ALsource {
  47. /** Source properties. */
  48. float Pitch{1.0f};
  49. float Gain{1.0f};
  50. float OuterGain{0.0f};
  51. float MinGain{0.0f};
  52. float MaxGain{1.0f};
  53. float InnerAngle{360.0f};
  54. float OuterAngle{360.0f};
  55. float RefDistance{1.0f};
  56. float MaxDistance{std::numeric_limits<float>::max()};
  57. float RolloffFactor{1.0f};
  58. #ifdef ALSOFT_EAX
  59. // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
  60. // AL_ROLLOFF_FACTOR
  61. float RolloffFactor2{0.0f};
  62. #endif
  63. std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
  64. std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
  65. std::array<float,3> Direction{{0.0f, 0.0f, 0.0f}};
  66. std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
  67. std::array<float,3> OrientUp{{0.0f, 1.0f, 0.0f}};
  68. bool HeadRelative{false};
  69. bool Looping{false};
  70. DistanceModel mDistanceModel{DistanceModel::Default};
  71. Resampler mResampler{ResamplerDefault};
  72. DirectMode DirectChannels{DirectMode::Off};
  73. SpatializeMode mSpatialize{SpatializeMode::Auto};
  74. SourceStereo mStereoMode{SourceStereo::Normal};
  75. bool DryGainHFAuto{true};
  76. bool WetGainAuto{true};
  77. bool WetGainHFAuto{true};
  78. float OuterGainHF{1.0f};
  79. float AirAbsorptionFactor{0.0f};
  80. float RoomRolloffFactor{0.0f};
  81. float DopplerFactor{1.0f};
  82. /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
  83. * rather than clockwise.
  84. */
  85. std::array<float,2> StereoPan{{al::numbers::pi_v<float>/6.0f, -al::numbers::pi_v<float>/6.0f}};
  86. float Radius{0.0f};
  87. float EnhWidth{0.593f};
  88. /** Direct filter and auxiliary send info. */
  89. struct {
  90. float Gain;
  91. float GainHF;
  92. float HFReference;
  93. float GainLF;
  94. float LFReference;
  95. } Direct;
  96. struct SendData {
  97. ALeffectslot *Slot;
  98. float Gain;
  99. float GainHF;
  100. float HFReference;
  101. float GainLF;
  102. float LFReference;
  103. };
  104. std::array<SendData,MAX_SENDS> Send;
  105. /**
  106. * Last user-specified offset, and the offset type (bytes, samples, or
  107. * seconds).
  108. */
  109. double Offset{0.0};
  110. ALenum OffsetType{AL_NONE};
  111. /** Source type (static, streaming, or undetermined) */
  112. ALenum SourceType{AL_UNDETERMINED};
  113. /** Source state (initial, playing, paused, or stopped) */
  114. ALenum state{AL_INITIAL};
  115. /** Source Buffer Queue head. */
  116. al::deque<ALbufferQueueItem> mQueue;
  117. bool mPropsDirty{true};
  118. /* Index into the context's Voices array. Lazily updated, only checked and
  119. * reset when looking up the voice.
  120. */
  121. ALuint VoiceIdx{INVALID_VOICE_IDX};
  122. /** Self ID */
  123. ALuint id{0};
  124. ALsource();
  125. ~ALsource();
  126. ALsource(const ALsource&) = delete;
  127. ALsource& operator=(const ALsource&) = delete;
  128. DISABLE_ALLOC()
  129. #ifdef ALSOFT_EAX
  130. public:
  131. void eax_initialize(ALCcontext *context) noexcept;
  132. void eax_dispatch(const EaxCall& call);
  133. void eax_commit() { eax_commit(EaxCommitType::normal); }
  134. void eax_commit_and_update();
  135. bool eax_is_initialized() const noexcept { return eax_al_context_ != nullptr; }
  136. static ALsource* eax_lookup_source(ALCcontext& al_context, ALuint source_id) noexcept;
  137. private:
  138. using Exception = EaxSourceException;
  139. enum class EaxCommitType {
  140. normal,
  141. forced,
  142. };
  143. static constexpr auto eax_max_speakers = 9;
  144. using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS];
  145. static constexpr const EaxFxSlotIds eax4_fx_slot_ids = {
  146. &EAXPROPERTYID_EAX40_FXSlot0,
  147. &EAXPROPERTYID_EAX40_FXSlot1,
  148. &EAXPROPERTYID_EAX40_FXSlot2,
  149. &EAXPROPERTYID_EAX40_FXSlot3,
  150. };
  151. static constexpr const EaxFxSlotIds eax5_fx_slot_ids = {
  152. &EAXPROPERTYID_EAX50_FXSlot0,
  153. &EAXPROPERTYID_EAX50_FXSlot1,
  154. &EAXPROPERTYID_EAX50_FXSlot2,
  155. &EAXPROPERTYID_EAX50_FXSlot3,
  156. };
  157. using EaxActiveFxSlots = std::array<bool, EAX_MAX_FXSLOTS>;
  158. using EaxSpeakerLevels = std::array<EAXSPEAKERLEVELPROPERTIES, eax_max_speakers>;
  159. using EaxSends = std::array<EAXSOURCEALLSENDPROPERTIES, EAX_MAX_FXSLOTS>;
  160. using Eax1Props = EAXBUFFER_REVERBPROPERTIES;
  161. struct Eax1State {
  162. Eax1Props i; // Immediate.
  163. Eax1Props d; // Deferred.
  164. };
  165. using Eax2Props = EAX20BUFFERPROPERTIES;
  166. struct Eax2State {
  167. Eax2Props i; // Immediate.
  168. Eax2Props d; // Deferred.
  169. };
  170. using Eax3Props = EAX30SOURCEPROPERTIES;
  171. struct Eax3State {
  172. Eax3Props i; // Immediate.
  173. Eax3Props d; // Deferred.
  174. };
  175. struct Eax4Props {
  176. Eax3Props source;
  177. EaxSends sends;
  178. EAX40ACTIVEFXSLOTS active_fx_slots;
  179. bool operator==(const Eax4Props& rhs) noexcept
  180. {
  181. return std::memcmp(this, &rhs, sizeof(Eax4Props)) == 0;
  182. }
  183. };
  184. struct Eax4State {
  185. Eax4Props i; // Immediate.
  186. Eax4Props d; // Deferred.
  187. };
  188. struct Eax5Props {
  189. EAX50SOURCEPROPERTIES source;
  190. EaxSends sends;
  191. EAX50ACTIVEFXSLOTS active_fx_slots;
  192. EaxSpeakerLevels speaker_levels;
  193. bool operator==(const Eax5Props& rhs) noexcept
  194. {
  195. return std::memcmp(this, &rhs, sizeof(Eax5Props)) == 0;
  196. }
  197. };
  198. struct Eax5State {
  199. Eax5Props i; // Immediate.
  200. Eax5Props d; // Deferred.
  201. };
  202. ALCcontext* eax_al_context_{};
  203. EaxFxSlotIndex eax_primary_fx_slot_id_{};
  204. EaxActiveFxSlots eax_active_fx_slots_{};
  205. int eax_version_{};
  206. bool eax_changed_{};
  207. Eax1State eax1_{};
  208. Eax2State eax2_{};
  209. Eax3State eax3_{};
  210. Eax4State eax4_{};
  211. Eax5State eax5_{};
  212. Eax5Props eax_{};
  213. // ----------------------------------------------------------------------
  214. // Source validators
  215. struct Eax1SourceReverbMixValidator {
  216. void operator()(float reverb_mix) const
  217. {
  218. if (reverb_mix == EAX_REVERBMIX_USEDISTANCE)
  219. return;
  220. eax_validate_range<Exception>(
  221. "Reverb Mix",
  222. reverb_mix,
  223. EAX_BUFFER_MINREVERBMIX,
  224. EAX_BUFFER_MAXREVERBMIX);
  225. }
  226. };
  227. struct Eax2SourceDirectValidator {
  228. void operator()(long lDirect) const
  229. {
  230. eax_validate_range<Exception>(
  231. "Direct",
  232. lDirect,
  233. EAXSOURCE_MINDIRECT,
  234. EAXSOURCE_MAXDIRECT);
  235. }
  236. };
  237. struct Eax2SourceDirectHfValidator {
  238. void operator()(long lDirectHF) const
  239. {
  240. eax_validate_range<Exception>(
  241. "Direct HF",
  242. lDirectHF,
  243. EAXSOURCE_MINDIRECTHF,
  244. EAXSOURCE_MAXDIRECTHF);
  245. }
  246. };
  247. struct Eax2SourceRoomValidator {
  248. void operator()(long lRoom) const
  249. {
  250. eax_validate_range<Exception>(
  251. "Room",
  252. lRoom,
  253. EAXSOURCE_MINROOM,
  254. EAXSOURCE_MAXROOM);
  255. }
  256. };
  257. struct Eax2SourceRoomHfValidator {
  258. void operator()(long lRoomHF) const
  259. {
  260. eax_validate_range<Exception>(
  261. "Room HF",
  262. lRoomHF,
  263. EAXSOURCE_MINROOMHF,
  264. EAXSOURCE_MAXROOMHF);
  265. }
  266. };
  267. struct Eax2SourceRoomRolloffFactorValidator {
  268. void operator()(float flRoomRolloffFactor) const
  269. {
  270. eax_validate_range<Exception>(
  271. "Room Rolloff Factor",
  272. flRoomRolloffFactor,
  273. EAXSOURCE_MINROOMROLLOFFFACTOR,
  274. EAXSOURCE_MAXROOMROLLOFFFACTOR);
  275. }
  276. };
  277. struct Eax2SourceObstructionValidator {
  278. void operator()(long lObstruction) const
  279. {
  280. eax_validate_range<Exception>(
  281. "Obstruction",
  282. lObstruction,
  283. EAXSOURCE_MINOBSTRUCTION,
  284. EAXSOURCE_MAXOBSTRUCTION);
  285. }
  286. };
  287. struct Eax2SourceObstructionLfRatioValidator {
  288. void operator()(float flObstructionLFRatio) const
  289. {
  290. eax_validate_range<Exception>(
  291. "Obstruction LF Ratio",
  292. flObstructionLFRatio,
  293. EAXSOURCE_MINOBSTRUCTIONLFRATIO,
  294. EAXSOURCE_MAXOBSTRUCTIONLFRATIO);
  295. }
  296. };
  297. struct Eax2SourceOcclusionValidator {
  298. void operator()(long lOcclusion) const
  299. {
  300. eax_validate_range<Exception>(
  301. "Occlusion",
  302. lOcclusion,
  303. EAXSOURCE_MINOCCLUSION,
  304. EAXSOURCE_MAXOCCLUSION);
  305. }
  306. };
  307. struct Eax2SourceOcclusionLfRatioValidator {
  308. void operator()(float flOcclusionLFRatio) const
  309. {
  310. eax_validate_range<Exception>(
  311. "Occlusion LF Ratio",
  312. flOcclusionLFRatio,
  313. EAXSOURCE_MINOCCLUSIONLFRATIO,
  314. EAXSOURCE_MAXOCCLUSIONLFRATIO);
  315. }
  316. };
  317. struct Eax2SourceOcclusionRoomRatioValidator {
  318. void operator()(float flOcclusionRoomRatio) const
  319. {
  320. eax_validate_range<Exception>(
  321. "Occlusion Room Ratio",
  322. flOcclusionRoomRatio,
  323. EAXSOURCE_MINOCCLUSIONROOMRATIO,
  324. EAXSOURCE_MAXOCCLUSIONROOMRATIO);
  325. }
  326. };
  327. struct Eax2SourceOutsideVolumeHfValidator {
  328. void operator()(long lOutsideVolumeHF) const
  329. {
  330. eax_validate_range<Exception>(
  331. "Outside Volume HF",
  332. lOutsideVolumeHF,
  333. EAXSOURCE_MINOUTSIDEVOLUMEHF,
  334. EAXSOURCE_MAXOUTSIDEVOLUMEHF);
  335. }
  336. };
  337. struct Eax2SourceAirAbsorptionFactorValidator {
  338. void operator()(float flAirAbsorptionFactor) const
  339. {
  340. eax_validate_range<Exception>(
  341. "Air Absorption Factor",
  342. flAirAbsorptionFactor,
  343. EAXSOURCE_MINAIRABSORPTIONFACTOR,
  344. EAXSOURCE_MAXAIRABSORPTIONFACTOR);
  345. }
  346. };
  347. struct Eax2SourceFlagsValidator {
  348. void operator()(unsigned long dwFlags) const
  349. {
  350. eax_validate_range<Exception>(
  351. "Flags",
  352. dwFlags,
  353. 0UL,
  354. ~EAX20SOURCEFLAGS_RESERVED);
  355. }
  356. };
  357. struct Eax3SourceOcclusionDirectRatioValidator {
  358. void operator()(float flOcclusionDirectRatio) const
  359. {
  360. eax_validate_range<Exception>(
  361. "Occlusion Direct Ratio",
  362. flOcclusionDirectRatio,
  363. EAXSOURCE_MINOCCLUSIONDIRECTRATIO,
  364. EAXSOURCE_MAXOCCLUSIONDIRECTRATIO);
  365. }
  366. };
  367. struct Eax3SourceExclusionValidator {
  368. void operator()(long lExclusion) const
  369. {
  370. eax_validate_range<Exception>(
  371. "Exclusion",
  372. lExclusion,
  373. EAXSOURCE_MINEXCLUSION,
  374. EAXSOURCE_MAXEXCLUSION);
  375. }
  376. };
  377. struct Eax3SourceExclusionLfRatioValidator {
  378. void operator()(float flExclusionLFRatio) const
  379. {
  380. eax_validate_range<Exception>(
  381. "Exclusion LF Ratio",
  382. flExclusionLFRatio,
  383. EAXSOURCE_MINEXCLUSIONLFRATIO,
  384. EAXSOURCE_MAXEXCLUSIONLFRATIO);
  385. }
  386. };
  387. struct Eax3SourceDopplerFactorValidator {
  388. void operator()(float flDopplerFactor) const
  389. {
  390. eax_validate_range<Exception>(
  391. "Doppler Factor",
  392. flDopplerFactor,
  393. EAXSOURCE_MINDOPPLERFACTOR,
  394. EAXSOURCE_MAXDOPPLERFACTOR);
  395. }
  396. };
  397. struct Eax3SourceRolloffFactorValidator {
  398. void operator()(float flRolloffFactor) const
  399. {
  400. eax_validate_range<Exception>(
  401. "Rolloff Factor",
  402. flRolloffFactor,
  403. EAXSOURCE_MINROLLOFFFACTOR,
  404. EAXSOURCE_MAXROLLOFFFACTOR);
  405. }
  406. };
  407. struct Eax5SourceMacroFXFactorValidator {
  408. void operator()(float flMacroFXFactor) const
  409. {
  410. eax_validate_range<Exception>(
  411. "Macro FX Factor",
  412. flMacroFXFactor,
  413. EAXSOURCE_MINMACROFXFACTOR,
  414. EAXSOURCE_MAXMACROFXFACTOR);
  415. }
  416. };
  417. struct Eax5SourceFlagsValidator {
  418. void operator()(unsigned long dwFlags) const
  419. {
  420. eax_validate_range<Exception>(
  421. "Flags",
  422. dwFlags,
  423. 0UL,
  424. ~EAX50SOURCEFLAGS_RESERVED);
  425. }
  426. };
  427. struct Eax1SourceAllValidator {
  428. void operator()(const Eax1Props& props) const
  429. {
  430. Eax1SourceReverbMixValidator{}(props.fMix);
  431. }
  432. };
  433. struct Eax2SourceAllValidator {
  434. void operator()(const Eax2Props& props) const
  435. {
  436. Eax2SourceDirectValidator{}(props.lDirect);
  437. Eax2SourceDirectHfValidator{}(props.lDirectHF);
  438. Eax2SourceRoomValidator{}(props.lRoom);
  439. Eax2SourceRoomHfValidator{}(props.lRoomHF);
  440. Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
  441. Eax2SourceObstructionValidator{}(props.lObstruction);
  442. Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
  443. Eax2SourceOcclusionValidator{}(props.lOcclusion);
  444. Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
  445. Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
  446. Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
  447. Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
  448. Eax2SourceFlagsValidator{}(props.dwFlags);
  449. }
  450. };
  451. struct Eax3SourceAllValidator {
  452. void operator()(const Eax3Props& props) const
  453. {
  454. Eax2SourceDirectValidator{}(props.lDirect);
  455. Eax2SourceDirectHfValidator{}(props.lDirectHF);
  456. Eax2SourceRoomValidator{}(props.lRoom);
  457. Eax2SourceRoomHfValidator{}(props.lRoomHF);
  458. Eax2SourceObstructionValidator{}(props.lObstruction);
  459. Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
  460. Eax2SourceOcclusionValidator{}(props.lOcclusion);
  461. Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
  462. Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
  463. Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
  464. Eax3SourceExclusionValidator{}(props.lExclusion);
  465. Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
  466. Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
  467. Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
  468. Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
  469. Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
  470. Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
  471. Eax2SourceFlagsValidator{}(props.ulFlags);
  472. }
  473. };
  474. struct Eax5SourceAllValidator {
  475. void operator()(const EAX50SOURCEPROPERTIES& props) const
  476. {
  477. Eax3SourceAllValidator{}(static_cast<const Eax3Props&>(props));
  478. Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor);
  479. }
  480. };
  481. struct Eax5SourceAll2dValidator {
  482. void operator()(const EAXSOURCE2DPROPERTIES& props) const
  483. {
  484. Eax2SourceDirectValidator{}(props.lDirect);
  485. Eax2SourceDirectHfValidator{}(props.lDirectHF);
  486. Eax2SourceRoomValidator{}(props.lRoom);
  487. Eax2SourceRoomHfValidator{}(props.lRoomHF);
  488. Eax5SourceFlagsValidator{}(props.ulFlags);
  489. }
  490. };
  491. struct Eax4ObstructionValidator {
  492. void operator()(const EAXOBSTRUCTIONPROPERTIES& props) const
  493. {
  494. Eax2SourceObstructionValidator{}(props.lObstruction);
  495. Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
  496. }
  497. };
  498. struct Eax4OcclusionValidator {
  499. void operator()(const EAXOCCLUSIONPROPERTIES& props) const
  500. {
  501. Eax2SourceOcclusionValidator{}(props.lOcclusion);
  502. Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
  503. Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
  504. Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
  505. }
  506. };
  507. struct Eax4ExclusionValidator {
  508. void operator()(const EAXEXCLUSIONPROPERTIES& props) const
  509. {
  510. Eax3SourceExclusionValidator{}(props.lExclusion);
  511. Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
  512. }
  513. };
  514. // Source validators
  515. // ----------------------------------------------------------------------
  516. // Send validators
  517. struct Eax4SendReceivingFxSlotIdValidator {
  518. void operator()(const GUID& guidReceivingFXSlotID) const
  519. {
  520. if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 &&
  521. guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 &&
  522. guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 &&
  523. guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3)
  524. {
  525. eax_fail_unknown_receiving_fx_slot_id();
  526. }
  527. }
  528. };
  529. struct Eax5SendReceivingFxSlotIdValidator {
  530. void operator()(const GUID& guidReceivingFXSlotID) const
  531. {
  532. if (guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 &&
  533. guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 &&
  534. guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 &&
  535. guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3)
  536. {
  537. eax_fail_unknown_receiving_fx_slot_id();
  538. }
  539. }
  540. };
  541. struct Eax4SendSendValidator {
  542. void operator()(long lSend) const
  543. {
  544. eax_validate_range<Exception>(
  545. "Send",
  546. lSend,
  547. EAXSOURCE_MINSEND,
  548. EAXSOURCE_MAXSEND);
  549. }
  550. };
  551. struct Eax4SendSendHfValidator {
  552. void operator()(long lSendHF) const
  553. {
  554. eax_validate_range<Exception>(
  555. "Send HF",
  556. lSendHF,
  557. EAXSOURCE_MINSENDHF,
  558. EAXSOURCE_MAXSENDHF);
  559. }
  560. };
  561. template<typename TIdValidator>
  562. struct EaxSendValidator {
  563. void operator()(const EAXSOURCESENDPROPERTIES& props) const
  564. {
  565. TIdValidator{}(props.guidReceivingFXSlotID);
  566. Eax4SendSendValidator{}(props.lSend);
  567. Eax4SendSendHfValidator{}(props.lSendHF);
  568. }
  569. };
  570. struct Eax4SendValidator : EaxSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
  571. struct Eax5SendValidator : EaxSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
  572. template<typename TIdValidator>
  573. struct EaxOcclusionSendValidator {
  574. void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES& props) const
  575. {
  576. TIdValidator{}(props.guidReceivingFXSlotID);
  577. Eax2SourceOcclusionValidator{}(props.lOcclusion);
  578. Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
  579. Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
  580. Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
  581. }
  582. };
  583. struct Eax4OcclusionSendValidator : EaxOcclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
  584. struct Eax5OcclusionSendValidator : EaxOcclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
  585. template<typename TIdValidator>
  586. struct EaxExclusionSendValidator {
  587. void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES& props) const
  588. {
  589. TIdValidator{}(props.guidReceivingFXSlotID);
  590. Eax3SourceExclusionValidator{}(props.lExclusion);
  591. Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
  592. }
  593. };
  594. struct Eax4ExclusionSendValidator : EaxExclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
  595. struct Eax5ExclusionSendValidator : EaxExclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
  596. template<typename TIdValidator>
  597. struct EaxAllSendValidator {
  598. void operator()(const EAXSOURCEALLSENDPROPERTIES& props) const
  599. {
  600. TIdValidator{}(props.guidReceivingFXSlotID);
  601. Eax4SendSendValidator{}(props.lSend);
  602. Eax4SendSendHfValidator{}(props.lSendHF);
  603. Eax2SourceOcclusionValidator{}(props.lOcclusion);
  604. Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
  605. Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
  606. Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
  607. Eax3SourceExclusionValidator{}(props.lExclusion);
  608. Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
  609. }
  610. };
  611. struct Eax4AllSendValidator : EaxAllSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
  612. struct Eax5AllSendValidator : EaxAllSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
  613. // Send validators
  614. // ----------------------------------------------------------------------
  615. // Active FX slot ID validators
  616. struct Eax4ActiveFxSlotIdValidator {
  617. void operator()(const GUID &guid) const
  618. {
  619. if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
  620. && guid != EAXPROPERTYID_EAX40_FXSlot0 && guid != EAXPROPERTYID_EAX40_FXSlot1
  621. && guid != EAXPROPERTYID_EAX40_FXSlot2 && guid != EAXPROPERTYID_EAX40_FXSlot3)
  622. {
  623. eax_fail_unknown_active_fx_slot_id();
  624. }
  625. }
  626. };
  627. struct Eax5ActiveFxSlotIdValidator {
  628. void operator()(const GUID &guid) const
  629. {
  630. if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
  631. && guid != EAXPROPERTYID_EAX50_FXSlot0 && guid != EAXPROPERTYID_EAX50_FXSlot1
  632. && guid != EAXPROPERTYID_EAX50_FXSlot2 && guid != EAXPROPERTYID_EAX50_FXSlot3)
  633. {
  634. eax_fail_unknown_active_fx_slot_id();
  635. }
  636. }
  637. };
  638. // Active FX slot ID validators
  639. // ----------------------------------------------------------------------
  640. // Speaker level validators.
  641. struct Eax5SpeakerIdValidator {
  642. void operator()(long lSpeakerID) const
  643. {
  644. switch (lSpeakerID) {
  645. case EAXSPEAKER_FRONT_LEFT:
  646. case EAXSPEAKER_FRONT_CENTER:
  647. case EAXSPEAKER_FRONT_RIGHT:
  648. case EAXSPEAKER_SIDE_RIGHT:
  649. case EAXSPEAKER_REAR_RIGHT:
  650. case EAXSPEAKER_REAR_CENTER:
  651. case EAXSPEAKER_REAR_LEFT:
  652. case EAXSPEAKER_SIDE_LEFT:
  653. case EAXSPEAKER_LOW_FREQUENCY:
  654. break;
  655. default:
  656. eax_fail("Unknown speaker ID.");
  657. }
  658. }
  659. };
  660. struct Eax5SpeakerLevelValidator {
  661. void operator()(long lLevel) const
  662. {
  663. // TODO Use a range when the feature will be implemented.
  664. if (lLevel != EAXSOURCE_DEFAULTSPEAKERLEVEL)
  665. eax_fail("Speaker level out of range.");
  666. }
  667. };
  668. struct Eax5SpeakerAllValidator {
  669. void operator()(const EAXSPEAKERLEVELPROPERTIES& all) const
  670. {
  671. Eax5SpeakerIdValidator{}(all.lSpeakerID);
  672. Eax5SpeakerLevelValidator{}(all.lLevel);
  673. }
  674. };
  675. // Speaker level validators.
  676. // ----------------------------------------------------------------------
  677. struct Eax4SendIndexGetter {
  678. EaxFxSlotIndexValue operator()(const GUID &guid) const
  679. {
  680. if(guid == EAXPROPERTYID_EAX40_FXSlot0)
  681. return 0;
  682. if(guid == EAXPROPERTYID_EAX40_FXSlot1)
  683. return 1;
  684. if(guid == EAXPROPERTYID_EAX40_FXSlot2)
  685. return 2;
  686. if(guid == EAXPROPERTYID_EAX40_FXSlot3)
  687. return 3;
  688. eax_fail_unknown_receiving_fx_slot_id();
  689. }
  690. };
  691. struct Eax5SendIndexGetter {
  692. EaxFxSlotIndexValue operator()(const GUID &guid) const
  693. {
  694. if(guid == EAXPROPERTYID_EAX50_FXSlot0)
  695. return 0;
  696. if(guid == EAXPROPERTYID_EAX50_FXSlot1)
  697. return 1;
  698. if(guid == EAXPROPERTYID_EAX50_FXSlot2)
  699. return 2;
  700. if(guid == EAXPROPERTYID_EAX50_FXSlot3)
  701. return 3;
  702. eax_fail_unknown_receiving_fx_slot_id();
  703. }
  704. };
  705. [[noreturn]] static void eax_fail(const char* message);
  706. [[noreturn]] static void eax_fail_unknown_property_id();
  707. [[noreturn]] static void eax_fail_unknown_version();
  708. [[noreturn]] static void eax_fail_unknown_active_fx_slot_id();
  709. [[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id();
  710. void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
  711. void eax1_set_defaults(Eax1Props& props) noexcept;
  712. void eax1_set_defaults() noexcept;
  713. void eax2_set_defaults(Eax2Props& props) noexcept;
  714. void eax2_set_defaults() noexcept;
  715. void eax3_set_defaults(Eax3Props& props) noexcept;
  716. void eax3_set_defaults() noexcept;
  717. void eax4_set_sends_defaults(EaxSends& sends) noexcept;
  718. void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
  719. void eax4_set_defaults() noexcept;
  720. void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
  721. void eax5_set_sends_defaults(EaxSends& sends) noexcept;
  722. void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
  723. void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
  724. void eax5_set_defaults(Eax5Props& props) noexcept;
  725. void eax5_set_defaults() noexcept;
  726. void eax_set_defaults() noexcept;
  727. void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
  728. void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
  729. void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
  730. void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
  731. static float eax_calculate_dst_occlusion_mb(
  732. long src_occlusion_mb,
  733. float path_ratio,
  734. float lf_ratio) noexcept;
  735. EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;
  736. EaxAlLowPassParam eax_create_room_filter_param(
  737. const ALeffectslot& fx_slot,
  738. const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;
  739. void eax_update_direct_filter();
  740. void eax_update_room_filters();
  741. void eax_commit_filters();
  742. static void eax_copy_send_for_get(
  743. const EAXSOURCEALLSENDPROPERTIES& src,
  744. EAXSOURCESENDPROPERTIES& dst) noexcept
  745. {
  746. dst = reinterpret_cast<const EAXSOURCESENDPROPERTIES&>(src);
  747. }
  748. static void eax_copy_send_for_get(
  749. const EAXSOURCEALLSENDPROPERTIES& src,
  750. EAXSOURCEALLSENDPROPERTIES& dst) noexcept
  751. {
  752. dst = src;
  753. }
  754. static void eax_copy_send_for_get(
  755. const EAXSOURCEALLSENDPROPERTIES& src,
  756. EAXSOURCEOCCLUSIONSENDPROPERTIES& dst) noexcept
  757. {
  758. dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
  759. dst.lOcclusion = src.lOcclusion;
  760. dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
  761. dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
  762. dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
  763. }
  764. static void eax_copy_send_for_get(
  765. const EAXSOURCEALLSENDPROPERTIES& src,
  766. EAXSOURCEEXCLUSIONSENDPROPERTIES& dst) noexcept
  767. {
  768. dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
  769. dst.lExclusion = src.lExclusion;
  770. dst.flExclusionLFRatio = src.flExclusionLFRatio;
  771. }
  772. template<typename TDstSend>
  773. void eax_get_sends(const EaxCall& call, const EaxSends& src_sends)
  774. {
  775. const auto dst_sends = call.get_values<TDstSend>(EAX_MAX_FXSLOTS);
  776. const auto count = dst_sends.size();
  777. for (auto i = decltype(count){}; i < count; ++i) {
  778. const auto& src_send = src_sends[i];
  779. auto& dst_send = dst_sends[i];
  780. eax_copy_send_for_get(src_send, dst_send);
  781. }
  782. }
  783. void eax1_get(const EaxCall& call, const Eax1Props& props);
  784. void eax2_get(const EaxCall& call, const Eax2Props& props);
  785. void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
  786. void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
  787. void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
  788. void eax3_get(const EaxCall& call, const Eax3Props& props);
  789. void eax4_get(const EaxCall& call, const Eax4Props& props);
  790. void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
  791. void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
  792. void eax5_get(const EaxCall& call, const Eax5Props& props);
  793. void eax_get(const EaxCall& call);
  794. static void eax_copy_send_for_set(
  795. const EAXSOURCESENDPROPERTIES& src,
  796. EAXSOURCEALLSENDPROPERTIES& dst) noexcept
  797. {
  798. dst.lSend = src.lSend;
  799. dst.lSendHF = src.lSendHF;
  800. }
  801. static void eax_copy_send_for_set(
  802. const EAXSOURCEALLSENDPROPERTIES& src,
  803. EAXSOURCEALLSENDPROPERTIES& dst) noexcept
  804. {
  805. dst.lSend = src.lSend;
  806. dst.lSendHF = src.lSendHF;
  807. dst.lOcclusion = src.lOcclusion;
  808. dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
  809. dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
  810. dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
  811. dst.lExclusion = src.lExclusion;
  812. dst.flExclusionLFRatio = src.flExclusionLFRatio;
  813. }
  814. static void eax_copy_send_for_set(
  815. const EAXSOURCEOCCLUSIONSENDPROPERTIES& src,
  816. EAXSOURCEALLSENDPROPERTIES& dst) noexcept
  817. {
  818. dst.lOcclusion = src.lOcclusion;
  819. dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
  820. dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
  821. dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
  822. }
  823. static void eax_copy_send_for_set(
  824. const EAXSOURCEEXCLUSIONSENDPROPERTIES& src,
  825. EAXSOURCEALLSENDPROPERTIES& dst) noexcept
  826. {
  827. dst.lExclusion = src.lExclusion;
  828. dst.flExclusionLFRatio = src.flExclusionLFRatio;
  829. }
  830. template<typename TValidator, typename TIndexGetter, typename TSrcSend>
  831. void eax_defer_sends(const EaxCall& call, EaxSends& dst_sends)
  832. {
  833. const auto src_sends = call.get_values<const TSrcSend>(EAX_MAX_FXSLOTS);
  834. std::for_each(src_sends.cbegin(), src_sends.cend(), TValidator{});
  835. const auto count = src_sends.size();
  836. const auto index_getter = TIndexGetter{};
  837. for (auto i = decltype(count){}; i < count; ++i) {
  838. const auto& src_send = src_sends[i];
  839. const auto dst_index = index_getter(src_send.guidReceivingFXSlotID);
  840. auto& dst_send = dst_sends[dst_index];
  841. eax_copy_send_for_set(src_send, dst_send);
  842. }
  843. }
  844. template<typename TValidator, typename TSrcSend>
  845. void eax4_defer_sends(const EaxCall& call, EaxSends& dst_sends)
  846. {
  847. eax_defer_sends<TValidator, Eax4SendIndexGetter, TSrcSend>(call, dst_sends);
  848. }
  849. template<typename TValidator, typename TSrcSend>
  850. void eax5_defer_sends(const EaxCall& call, EaxSends& dst_sends)
  851. {
  852. eax_defer_sends<TValidator, Eax5SendIndexGetter, TSrcSend>(call, dst_sends);
  853. }
  854. template<typename TValidator, size_t TIdCount>
  855. void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
  856. {
  857. const auto src_ids = call.get_values<const GUID>(TIdCount);
  858. std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
  859. std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids);
  860. }
  861. template<size_t TIdCount>
  862. void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
  863. {
  864. eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
  865. }
  866. template<size_t TIdCount>
  867. void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
  868. {
  869. eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
  870. }
  871. template<typename TValidator, typename TProperty>
  872. static void eax_defer(const EaxCall& call, TProperty& property)
  873. {
  874. const auto& value = call.get_value<Exception, const TProperty>();
  875. TValidator{}(value);
  876. property = value;
  877. }
  878. // Defers source's sub-properties (obstruction, occlusion, exclusion).
  879. template<typename TValidator, typename TSubproperty, typename TProperty>
  880. void eax_defer_sub(const EaxCall& call, TProperty& property)
  881. {
  882. const auto& src_props = call.get_value<Exception, const TSubproperty>();
  883. TValidator{}(src_props);
  884. auto& dst_props = reinterpret_cast<TSubproperty&>(property);
  885. dst_props = src_props;
  886. }
  887. void eax_set_efx_outer_gain_hf();
  888. void eax_set_efx_doppler_factor();
  889. void eax_set_efx_rolloff_factor();
  890. void eax_set_efx_room_rolloff_factor();
  891. void eax_set_efx_air_absorption_factor();
  892. void eax_set_efx_dry_gain_hf_auto();
  893. void eax_set_efx_wet_gain_auto();
  894. void eax_set_efx_wet_gain_hf_auto();
  895. void eax1_set(const EaxCall& call, Eax1Props& props);
  896. void eax2_set(const EaxCall& call, Eax2Props& props);
  897. void eax3_set(const EaxCall& call, Eax3Props& props);
  898. void eax4_set(const EaxCall& call, Eax4Props& props);
  899. void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
  900. void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
  901. void eax5_set(const EaxCall& call, Eax5Props& props);
  902. void eax_set(const EaxCall& call);
  903. // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
  904. void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx,
  905. const EaxAlLowPassParam &filter);
  906. void eax_commit_active_fx_slots();
  907. void eax_commit(EaxCommitType commit_type);
  908. #endif // ALSOFT_EAX
  909. };
  910. void UpdateAllSourceProps(ALCcontext *context);
  911. #endif