Trace the UHJ encoder filter type
[openal-soft.git] / al / source.h
blob9f70bfafd6a32c1aec0a8f27bb5983b8873ad644
1 #ifndef AL_SOURCE_H
2 #define AL_SOURCE_H
4 #include <array>
5 #include <cstddef>
6 #include <cstdint>
7 #include <deque>
8 #include <limits>
9 #include <string_view>
10 #include <utility>
12 #include "AL/al.h"
13 #include "AL/alc.h"
14 #include "AL/alext.h"
16 #include "almalloc.h"
17 #include "alnumbers.h"
18 #include "alnumeric.h"
19 #include "alspan.h"
20 #include "core/context.h"
21 #include "core/voice.h"
23 #ifdef ALSOFT_EAX
24 #include "eax/api.h"
25 #include "eax/call.h"
26 #include "eax/exception.h"
27 #include "eax/fx_slot_index.h"
28 #include "eax/utils.h"
29 #endif // ALSOFT_EAX
31 struct ALbuffer;
32 struct ALeffectslot;
33 enum class Resampler : uint8_t;
35 enum class SourceStereo : bool {
36 Normal = AL_NORMAL_SOFT,
37 Enhanced = AL_SUPER_STEREO_SOFT
40 inline constexpr size_t DefaultSendCount{2};
42 inline constexpr ALuint InvalidVoiceIndex{std::numeric_limits<ALuint>::max()};
44 inline bool sBufferSubDataCompat{false};
46 struct ALbufferQueueItem : public VoiceBufferItem {
47 ALbuffer *mBuffer{nullptr};
49 DISABLE_ALLOC
53 #ifdef ALSOFT_EAX
54 class EaxSourceException : public EaxException {
55 public:
56 explicit EaxSourceException(const char* message)
57 : EaxException{"EAX_SOURCE", message}
60 #endif // ALSOFT_EAX
62 struct ALsource {
63 /** Source properties. */
64 float Pitch{1.0f};
65 float Gain{1.0f};
66 float OuterGain{0.0f};
67 float MinGain{0.0f};
68 float MaxGain{1.0f};
69 float InnerAngle{360.0f};
70 float OuterAngle{360.0f};
71 float RefDistance{1.0f};
72 float MaxDistance{std::numeric_limits<float>::max()};
73 float RolloffFactor{1.0f};
74 #ifdef ALSOFT_EAX
75 // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
76 // AL_ROLLOFF_FACTOR
77 float RolloffFactor2{0.0f};
78 #endif
79 std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
80 std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
81 std::array<float,3> Direction{{0.0f, 0.0f, 0.0f}};
82 std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
83 std::array<float,3> OrientUp{{0.0f, 1.0f, 0.0f}};
84 bool HeadRelative{false};
85 bool Looping{false};
86 DistanceModel mDistanceModel{DistanceModel::Default};
87 Resampler mResampler{ResamplerDefault};
88 DirectMode DirectChannels{DirectMode::Off};
89 SpatializeMode mSpatialize{SpatializeMode::Auto};
90 SourceStereo mStereoMode{SourceStereo::Normal};
91 bool mPanningEnabled{false};
93 bool DryGainHFAuto{true};
94 bool WetGainAuto{true};
95 bool WetGainHFAuto{true};
96 float OuterGainHF{1.0f};
98 float AirAbsorptionFactor{0.0f};
99 float RoomRolloffFactor{0.0f};
100 float DopplerFactor{1.0f};
102 /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
103 * rather than clockwise.
105 std::array<float,2> StereoPan{{al::numbers::pi_v<float>/6.0f, -al::numbers::pi_v<float>/6.0f}};
107 float Radius{0.0f};
108 float EnhWidth{0.593f};
109 float mPan{0.0f};
111 /** Direct filter and auxiliary send info. */
112 struct DirectData {
113 float Gain{};
114 float GainHF{};
115 float HFReference{};
116 float GainLF{};
117 float LFReference{};
119 DirectData Direct;
121 struct SendData {
122 ALeffectslot *Slot{};
123 float Gain{};
124 float GainHF{};
125 float HFReference{};
126 float GainLF{};
127 float LFReference{};
129 std::array<SendData,MaxSendCount> Send;
132 * Last user-specified offset, and the offset type (bytes, samples, or
133 * seconds).
135 double Offset{0.0};
136 ALenum OffsetType{AL_NONE};
138 /** Source type (static, streaming, or undetermined) */
139 ALenum SourceType{AL_UNDETERMINED};
141 /** Source state (initial, playing, paused, or stopped) */
142 ALenum state{AL_INITIAL};
144 /** Source Buffer Queue head. */
145 std::deque<ALbufferQueueItem> mQueue;
147 bool mPropsDirty{true};
149 /* Index into the context's Voices array. Lazily updated, only checked and
150 * reset when looking up the voice.
152 ALuint VoiceIdx{InvalidVoiceIndex};
154 /** Self ID */
155 ALuint id{0};
158 ALsource() noexcept;
159 ~ALsource();
161 ALsource(const ALsource&) = delete;
162 ALsource& operator=(const ALsource&) = delete;
164 static void SetName(ALCcontext *context, ALuint id, std::string_view name);
166 DISABLE_ALLOC
168 #ifdef ALSOFT_EAX
169 public:
170 void eaxInitialize(ALCcontext *context) noexcept;
171 void eaxDispatch(const EaxCall& call);
172 void eaxCommit();
173 void eaxMarkAsChanged() noexcept { mEaxChanged = true; }
175 static ALsource* EaxLookupSource(ALCcontext& al_context, ALuint source_id) noexcept;
177 private:
178 using Exception = EaxSourceException;
180 static constexpr auto eax_max_speakers{9u};
182 using EaxFxSlotIds = std::array<const GUID*,EAX_MAX_FXSLOTS>;
184 static constexpr const EaxFxSlotIds eax4_fx_slot_ids{
185 &EAXPROPERTYID_EAX40_FXSlot0,
186 &EAXPROPERTYID_EAX40_FXSlot1,
187 &EAXPROPERTYID_EAX40_FXSlot2,
188 &EAXPROPERTYID_EAX40_FXSlot3,
191 static constexpr const EaxFxSlotIds eax5_fx_slot_ids{
192 &EAXPROPERTYID_EAX50_FXSlot0,
193 &EAXPROPERTYID_EAX50_FXSlot1,
194 &EAXPROPERTYID_EAX50_FXSlot2,
195 &EAXPROPERTYID_EAX50_FXSlot3,
198 using EaxActiveFxSlots = std::array<bool, EAX_MAX_FXSLOTS>;
199 using EaxSpeakerLevels = std::array<EAXSPEAKERLEVELPROPERTIES, eax_max_speakers>;
200 using EaxSends = std::array<EAXSOURCEALLSENDPROPERTIES, EAX_MAX_FXSLOTS>;
202 using Eax1Props = EAXBUFFER_REVERBPROPERTIES;
203 struct Eax1State {
204 Eax1Props i; // Immediate.
205 Eax1Props d; // Deferred.
208 using Eax2Props = EAX20BUFFERPROPERTIES;
209 struct Eax2State {
210 Eax2Props i; // Immediate.
211 Eax2Props d; // Deferred.
214 using Eax3Props = EAX30SOURCEPROPERTIES;
215 struct Eax3State {
216 Eax3Props i; // Immediate.
217 Eax3Props d; // Deferred.
220 struct Eax4Props {
221 Eax3Props source;
222 EaxSends sends;
223 EAX40ACTIVEFXSLOTS active_fx_slots;
226 struct Eax4State {
227 Eax4Props i; // Immediate.
228 Eax4Props d; // Deferred.
231 struct Eax5Props {
232 EAX50SOURCEPROPERTIES source;
233 EaxSends sends;
234 EAX50ACTIVEFXSLOTS active_fx_slots;
235 EaxSpeakerLevels speaker_levels;
238 struct Eax5State {
239 Eax5Props i; // Immediate.
240 Eax5Props d; // Deferred.
243 ALCcontext* mEaxAlContext{};
244 EaxFxSlotIndex mEaxPrimaryFxSlotId{};
245 EaxActiveFxSlots mEaxActiveFxSlots{};
246 int mEaxVersion{};
247 bool mEaxChanged{};
248 Eax1State mEax1{};
249 Eax2State mEax2{};
250 Eax3State mEax3{};
251 Eax4State mEax4{};
252 Eax5State mEax5{};
253 Eax5Props mEax{};
255 // ----------------------------------------------------------------------
256 // Source validators
258 struct Eax1SourceReverbMixValidator {
259 void operator()(float reverb_mix) const
261 if (reverb_mix == EAX_REVERBMIX_USEDISTANCE)
262 return;
264 eax_validate_range<Exception>(
265 "Reverb Mix",
266 reverb_mix,
267 EAX_BUFFER_MINREVERBMIX,
268 EAX_BUFFER_MAXREVERBMIX);
272 struct Eax2SourceDirectValidator {
273 void operator()(long lDirect) const
275 eax_validate_range<Exception>(
276 "Direct",
277 lDirect,
278 EAXSOURCE_MINDIRECT,
279 EAXSOURCE_MAXDIRECT);
283 struct Eax2SourceDirectHfValidator {
284 void operator()(long lDirectHF) const
286 eax_validate_range<Exception>(
287 "Direct HF",
288 lDirectHF,
289 EAXSOURCE_MINDIRECTHF,
290 EAXSOURCE_MAXDIRECTHF);
294 struct Eax2SourceRoomValidator {
295 void operator()(long lRoom) const
297 eax_validate_range<Exception>(
298 "Room",
299 lRoom,
300 EAXSOURCE_MINROOM,
301 EAXSOURCE_MAXROOM);
305 struct Eax2SourceRoomHfValidator {
306 void operator()(long lRoomHF) const
308 eax_validate_range<Exception>(
309 "Room HF",
310 lRoomHF,
311 EAXSOURCE_MINROOMHF,
312 EAXSOURCE_MAXROOMHF);
316 struct Eax2SourceRoomRolloffFactorValidator {
317 void operator()(float flRoomRolloffFactor) const
319 eax_validate_range<Exception>(
320 "Room Rolloff Factor",
321 flRoomRolloffFactor,
322 EAXSOURCE_MINROOMROLLOFFFACTOR,
323 EAXSOURCE_MAXROOMROLLOFFFACTOR);
327 struct Eax2SourceObstructionValidator {
328 void operator()(long lObstruction) const
330 eax_validate_range<Exception>(
331 "Obstruction",
332 lObstruction,
333 EAXSOURCE_MINOBSTRUCTION,
334 EAXSOURCE_MAXOBSTRUCTION);
338 struct Eax2SourceObstructionLfRatioValidator {
339 void operator()(float flObstructionLFRatio) const
341 eax_validate_range<Exception>(
342 "Obstruction LF Ratio",
343 flObstructionLFRatio,
344 EAXSOURCE_MINOBSTRUCTIONLFRATIO,
345 EAXSOURCE_MAXOBSTRUCTIONLFRATIO);
349 struct Eax2SourceOcclusionValidator {
350 void operator()(long lOcclusion) const
352 eax_validate_range<Exception>(
353 "Occlusion",
354 lOcclusion,
355 EAXSOURCE_MINOCCLUSION,
356 EAXSOURCE_MAXOCCLUSION);
360 struct Eax2SourceOcclusionLfRatioValidator {
361 void operator()(float flOcclusionLFRatio) const
363 eax_validate_range<Exception>(
364 "Occlusion LF Ratio",
365 flOcclusionLFRatio,
366 EAXSOURCE_MINOCCLUSIONLFRATIO,
367 EAXSOURCE_MAXOCCLUSIONLFRATIO);
371 struct Eax2SourceOcclusionRoomRatioValidator {
372 void operator()(float flOcclusionRoomRatio) const
374 eax_validate_range<Exception>(
375 "Occlusion Room Ratio",
376 flOcclusionRoomRatio,
377 EAXSOURCE_MINOCCLUSIONROOMRATIO,
378 EAXSOURCE_MAXOCCLUSIONROOMRATIO);
382 struct Eax2SourceOutsideVolumeHfValidator {
383 void operator()(long lOutsideVolumeHF) const
385 eax_validate_range<Exception>(
386 "Outside Volume HF",
387 lOutsideVolumeHF,
388 EAXSOURCE_MINOUTSIDEVOLUMEHF,
389 EAXSOURCE_MAXOUTSIDEVOLUMEHF);
393 struct Eax2SourceAirAbsorptionFactorValidator {
394 void operator()(float flAirAbsorptionFactor) const
396 eax_validate_range<Exception>(
397 "Air Absorption Factor",
398 flAirAbsorptionFactor,
399 EAXSOURCE_MINAIRABSORPTIONFACTOR,
400 EAXSOURCE_MAXAIRABSORPTIONFACTOR);
404 struct Eax2SourceFlagsValidator {
405 void operator()(unsigned long dwFlags) const
407 eax_validate_range<Exception>(
408 "Flags",
409 dwFlags,
410 0UL,
411 ~EAX20SOURCEFLAGS_RESERVED);
415 struct Eax3SourceOcclusionDirectRatioValidator {
416 void operator()(float flOcclusionDirectRatio) const
418 eax_validate_range<Exception>(
419 "Occlusion Direct Ratio",
420 flOcclusionDirectRatio,
421 EAXSOURCE_MINOCCLUSIONDIRECTRATIO,
422 EAXSOURCE_MAXOCCLUSIONDIRECTRATIO);
426 struct Eax3SourceExclusionValidator {
427 void operator()(long lExclusion) const
429 eax_validate_range<Exception>(
430 "Exclusion",
431 lExclusion,
432 EAXSOURCE_MINEXCLUSION,
433 EAXSOURCE_MAXEXCLUSION);
437 struct Eax3SourceExclusionLfRatioValidator {
438 void operator()(float flExclusionLFRatio) const
440 eax_validate_range<Exception>(
441 "Exclusion LF Ratio",
442 flExclusionLFRatio,
443 EAXSOURCE_MINEXCLUSIONLFRATIO,
444 EAXSOURCE_MAXEXCLUSIONLFRATIO);
448 struct Eax3SourceDopplerFactorValidator {
449 void operator()(float flDopplerFactor) const
451 eax_validate_range<Exception>(
452 "Doppler Factor",
453 flDopplerFactor,
454 EAXSOURCE_MINDOPPLERFACTOR,
455 EAXSOURCE_MAXDOPPLERFACTOR);
459 struct Eax3SourceRolloffFactorValidator {
460 void operator()(float flRolloffFactor) const
462 eax_validate_range<Exception>(
463 "Rolloff Factor",
464 flRolloffFactor,
465 EAXSOURCE_MINROLLOFFFACTOR,
466 EAXSOURCE_MAXROLLOFFFACTOR);
470 struct Eax5SourceMacroFXFactorValidator {
471 void operator()(float flMacroFXFactor) const
473 eax_validate_range<Exception>(
474 "Macro FX Factor",
475 flMacroFXFactor,
476 EAXSOURCE_MINMACROFXFACTOR,
477 EAXSOURCE_MAXMACROFXFACTOR);
481 struct Eax5SourceFlagsValidator {
482 void operator()(unsigned long dwFlags) const
484 eax_validate_range<Exception>(
485 "Flags",
486 dwFlags,
487 0UL,
488 ~EAX50SOURCEFLAGS_RESERVED);
492 struct Eax1SourceAllValidator {
493 void operator()(const Eax1Props& props) const
495 Eax1SourceReverbMixValidator{}(props.fMix);
499 struct Eax2SourceAllValidator {
500 void operator()(const Eax2Props& props) const
502 Eax2SourceDirectValidator{}(props.lDirect);
503 Eax2SourceDirectHfValidator{}(props.lDirectHF);
504 Eax2SourceRoomValidator{}(props.lRoom);
505 Eax2SourceRoomHfValidator{}(props.lRoomHF);
506 Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
507 Eax2SourceObstructionValidator{}(props.lObstruction);
508 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
509 Eax2SourceOcclusionValidator{}(props.lOcclusion);
510 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
511 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
512 Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
513 Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
514 Eax2SourceFlagsValidator{}(props.dwFlags);
518 struct Eax3SourceAllValidator {
519 void operator()(const Eax3Props& props) const
521 Eax2SourceDirectValidator{}(props.lDirect);
522 Eax2SourceDirectHfValidator{}(props.lDirectHF);
523 Eax2SourceRoomValidator{}(props.lRoom);
524 Eax2SourceRoomHfValidator{}(props.lRoomHF);
525 Eax2SourceObstructionValidator{}(props.lObstruction);
526 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
527 Eax2SourceOcclusionValidator{}(props.lOcclusion);
528 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
529 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
530 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
531 Eax3SourceExclusionValidator{}(props.lExclusion);
532 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
533 Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
534 Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
535 Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
536 Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
537 Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
538 Eax2SourceFlagsValidator{}(props.ulFlags);
542 struct Eax5SourceAllValidator {
543 void operator()(const EAX50SOURCEPROPERTIES& props) const
545 Eax2SourceDirectValidator{}(props.lDirect);
546 Eax2SourceDirectHfValidator{}(props.lDirectHF);
547 Eax2SourceRoomValidator{}(props.lRoom);
548 Eax2SourceRoomHfValidator{}(props.lRoomHF);
549 Eax2SourceObstructionValidator{}(props.lObstruction);
550 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
551 Eax2SourceOcclusionValidator{}(props.lOcclusion);
552 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
553 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
554 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
555 Eax3SourceExclusionValidator{}(props.lExclusion);
556 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
557 Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
558 Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
559 Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
560 Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
561 Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
562 Eax5SourceFlagsValidator{}(props.ulFlags);
563 Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor);
567 struct Eax5SourceAll2dValidator {
568 void operator()(const EAXSOURCE2DPROPERTIES& props) const
570 Eax2SourceDirectValidator{}(props.lDirect);
571 Eax2SourceDirectHfValidator{}(props.lDirectHF);
572 Eax2SourceRoomValidator{}(props.lRoom);
573 Eax2SourceRoomHfValidator{}(props.lRoomHF);
574 Eax5SourceFlagsValidator{}(props.ulFlags);
578 struct Eax4ObstructionValidator {
579 void operator()(const EAXOBSTRUCTIONPROPERTIES& props) const
581 Eax2SourceObstructionValidator{}(props.lObstruction);
582 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
586 struct Eax4OcclusionValidator {
587 void operator()(const EAXOCCLUSIONPROPERTIES& props) const
589 Eax2SourceOcclusionValidator{}(props.lOcclusion);
590 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
591 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
592 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
596 struct Eax4ExclusionValidator {
597 void operator()(const EAXEXCLUSIONPROPERTIES& props) const
599 Eax3SourceExclusionValidator{}(props.lExclusion);
600 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
604 // Source validators
605 // ----------------------------------------------------------------------
606 // Send validators
608 struct Eax4SendReceivingFxSlotIdValidator {
609 void operator()(const GUID& guidReceivingFXSlotID) const
611 if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 &&
612 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 &&
613 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 &&
614 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3)
616 eax_fail_unknown_receiving_fx_slot_id();
621 struct Eax5SendReceivingFxSlotIdValidator {
622 void operator()(const GUID& guidReceivingFXSlotID) const
624 if (guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 &&
625 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 &&
626 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 &&
627 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3)
629 eax_fail_unknown_receiving_fx_slot_id();
634 struct Eax4SendSendValidator {
635 void operator()(long lSend) const
637 eax_validate_range<Exception>(
638 "Send",
639 lSend,
640 EAXSOURCE_MINSEND,
641 EAXSOURCE_MAXSEND);
645 struct Eax4SendSendHfValidator {
646 void operator()(long lSendHF) const
648 eax_validate_range<Exception>(
649 "Send HF",
650 lSendHF,
651 EAXSOURCE_MINSENDHF,
652 EAXSOURCE_MAXSENDHF);
656 template<typename TIdValidator>
657 struct EaxSendValidator {
658 void operator()(const EAXSOURCESENDPROPERTIES& props) const
660 TIdValidator{}(props.guidReceivingFXSlotID);
661 Eax4SendSendValidator{}(props.lSend);
662 Eax4SendSendHfValidator{}(props.lSendHF);
666 struct Eax4SendValidator : EaxSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
667 struct Eax5SendValidator : EaxSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
669 template<typename TIdValidator>
670 struct EaxOcclusionSendValidator {
671 void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES& props) const
673 TIdValidator{}(props.guidReceivingFXSlotID);
674 Eax2SourceOcclusionValidator{}(props.lOcclusion);
675 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
676 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
677 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
681 struct Eax4OcclusionSendValidator : EaxOcclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
682 struct Eax5OcclusionSendValidator : EaxOcclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
684 template<typename TIdValidator>
685 struct EaxExclusionSendValidator {
686 void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES& props) const
688 TIdValidator{}(props.guidReceivingFXSlotID);
689 Eax3SourceExclusionValidator{}(props.lExclusion);
690 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
694 struct Eax4ExclusionSendValidator : EaxExclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
695 struct Eax5ExclusionSendValidator : EaxExclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
697 template<typename TIdValidator>
698 struct EaxAllSendValidator {
699 void operator()(const EAXSOURCEALLSENDPROPERTIES& props) const
701 TIdValidator{}(props.guidReceivingFXSlotID);
702 Eax4SendSendValidator{}(props.lSend);
703 Eax4SendSendHfValidator{}(props.lSendHF);
704 Eax2SourceOcclusionValidator{}(props.lOcclusion);
705 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
706 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
707 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
708 Eax3SourceExclusionValidator{}(props.lExclusion);
709 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
713 struct Eax4AllSendValidator : EaxAllSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
714 struct Eax5AllSendValidator : EaxAllSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
716 // Send validators
717 // ----------------------------------------------------------------------
718 // Active FX slot ID validators
720 struct Eax4ActiveFxSlotIdValidator {
721 void operator()(const GUID &guid) const
723 if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
724 && guid != EAXPROPERTYID_EAX40_FXSlot0 && guid != EAXPROPERTYID_EAX40_FXSlot1
725 && guid != EAXPROPERTYID_EAX40_FXSlot2 && guid != EAXPROPERTYID_EAX40_FXSlot3)
727 eax_fail_unknown_active_fx_slot_id();
732 struct Eax5ActiveFxSlotIdValidator {
733 void operator()(const GUID &guid) const
735 if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
736 && guid != EAXPROPERTYID_EAX50_FXSlot0 && guid != EAXPROPERTYID_EAX50_FXSlot1
737 && guid != EAXPROPERTYID_EAX50_FXSlot2 && guid != EAXPROPERTYID_EAX50_FXSlot3)
739 eax_fail_unknown_active_fx_slot_id();
744 // Active FX slot ID validators
745 // ----------------------------------------------------------------------
746 // Speaker level validators.
748 struct Eax5SpeakerIdValidator {
749 void operator()(long lSpeakerID) const
751 switch (lSpeakerID) {
752 case EAXSPEAKER_FRONT_LEFT:
753 case EAXSPEAKER_FRONT_CENTER:
754 case EAXSPEAKER_FRONT_RIGHT:
755 case EAXSPEAKER_SIDE_RIGHT:
756 case EAXSPEAKER_REAR_RIGHT:
757 case EAXSPEAKER_REAR_CENTER:
758 case EAXSPEAKER_REAR_LEFT:
759 case EAXSPEAKER_SIDE_LEFT:
760 case EAXSPEAKER_LOW_FREQUENCY:
761 break;
763 default:
764 eax_fail("Unknown speaker ID.");
769 struct Eax5SpeakerLevelValidator {
770 void operator()(long lLevel) const
772 // TODO Use a range when the feature will be implemented.
773 if (lLevel != EAXSOURCE_DEFAULTSPEAKERLEVEL)
774 eax_fail("Speaker level out of range.");
778 struct Eax5SpeakerAllValidator {
779 void operator()(const EAXSPEAKERLEVELPROPERTIES& all) const
781 Eax5SpeakerIdValidator{}(all.lSpeakerID);
782 Eax5SpeakerLevelValidator{}(all.lLevel);
786 // Speaker level validators.
787 // ----------------------------------------------------------------------
789 struct Eax4SendIndexGetter {
790 EaxFxSlotIndexValue operator()(const GUID &guid) const
792 if(guid == EAXPROPERTYID_EAX40_FXSlot0)
793 return 0;
794 if(guid == EAXPROPERTYID_EAX40_FXSlot1)
795 return 1;
796 if(guid == EAXPROPERTYID_EAX40_FXSlot2)
797 return 2;
798 if(guid == EAXPROPERTYID_EAX40_FXSlot3)
799 return 3;
800 eax_fail_unknown_receiving_fx_slot_id();
804 struct Eax5SendIndexGetter {
805 EaxFxSlotIndexValue operator()(const GUID &guid) const
807 if(guid == EAXPROPERTYID_EAX50_FXSlot0)
808 return 0;
809 if(guid == EAXPROPERTYID_EAX50_FXSlot1)
810 return 1;
811 if(guid == EAXPROPERTYID_EAX50_FXSlot2)
812 return 2;
813 if(guid == EAXPROPERTYID_EAX50_FXSlot3)
814 return 3;
815 eax_fail_unknown_receiving_fx_slot_id();
819 [[noreturn]] static void eax_fail(const char* message);
820 [[noreturn]] static void eax_fail_unknown_property_id();
821 [[noreturn]] static void eax_fail_unknown_version();
822 [[noreturn]] static void eax_fail_unknown_active_fx_slot_id();
823 [[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id();
825 static void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
826 static void eax1_set_defaults(Eax1Props& props) noexcept;
827 void eax1_set_defaults() noexcept;
828 static void eax2_set_defaults(Eax2Props& props) noexcept;
829 void eax2_set_defaults() noexcept;
830 static void eax3_set_defaults(Eax3Props& props) noexcept;
831 void eax3_set_defaults() noexcept;
832 static void eax4_set_sends_defaults(EaxSends& sends) noexcept;
833 static void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
834 void eax4_set_defaults() noexcept;
835 static void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
836 static void eax5_set_sends_defaults(EaxSends& sends) noexcept;
837 static void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
838 static void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
839 static void eax5_set_defaults(Eax5Props& props) noexcept;
840 void eax5_set_defaults() noexcept;
841 void eax_set_defaults() noexcept;
843 static void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
844 static void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
845 static void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
846 static void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
848 static float eax_calculate_dst_occlusion_mb(
849 long src_occlusion_mb,
850 float path_ratio,
851 float lf_ratio) noexcept;
853 [[nodiscard]] auto eax_create_direct_filter_param() const noexcept -> EaxAlLowPassParam;
855 [[nodiscard]] auto eax_create_room_filter_param(const ALeffectslot& fx_slot,
856 const EAXSOURCEALLSENDPROPERTIES& send) const noexcept -> EaxAlLowPassParam;
858 void eax_update_direct_filter();
859 void eax_update_room_filters();
860 void eax_commit_filters();
862 static void eax_copy_send_for_get(
863 const EAXSOURCEALLSENDPROPERTIES& src,
864 EAXSOURCESENDPROPERTIES& dst) noexcept
866 dst = reinterpret_cast<const EAXSOURCESENDPROPERTIES&>(src);
869 static void eax_copy_send_for_get(
870 const EAXSOURCEALLSENDPROPERTIES& src,
871 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
873 dst = src;
876 static void eax_copy_send_for_get(
877 const EAXSOURCEALLSENDPROPERTIES& src,
878 EAXSOURCEOCCLUSIONSENDPROPERTIES& dst) noexcept
880 dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
881 dst.lOcclusion = src.lOcclusion;
882 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
883 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
884 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
887 static void eax_copy_send_for_get(
888 const EAXSOURCEALLSENDPROPERTIES& src,
889 EAXSOURCEEXCLUSIONSENDPROPERTIES& dst) noexcept
891 dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
892 dst.lExclusion = src.lExclusion;
893 dst.flExclusionLFRatio = src.flExclusionLFRatio;
896 template<typename TDstSend>
897 void eax_get_sends(const EaxCall& call, const EaxSends& src_sends)
899 const auto dst_sends = call.get_values<TDstSend>(EAX_MAX_FXSLOTS);
900 const auto count = dst_sends.size();
902 for (auto i = decltype(count){}; i < count; ++i) {
903 const auto& src_send = src_sends[i];
904 auto& dst_send = dst_sends[i];
905 eax_copy_send_for_get(src_send, dst_send);
909 static void eax_get_active_fx_slot_id(const EaxCall& call, const al::span<const GUID> src_ids);
910 static void eax1_get(const EaxCall& call, const Eax1Props& props);
911 static void eax2_get(const EaxCall& call, const Eax2Props& props);
912 static void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
913 static void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
914 static void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
915 static void eax3_get(const EaxCall& call, const Eax3Props& props);
916 void eax4_get(const EaxCall& call, const Eax4Props& props);
917 static void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
918 static void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
919 void eax5_get(const EaxCall& call, const Eax5Props& props);
920 void eax_get(const EaxCall& call);
922 static void eax_copy_send_for_set(
923 const EAXSOURCESENDPROPERTIES& src,
924 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
926 dst.lSend = src.lSend;
927 dst.lSendHF = src.lSendHF;
930 static void eax_copy_send_for_set(
931 const EAXSOURCEALLSENDPROPERTIES& src,
932 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
934 dst.lSend = src.lSend;
935 dst.lSendHF = src.lSendHF;
936 dst.lOcclusion = src.lOcclusion;
937 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
938 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
939 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
940 dst.lExclusion = src.lExclusion;
941 dst.flExclusionLFRatio = src.flExclusionLFRatio;
944 static void eax_copy_send_for_set(
945 const EAXSOURCEOCCLUSIONSENDPROPERTIES& src,
946 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
948 dst.lOcclusion = src.lOcclusion;
949 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
950 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
951 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
954 static void eax_copy_send_for_set(
955 const EAXSOURCEEXCLUSIONSENDPROPERTIES& src,
956 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
958 dst.lExclusion = src.lExclusion;
959 dst.flExclusionLFRatio = src.flExclusionLFRatio;
962 template<typename TValidator, typename TIndexGetter, typename TSrcSend>
963 void eax_defer_sends(const EaxCall& call, EaxSends& dst_sends)
965 const auto src_sends = call.get_values<const TSrcSend>(EAX_MAX_FXSLOTS);
966 std::for_each(src_sends.cbegin(), src_sends.cend(), TValidator{});
967 const auto count = src_sends.size();
968 const auto index_getter = TIndexGetter{};
970 for (auto i = decltype(count){}; i < count; ++i) {
971 const auto& src_send = src_sends[i];
972 const auto dst_index = index_getter(src_send.guidReceivingFXSlotID);
973 auto& dst_send = dst_sends[dst_index];
974 eax_copy_send_for_set(src_send, dst_send);
978 template<typename TValidator, typename TSrcSend>
979 void eax4_defer_sends(const EaxCall& call, EaxSends& dst_sends)
981 eax_defer_sends<TValidator, Eax4SendIndexGetter, TSrcSend>(call, dst_sends);
984 template<typename TValidator, typename TSrcSend>
985 void eax5_defer_sends(const EaxCall& call, EaxSends& dst_sends)
987 eax_defer_sends<TValidator, Eax5SendIndexGetter, TSrcSend>(call, dst_sends);
990 template<typename TValidator, size_t TIdCount>
991 void eax_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
993 const auto src_ids = call.get_values<const GUID>(TIdCount);
994 std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
995 std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids.begin());
998 template<size_t TIdCount>
999 void eax4_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
1001 eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
1004 template<size_t TIdCount>
1005 void eax5_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
1007 eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
1010 template<typename TValidator, typename TProperty>
1011 static void eax_defer(const EaxCall& call, TProperty& property)
1013 const auto& value = call.get_value<Exception, const TProperty>();
1014 TValidator{}(value);
1015 property = value;
1018 // Defers source's sub-properties (obstruction, occlusion, exclusion).
1019 template<typename TValidator, typename TSubproperty, typename TProperty>
1020 void eax_defer_sub(const EaxCall& call, TProperty& property)
1022 const auto& src_props = call.get_value<Exception, const TSubproperty>();
1023 TValidator{}(src_props);
1024 auto& dst_props = reinterpret_cast<TSubproperty&>(property);
1025 dst_props = src_props;
1028 void eax_set_efx_outer_gain_hf();
1029 void eax_set_efx_doppler_factor();
1030 void eax_set_efx_rolloff_factor();
1031 void eax_set_efx_room_rolloff_factor();
1032 void eax_set_efx_air_absorption_factor();
1033 void eax_set_efx_dry_gain_hf_auto();
1034 void eax_set_efx_wet_gain_auto();
1035 void eax_set_efx_wet_gain_hf_auto();
1037 static void eax1_set(const EaxCall& call, Eax1Props& props);
1038 static void eax2_set(const EaxCall& call, Eax2Props& props);
1039 void eax3_set(const EaxCall& call, Eax3Props& props);
1040 void eax4_set(const EaxCall& call, Eax4Props& props);
1041 static void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
1042 static void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
1043 void eax5_set(const EaxCall& call, Eax5Props& props);
1044 void eax_set(const EaxCall& call);
1046 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
1047 void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx,
1048 const EaxAlLowPassParam &filter);
1050 void eax_commit_active_fx_slots();
1051 #endif // ALSOFT_EAX
1054 void UpdateAllSourceProps(ALCcontext *context);
1056 struct SourceSubList {
1057 uint64_t FreeMask{~0_u64};
1058 gsl::owner<std::array<ALsource,64>*> Sources{nullptr};
1060 SourceSubList() noexcept = default;
1061 SourceSubList(const SourceSubList&) = delete;
1062 SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources}
1063 { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; }
1064 ~SourceSubList();
1066 SourceSubList& operator=(const SourceSubList&) = delete;
1067 SourceSubList& operator=(SourceSubList&& rhs) noexcept
1068 { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; }
1071 #endif