source.h 36 KB

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