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