aboutsummaryrefslogtreecommitdiffstats
path: root/al/source.h
blob: 6db6bfa7aa2bf8dbb68a7bd4058c89b7de0e5086 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
#ifndef AL_SOURCE_H
#define AL_SOURCE_H

#include <array>
#include <atomic>
#include <cstddef>
#include <iterator>
#include <limits>
#include <deque>

#include "AL/al.h"
#include "AL/alc.h"

#include "alc/alu.h"
#include "alc/context.h"
#include "alc/inprogext.h"
#include "aldeque.h"
#include "almalloc.h"
#include "alnumeric.h"
#include "atomic.h"
#include "core/voice.h"
#include "vector.h"

#ifdef ALSOFT_EAX
#include "eax_eax_call.h"
#include "eax_fx_slot_index.h"
#include "eax_utils.h"
#endif // ALSOFT_EAX

struct ALbuffer;
struct ALeffectslot;


enum class SourceStereo : bool {
    Normal = AL_NORMAL_SOFT,
    Enhanced = AL_SUPER_STEREO_SOFT
};

#define DEFAULT_SENDS  2

#define INVALID_VOICE_IDX static_cast<ALuint>(-1)

struct ALbufferQueueItem : public VoiceBufferItem {
    ALbuffer *mBuffer{nullptr};

    DISABLE_ALLOC()
};


#ifdef ALSOFT_EAX
using EaxSourceSourceFilterDirtyFlagsValue = std::uint_least16_t;

struct EaxSourceSourceFilterDirtyFlags
{
    using EaxIsBitFieldStruct = bool;

	EaxSourceSourceFilterDirtyFlagsValue lDirect : 1;
	EaxSourceSourceFilterDirtyFlagsValue lDirectHF : 1;
	EaxSourceSourceFilterDirtyFlagsValue lRoom : 1;
	EaxSourceSourceFilterDirtyFlagsValue lRoomHF : 1;
	EaxSourceSourceFilterDirtyFlagsValue lObstruction : 1;
	EaxSourceSourceFilterDirtyFlagsValue flObstructionLFRatio : 1;
	EaxSourceSourceFilterDirtyFlagsValue lOcclusion : 1;
	EaxSourceSourceFilterDirtyFlagsValue flOcclusionLFRatio : 1;
	EaxSourceSourceFilterDirtyFlagsValue flOcclusionRoomRatio : 1;
	EaxSourceSourceFilterDirtyFlagsValue flOcclusionDirectRatio : 1;
	EaxSourceSourceFilterDirtyFlagsValue lExclusion : 1;
	EaxSourceSourceFilterDirtyFlagsValue flExclusionLFRatio : 1;
}; // EaxSourceSourceFilterDirtyFlags


using EaxSourceSourceMiscDirtyFlagsValue = std::uint_least8_t;

struct EaxSourceSourceMiscDirtyFlags
{
    using EaxIsBitFieldStruct = bool;

	EaxSourceSourceMiscDirtyFlagsValue lOutsideVolumeHF : 1;
	EaxSourceSourceMiscDirtyFlagsValue flDopplerFactor : 1;
	EaxSourceSourceMiscDirtyFlagsValue flRolloffFactor : 1;
	EaxSourceSourceMiscDirtyFlagsValue flRoomRolloffFactor : 1;
	EaxSourceSourceMiscDirtyFlagsValue flAirAbsorptionFactor : 1;
	EaxSourceSourceMiscDirtyFlagsValue ulFlags : 1;
	EaxSourceSourceMiscDirtyFlagsValue flMacroFXFactor : 1;
	EaxSourceSourceMiscDirtyFlagsValue speaker_levels : 1;
}; // EaxSourceSourceMiscDirtyFlags


using EaxSourceSendDirtyFlagsValue = std::uint_least8_t;

struct EaxSourceSendDirtyFlags
{
    using EaxIsBitFieldStruct = bool;

	EaxSourceSendDirtyFlagsValue lSend : 1;
	EaxSourceSendDirtyFlagsValue lSendHF : 1;
	EaxSourceSendDirtyFlagsValue lOcclusion : 1;
	EaxSourceSendDirtyFlagsValue flOcclusionLFRatio : 1;
	EaxSourceSendDirtyFlagsValue flOcclusionRoomRatio : 1;
	EaxSourceSendDirtyFlagsValue flOcclusionDirectRatio : 1;
	EaxSourceSendDirtyFlagsValue lExclusion : 1;
	EaxSourceSendDirtyFlagsValue flExclusionLFRatio : 1;
}; // EaxSourceSendDirtyFlags


struct EaxSourceSendsDirtyFlags
{
    using EaxIsBitFieldStruct = bool;

	EaxSourceSendDirtyFlags sends[EAX_MAX_FXSLOTS];
}; // EaxSourceSendsDirtyFlags
#endif // ALSOFT_EAX

struct ALsource {
    /** Source properties. */
    float Pitch{1.0f};
    float Gain{1.0f};
    float OuterGain{0.0f};
    float MinGain{0.0f};
    float MaxGain{1.0f};
    float InnerAngle{360.0f};
    float OuterAngle{360.0f};
    float RefDistance{1.0f};
    float MaxDistance{std::numeric_limits<float>::max()};
    float RolloffFactor{1.0f};
#ifdef ALSOFT_EAX
    // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
    // AL_ROLLOFF_FACTOR
    float RolloffFactor2{0.0f};
#endif
    std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
    std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
    std::array<float,3> Direction{{0.0f, 0.0f, 0.0f}};
    std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
    std::array<float,3> OrientUp{{0.0f, 1.0f,  0.0f}};
    bool HeadRelative{false};
    bool Looping{false};
    DistanceModel mDistanceModel{DistanceModel::Default};
    Resampler mResampler{ResamplerDefault};
    DirectMode DirectChannels{DirectMode::Off};
    SpatializeMode mSpatialize{SpatializeMode::Auto};
    SourceStereo mStereoMode{SourceStereo::Normal};

    bool DryGainHFAuto{true};
    bool WetGainAuto{true};
    bool WetGainHFAuto{true};
    float OuterGainHF{1.0f};

    float AirAbsorptionFactor{0.0f};
    float RoomRolloffFactor{0.0f};
    float DopplerFactor{1.0f};

    /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
     * rather than clockwise.
     */
    std::array<float,2> StereoPan{{al::numbers::pi_v<float>/6.0f, -al::numbers::pi_v<float>/6.0f}};

    float Radius{0.0f};
    float EnhWidth{0.593f};

    /** Direct filter and auxiliary send info. */
    struct {
        float Gain;
        float GainHF;
        float HFReference;
        float GainLF;
        float LFReference;
    } Direct;
    struct SendData {
        ALeffectslot *Slot;
        float Gain;
        float GainHF;
        float HFReference;
        float GainLF;
        float LFReference;
    };
    std::array<SendData,MAX_SENDS> Send;

    /**
     * Last user-specified offset, and the offset type (bytes, samples, or
     * seconds).
     */
    double Offset{0.0};
    ALenum OffsetType{AL_NONE};

    /** Source type (static, streaming, or undetermined) */
    ALenum SourceType{AL_UNDETERMINED};

    /** Source state (initial, playing, paused, or stopped) */
    ALenum state{AL_INITIAL};

    /** Source Buffer Queue head. */
    al::deque<ALbufferQueueItem> mQueue;

    bool mPropsDirty{true};

    /* Index into the context's Voices array. Lazily updated, only checked and
     * reset when looking up the voice.
     */
    ALuint VoiceIdx{INVALID_VOICE_IDX};

    /** Self ID */
    ALuint id{0};


    ALsource();
    ~ALsource();

    ALsource(const ALsource&) = delete;
    ALsource& operator=(const ALsource&) = delete;

    DISABLE_ALLOC()

#ifdef ALSOFT_EAX
public:
    void eax_initialize(ALCcontext *context) noexcept;


    void eax_dispatch(const EaxEaxCall& eax_call)
    { eax_call.is_get() ? eax_get(eax_call) : eax_set(eax_call); }


    void eax_update_filters();

    void eax_update(
        EaxContextSharedDirtyFlags dirty_flags);

    void eax_commit() { eax_apply_deferred(); }
    void eax_commit_and_update();

    bool eax_is_initialized() const noexcept { return eax_al_context_; }


    static ALsource* eax_lookup_source(
        ALCcontext& al_context,
        ALuint source_id) noexcept;


private:
    static constexpr auto eax_max_speakers = 9;


    using EaxActiveFxSlots = std::array<bool, EAX_MAX_FXSLOTS>;
    using EaxSpeakerLevels = std::array<long, eax_max_speakers>;

    struct Eax
    {
        using Sends = std::array<EAXSOURCEALLSENDPROPERTIES, EAX_MAX_FXSLOTS>;

        EAX50ACTIVEFXSLOTS active_fx_slots{};
        EAX50SOURCEPROPERTIES source{};
        Sends sends{};
        EaxSpeakerLevels speaker_levels{};
    }; // Eax


    bool eax_uses_primary_id_{};
    bool eax_has_active_fx_slots_{};
    bool eax_are_active_fx_slots_dirty_{};

    ALCcontext* eax_al_context_{};

    EAXBUFFER_REVERBPROPERTIES eax1_{};
    Eax eax_{};
    Eax eax_d_{};
    EaxActiveFxSlots eax_active_fx_slots_{};

    EaxSourceSendsDirtyFlags eax_sends_dirty_flags_{};
    EaxSourceSourceFilterDirtyFlags eax_source_dirty_filter_flags_{};
    EaxSourceSourceMiscDirtyFlags eax_source_dirty_misc_flags_{};


    [[noreturn]]
    static void eax_fail(
        const char* message);


    void eax_set_source_defaults() noexcept;
    void eax_set_active_fx_slots_defaults() noexcept;
    void eax_set_send_defaults(EAXSOURCEALLSENDPROPERTIES& eax_send) noexcept;
    void eax_set_sends_defaults() noexcept;
    void eax_set_speaker_levels_defaults() noexcept;
    void eax_set_defaults() noexcept;


    static float eax_calculate_dst_occlusion_mb(
        long src_occlusion_mb,
        float path_ratio,
        float lf_ratio) noexcept;

    EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;

    EaxAlLowPassParam eax_create_room_filter_param(
        const ALeffectslot& fx_slot,
        const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;

    void eax_set_fx_slots();

    void eax_initialize_fx_slots();

    void eax_update_direct_filter_internal();

    void eax_update_room_filters_internal();

    void eax_update_filters_internal();

    void eax_update_primary_fx_slot_id();


    void eax_defer_active_fx_slots(
        const EaxEaxCall& eax_call);


    static const char* eax_get_exclusion_name() noexcept;

    static const char* eax_get_exclusion_lf_ratio_name() noexcept;


    static const char* eax_get_occlusion_name() noexcept;

    static const char* eax_get_occlusion_lf_ratio_name() noexcept;

    static const char* eax_get_occlusion_direct_ratio_name() noexcept;

    static const char* eax_get_occlusion_room_ratio_name() noexcept;


    static void eax1_validate_reverb_mix(float reverb_mix);

    static void eax_validate_send_receiving_fx_slot_guid(
        const GUID& guidReceivingFXSlotID);

    static void eax_validate_send_send(
        long lSend);

    static void eax_validate_send_send_hf(
        long lSendHF);

    static void eax_validate_send_occlusion(
        long lOcclusion);

    static void eax_validate_send_occlusion_lf_ratio(
        float flOcclusionLFRatio);

    static void eax_validate_send_occlusion_room_ratio(
        float flOcclusionRoomRatio);

    static void eax_validate_send_occlusion_direct_ratio(
        float flOcclusionDirectRatio);

    static void eax_validate_send_exclusion(
        long lExclusion);

    static void eax_validate_send_exclusion_lf_ratio(
        float flExclusionLFRatio);

    static void eax_validate_send(
        const EAXSOURCESENDPROPERTIES& all);

    static void eax_validate_send_exclusion_all(
        const EAXSOURCEEXCLUSIONSENDPROPERTIES& all);

    static void eax_validate_send_occlusion_all(
        const EAXSOURCEOCCLUSIONSENDPROPERTIES& all);

    static void eax_validate_send_all(
        const EAXSOURCEALLSENDPROPERTIES& all);


    static EaxFxSlotIndexValue eax_get_send_index(
        const GUID& send_guid);


    void eax_defer_send_send(
        long lSend,
        EaxFxSlotIndexValue index);

    void eax_defer_send_send_hf(
        long lSendHF,
        EaxFxSlotIndexValue index);

    void eax_defer_send_occlusion(
        long lOcclusion,
        EaxFxSlotIndexValue index);

    void eax_defer_send_occlusion_lf_ratio(
        float flOcclusionLFRatio,
        EaxFxSlotIndexValue index);

    void eax_defer_send_occlusion_room_ratio(
        float flOcclusionRoomRatio,
        EaxFxSlotIndexValue index);

    void eax_defer_send_occlusion_direct_ratio(
        float flOcclusionDirectRatio,
        EaxFxSlotIndexValue index);

    void eax_defer_send_exclusion(
        long lExclusion,
        EaxFxSlotIndexValue index);

    void eax_defer_send_exclusion_lf_ratio(
        float flExclusionLFRatio,
        EaxFxSlotIndexValue index);

    void eax_defer_send(
        const EAXSOURCESENDPROPERTIES& all,
        EaxFxSlotIndexValue index);

    void eax_defer_send_exclusion_all(
        const EAXSOURCEEXCLUSIONSENDPROPERTIES& all,
        EaxFxSlotIndexValue index);

    void eax_defer_send_occlusion_all(
        const EAXSOURCEOCCLUSIONSENDPROPERTIES& all,
        EaxFxSlotIndexValue index);

    void eax_defer_send_all(
        const EAXSOURCEALLSENDPROPERTIES& all,
        EaxFxSlotIndexValue index);


    void eax_defer_send(
        const EaxEaxCall& eax_call);

    void eax_defer_send_exclusion_all(
        const EaxEaxCall& eax_call);

    void eax_defer_send_occlusion_all(
        const EaxEaxCall& eax_call);

    void eax_defer_send_all(
        const EaxEaxCall& eax_call);


    static void eax_validate_source_direct(
        long direct);

    static void eax_validate_source_direct_hf(
        long direct_hf);

    static void eax_validate_source_room(
        long room);

    static void eax_validate_source_room_hf(
        long room_hf);

    static void eax_validate_source_obstruction(
        long obstruction);

    static void eax_validate_source_obstruction_lf_ratio(
        float obstruction_lf_ratio);

    static void eax_validate_source_occlusion(
        long occlusion);

    static void eax_validate_source_occlusion_lf_ratio(
        float occlusion_lf_ratio);

    static void eax_validate_source_occlusion_room_ratio(
        float occlusion_room_ratio);

    static void eax_validate_source_occlusion_direct_ratio(
        float occlusion_direct_ratio);

    static void eax_validate_source_exclusion(
        long exclusion);

    static void eax_validate_source_exclusion_lf_ratio(
        float exclusion_lf_ratio);

    static void eax_validate_source_outside_volume_hf(
        long outside_volume_hf);

    static void eax_validate_source_doppler_factor(
        float doppler_factor);

    static void eax_validate_source_rolloff_factor(
        float rolloff_factor);

    static void eax_validate_source_room_rolloff_factor(
        float room_rolloff_factor);

    static void eax_validate_source_air_absorption_factor(
        float air_absorption_factor);

    static void eax_validate_source_flags(
        unsigned long flags,
        int eax_version);

    static void eax_validate_source_macro_fx_factor(
        float macro_fx_factor);

    static void eax_validate_source_2d_all(
        const EAXSOURCE2DPROPERTIES& all,
        int eax_version);

    static void eax_validate_source_obstruction_all(
        const EAXOBSTRUCTIONPROPERTIES& all);

    static void eax_validate_source_exclusion_all(
        const EAXEXCLUSIONPROPERTIES& all);

    static void eax_validate_source_occlusion_all(
        const EAXOCCLUSIONPROPERTIES& all);

    static void eax_validate_source_all(
        const EAX20BUFFERPROPERTIES& all,
        int eax_version);

    static void eax_validate_source_all(
        const EAX30SOURCEPROPERTIES& all,
        int eax_version);

    static void eax_validate_source_all(
        const EAX50SOURCEPROPERTIES& all,
        int eax_version);

    static void eax_validate_source_speaker_id(
        long speaker_id);

    static void eax_validate_source_speaker_level(
        long speaker_level);

    static void eax_validate_source_speaker_level_all(
        const EAXSPEAKERLEVELPROPERTIES& all);


    void eax_defer_source_direct(
        long lDirect);

    void eax_defer_source_direct_hf(
        long lDirectHF);

    void eax_defer_source_room(
        long lRoom);

    void eax_defer_source_room_hf(
        long lRoomHF);

    void eax_defer_source_obstruction(
        long lObstruction);

    void eax_defer_source_obstruction_lf_ratio(
        float flObstructionLFRatio);

    void eax_defer_source_occlusion(
        long lOcclusion);

    void eax_defer_source_occlusion_lf_ratio(
        float flOcclusionLFRatio);

    void eax_defer_source_occlusion_room_ratio(
        float flOcclusionRoomRatio);

    void eax_defer_source_occlusion_direct_ratio(
        float flOcclusionDirectRatio);

    void eax_defer_source_exclusion(
        long lExclusion);

    void eax_defer_source_exclusion_lf_ratio(
        float flExclusionLFRatio);

    void eax_defer_source_outside_volume_hf(
        long lOutsideVolumeHF);

    void eax_defer_source_doppler_factor(
        float flDopplerFactor);

    void eax_defer_source_rolloff_factor(
        float flRolloffFactor);

    void eax_defer_source_room_rolloff_factor(
        float flRoomRolloffFactor);

    void eax_defer_source_air_absorption_factor(
        float flAirAbsorptionFactor);

    void eax_defer_source_flags(
        unsigned long ulFlags);

    void eax_defer_source_macro_fx_factor(
        float flMacroFXFactor);

    void eax_defer_source_2d_all(
        const EAXSOURCE2DPROPERTIES& all);

    void eax_defer_source_obstruction_all(
        const EAXOBSTRUCTIONPROPERTIES& all);

    void eax_defer_source_exclusion_all(
        const EAXEXCLUSIONPROPERTIES& all);

    void eax_defer_source_occlusion_all(
        const EAXOCCLUSIONPROPERTIES& all);

    void eax_defer_source_all(
        const EAX20BUFFERPROPERTIES& all);

    void eax_defer_source_all(
        const EAX30SOURCEPROPERTIES& all);

    void eax_defer_source_all(
        const EAX50SOURCEPROPERTIES& all);

    void eax_defer_source_speaker_level_all(
        const EAXSPEAKERLEVELPROPERTIES& all);


    void eax_defer_source_direct(
        const EaxEaxCall& eax_call);

    void eax_defer_source_direct_hf(
        const EaxEaxCall& eax_call);

    void eax_defer_source_room(
        const EaxEaxCall& eax_call);

    void eax_defer_source_room_hf(
        const EaxEaxCall& eax_call);

    void eax_defer_source_obstruction(
        const EaxEaxCall& eax_call);

    void eax_defer_source_obstruction_lf_ratio(
        const EaxEaxCall& eax_call);

    void eax_defer_source_occlusion(
        const EaxEaxCall& eax_call);

    void eax_defer_source_occlusion_lf_ratio(
        const EaxEaxCall& eax_call);

    void eax_defer_source_occlusion_room_ratio(
        const EaxEaxCall& eax_call);

    void eax_defer_source_occlusion_direct_ratio(
        const EaxEaxCall& eax_call);

    void eax_defer_source_exclusion(
        const EaxEaxCall& eax_call);

    void eax_defer_source_exclusion_lf_ratio(
        const EaxEaxCall& eax_call);

    void eax_defer_source_outside_volume_hf(
        const EaxEaxCall& eax_call);

    void eax_defer_source_doppler_factor(
        const EaxEaxCall& eax_call);

    void eax_defer_source_rolloff_factor(
        const EaxEaxCall& eax_call);

    void eax_defer_source_room_rolloff_factor(
        const EaxEaxCall& eax_call);

    void eax_defer_source_air_absorption_factor(
        const EaxEaxCall& eax_call);

    void eax_defer_source_flags(
        const EaxEaxCall& eax_call);

    void eax_defer_source_macro_fx_factor(
        const EaxEaxCall& eax_call);

    void eax_defer_source_2d_all(
        const EaxEaxCall& eax_call);

    void eax_defer_source_obstruction_all(
        const EaxEaxCall& eax_call);

    void eax_defer_source_exclusion_all(
        const EaxEaxCall& eax_call);

    void eax_defer_source_occlusion_all(
        const EaxEaxCall& eax_call);

    void eax_defer_source_all(
        const EaxEaxCall& eax_call);

    void eax_defer_source_speaker_level_all(
        const EaxEaxCall& eax_call);


    void eax_set_outside_volume_hf();

    void eax_set_doppler_factor();

    void eax_set_rolloff_factor();

    void eax_set_room_rolloff_factor();

    void eax_set_air_absorption_factor();


    void eax_set_direct_hf_auto_flag();

    void eax_set_room_auto_flag();

    void eax_set_room_hf_auto_flag();

    void eax_set_flags();


    void eax_set_macro_fx_factor();

    void eax_set_speaker_levels();


    void eax1_set_efx();
    void eax1_set_reverb_mix(const EaxEaxCall& eax_call);
    void eax1_set(const EaxEaxCall& eax_call);

    void eax_apply_deferred();

    void eax_set(
        const EaxEaxCall& eax_call);


    static const GUID& eax_get_send_fx_slot_guid(
        int eax_version,
        EaxFxSlotIndexValue fx_slot_index);

    static void eax_copy_send(
        const EAXSOURCEALLSENDPROPERTIES& src_send,
        EAXSOURCESENDPROPERTIES& dst_send);

    static void eax_copy_send(
        const EAXSOURCEALLSENDPROPERTIES& src_send,
        EAXSOURCEALLSENDPROPERTIES& dst_send);

    static void eax_copy_send(
        const EAXSOURCEALLSENDPROPERTIES& src_send,
        EAXSOURCEOCCLUSIONSENDPROPERTIES& dst_send);

    static void eax_copy_send(
        const EAXSOURCEALLSENDPROPERTIES& src_send,
        EAXSOURCEEXCLUSIONSENDPROPERTIES& dst_send);

    template<
        typename TException,
        typename TSrcSend
    >
    void eax_api_get_send_properties(
        const EaxEaxCall& eax_call) const
    {
        const auto eax_version = eax_call.get_version();
        const auto dst_sends = eax_call.get_values<TException, TSrcSend>();
        const auto send_count = dst_sends.size();

        for (auto fx_slot_index = EaxFxSlotIndexValue{}; fx_slot_index < send_count; ++fx_slot_index)
        {
            auto& dst_send = dst_sends[fx_slot_index];
            const auto& src_send = eax_.sends[fx_slot_index];

            eax_copy_send(src_send, dst_send);

            dst_send.guidReceivingFXSlotID = eax_get_send_fx_slot_guid(eax_version, fx_slot_index);
        }
    }


    void eax1_get(const EaxEaxCall& eax_call);

    void eax_api_get_source_all_v2(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_v3(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_v5(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_obstruction(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_occlusion(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_exclusion(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_active_fx_slot_id(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_all_2d(
        const EaxEaxCall& eax_call);

    void eax_api_get_source_speaker_level_all(
        const EaxEaxCall& eax_call);

    void eax_get(
        const EaxEaxCall& eax_call);


    // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
    void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx,
        const EaxAlLowPassParam &filter);
#endif // ALSOFT_EAX
};

void UpdateAllSourceProps(ALCcontext *context);

#endif