Update changelog
[openal-soft.git] / al / source.h
bloba1efd527cce568fd9a082953c1be1a7369527d3c
1 #ifndef AL_SOURCE_H
2 #define AL_SOURCE_H
4 #include <array>
5 #include <atomic>
6 #include <cstddef>
7 #include <iterator>
8 #include <limits>
9 #include <deque>
11 #include "AL/al.h"
12 #include "AL/alc.h"
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"
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
31 struct ALbuffer;
32 struct ALeffectslot;
35 enum class SourceStereo : bool {
36 Normal = AL_NORMAL_SOFT,
37 Enhanced = AL_SUPER_STEREO_SOFT
40 #define DEFAULT_SENDS 2
42 #define INVALID_VOICE_IDX static_cast<ALuint>(-1)
44 struct ALbufferQueueItem : public VoiceBufferItem {
45 ALbuffer *mBuffer{nullptr};
47 DISABLE_ALLOC()
51 #ifdef ALSOFT_EAX
52 class EaxSourceException : public EaxException {
53 public:
54 explicit EaxSourceException(const char* message)
55 : EaxException{"EAX_SOURCE", message}
58 #endif // ALSOFT_EAX
60 struct ALsource {
61 /** Source properties. */
62 float Pitch{1.0f};
63 float Gain{1.0f};
64 float OuterGain{0.0f};
65 float MinGain{0.0f};
66 float MaxGain{1.0f};
67 float InnerAngle{360.0f};
68 float OuterAngle{360.0f};
69 float RefDistance{1.0f};
70 float MaxDistance{std::numeric_limits<float>::max()};
71 float RolloffFactor{1.0f};
72 #ifdef ALSOFT_EAX
73 // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
74 // AL_ROLLOFF_FACTOR
75 float RolloffFactor2{0.0f};
76 #endif
77 std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
78 std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
79 std::array<float,3> Direction{{0.0f, 0.0f, 0.0f}};
80 std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
81 std::array<float,3> OrientUp{{0.0f, 1.0f, 0.0f}};
82 bool HeadRelative{false};
83 bool Looping{false};
84 DistanceModel mDistanceModel{DistanceModel::Default};
85 Resampler mResampler{ResamplerDefault};
86 DirectMode DirectChannels{DirectMode::Off};
87 SpatializeMode mSpatialize{SpatializeMode::Auto};
88 SourceStereo mStereoMode{SourceStereo::Normal};
90 bool DryGainHFAuto{true};
91 bool WetGainAuto{true};
92 bool WetGainHFAuto{true};
93 float OuterGainHF{1.0f};
95 float AirAbsorptionFactor{0.0f};
96 float RoomRolloffFactor{0.0f};
97 float DopplerFactor{1.0f};
99 /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
100 * rather than clockwise.
102 std::array<float,2> StereoPan{{al::numbers::pi_v<float>/6.0f, -al::numbers::pi_v<float>/6.0f}};
104 float Radius{0.0f};
105 float EnhWidth{0.593f};
107 /** Direct filter and auxiliary send info. */
108 struct {
109 float Gain;
110 float GainHF;
111 float HFReference;
112 float GainLF;
113 float LFReference;
114 } Direct;
115 struct SendData {
116 ALeffectslot *Slot;
117 float Gain;
118 float GainHF;
119 float HFReference;
120 float GainLF;
121 float LFReference;
123 std::array<SendData,MAX_SENDS> Send;
126 * Last user-specified offset, and the offset type (bytes, samples, or
127 * seconds).
129 double Offset{0.0};
130 ALenum OffsetType{AL_NONE};
132 /** Source type (static, streaming, or undetermined) */
133 ALenum SourceType{AL_UNDETERMINED};
135 /** Source state (initial, playing, paused, or stopped) */
136 ALenum state{AL_INITIAL};
138 /** Source Buffer Queue head. */
139 al::deque<ALbufferQueueItem> mQueue;
141 bool mPropsDirty{true};
143 /* Index into the context's Voices array. Lazily updated, only checked and
144 * reset when looking up the voice.
146 ALuint VoiceIdx{INVALID_VOICE_IDX};
148 /** Self ID */
149 ALuint id{0};
152 ALsource();
153 ~ALsource();
155 ALsource(const ALsource&) = delete;
156 ALsource& operator=(const ALsource&) = delete;
158 DISABLE_ALLOC()
160 #ifdef ALSOFT_EAX
161 public:
162 void eax_initialize(ALCcontext *context) noexcept;
163 void eax_dispatch(const EaxCall& call);
164 void eax_commit() { eax_commit(EaxCommitType::normal); }
165 void eax_commit_and_update();
166 bool eax_is_initialized() const noexcept { return eax_al_context_ != nullptr; }
168 static ALsource* eax_lookup_source(ALCcontext& al_context, ALuint source_id) noexcept;
170 private:
171 using Exception = EaxSourceException;
173 enum class EaxCommitType {
174 normal,
175 forced,
178 static constexpr auto eax_max_speakers = 9;
180 using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS];
182 static constexpr const EaxFxSlotIds eax4_fx_slot_ids = {
183 &EAXPROPERTYID_EAX40_FXSlot0,
184 &EAXPROPERTYID_EAX40_FXSlot1,
185 &EAXPROPERTYID_EAX40_FXSlot2,
186 &EAXPROPERTYID_EAX40_FXSlot3,
189 static constexpr const EaxFxSlotIds eax5_fx_slot_ids = {
190 &EAXPROPERTYID_EAX50_FXSlot0,
191 &EAXPROPERTYID_EAX50_FXSlot1,
192 &EAXPROPERTYID_EAX50_FXSlot2,
193 &EAXPROPERTYID_EAX50_FXSlot3,
196 using EaxActiveFxSlots = std::array<bool, EAX_MAX_FXSLOTS>;
197 using EaxSpeakerLevels = std::array<EAXSPEAKERLEVELPROPERTIES, eax_max_speakers>;
198 using EaxSends = std::array<EAXSOURCEALLSENDPROPERTIES, EAX_MAX_FXSLOTS>;
200 using Eax1Props = EAXBUFFER_REVERBPROPERTIES;
202 struct Eax1State {
203 Eax1Props i; // Immediate.
204 Eax1Props d; // Deferred.
207 using Eax2Props = EAX20BUFFERPROPERTIES;
209 struct Eax2State {
210 Eax2Props i; // Immediate.
211 Eax2Props d; // Deferred.
214 using Eax3Props = EAX30SOURCEPROPERTIES;
216 struct Eax3State {
217 Eax3Props i; // Immediate.
218 Eax3Props d; // Deferred.
221 struct Eax4Props {
222 Eax3Props source;
223 EaxSends sends;
224 EAX40ACTIVEFXSLOTS active_fx_slots;
226 bool operator==(const Eax4Props& rhs) noexcept
228 return std::memcmp(this, &rhs, sizeof(Eax4Props)) == 0;
232 struct Eax4State {
233 Eax4Props i; // Immediate.
234 Eax4Props d; // Deferred.
237 struct Eax5Props {
238 EAX50SOURCEPROPERTIES source;
239 EaxSends sends;
240 EAX50ACTIVEFXSLOTS active_fx_slots;
241 EaxSpeakerLevels speaker_levels;
243 bool operator==(const Eax5Props& rhs) noexcept
245 return std::memcmp(this, &rhs, sizeof(Eax5Props)) == 0;
249 struct Eax5State {
250 Eax5Props i; // Immediate.
251 Eax5Props d; // Deferred.
254 ALCcontext* eax_al_context_{};
255 EaxFxSlotIndex eax_primary_fx_slot_id_{};
256 EaxActiveFxSlots eax_active_fx_slots_{};
257 int eax_version_{};
258 bool eax_changed_{};
259 Eax1State eax1_{};
260 Eax2State eax2_{};
261 Eax3State eax3_{};
262 Eax4State eax4_{};
263 Eax5State eax5_{};
264 Eax5Props eax_{};
266 // ----------------------------------------------------------------------
267 // Source validators
269 struct Eax1SourceReverbMixValidator {
270 void operator()(float reverb_mix) const
272 if (reverb_mix == EAX_REVERBMIX_USEDISTANCE)
273 return;
275 eax_validate_range<Exception>(
276 "Reverb Mix",
277 reverb_mix,
278 EAX_BUFFER_MINREVERBMIX,
279 EAX_BUFFER_MAXREVERBMIX);
283 struct Eax2SourceDirectValidator {
284 void operator()(long lDirect) const
286 eax_validate_range<Exception>(
287 "Direct",
288 lDirect,
289 EAXSOURCE_MINDIRECT,
290 EAXSOURCE_MAXDIRECT);
294 struct Eax2SourceDirectHfValidator {
295 void operator()(long lDirectHF) const
297 eax_validate_range<Exception>(
298 "Direct HF",
299 lDirectHF,
300 EAXSOURCE_MINDIRECTHF,
301 EAXSOURCE_MAXDIRECTHF);
305 struct Eax2SourceRoomValidator {
306 void operator()(long lRoom) const
308 eax_validate_range<Exception>(
309 "Room",
310 lRoom,
311 EAXSOURCE_MINROOM,
312 EAXSOURCE_MAXROOM);
316 struct Eax2SourceRoomHfValidator {
317 void operator()(long lRoomHF) const
319 eax_validate_range<Exception>(
320 "Room HF",
321 lRoomHF,
322 EAXSOURCE_MINROOMHF,
323 EAXSOURCE_MAXROOMHF);
327 struct Eax2SourceRoomRolloffFactorValidator {
328 void operator()(float flRoomRolloffFactor) const
330 eax_validate_range<Exception>(
331 "Room Rolloff Factor",
332 flRoomRolloffFactor,
333 EAXSOURCE_MINROOMROLLOFFFACTOR,
334 EAXSOURCE_MAXROOMROLLOFFFACTOR);
338 struct Eax2SourceObstructionValidator {
339 void operator()(long lObstruction) const
341 eax_validate_range<Exception>(
342 "Obstruction",
343 lObstruction,
344 EAXSOURCE_MINOBSTRUCTION,
345 EAXSOURCE_MAXOBSTRUCTION);
349 struct Eax2SourceObstructionLfRatioValidator {
350 void operator()(float flObstructionLFRatio) const
352 eax_validate_range<Exception>(
353 "Obstruction LF Ratio",
354 flObstructionLFRatio,
355 EAXSOURCE_MINOBSTRUCTIONLFRATIO,
356 EAXSOURCE_MAXOBSTRUCTIONLFRATIO);
360 struct Eax2SourceOcclusionValidator {
361 void operator()(long lOcclusion) const
363 eax_validate_range<Exception>(
364 "Occlusion",
365 lOcclusion,
366 EAXSOURCE_MINOCCLUSION,
367 EAXSOURCE_MAXOCCLUSION);
371 struct Eax2SourceOcclusionLfRatioValidator {
372 void operator()(float flOcclusionLFRatio) const
374 eax_validate_range<Exception>(
375 "Occlusion LF Ratio",
376 flOcclusionLFRatio,
377 EAXSOURCE_MINOCCLUSIONLFRATIO,
378 EAXSOURCE_MAXOCCLUSIONLFRATIO);
382 struct Eax2SourceOcclusionRoomRatioValidator {
383 void operator()(float flOcclusionRoomRatio) const
385 eax_validate_range<Exception>(
386 "Occlusion Room Ratio",
387 flOcclusionRoomRatio,
388 EAXSOURCE_MINOCCLUSIONROOMRATIO,
389 EAXSOURCE_MAXOCCLUSIONROOMRATIO);
393 struct Eax2SourceOutsideVolumeHfValidator {
394 void operator()(long lOutsideVolumeHF) const
396 eax_validate_range<Exception>(
397 "Outside Volume HF",
398 lOutsideVolumeHF,
399 EAXSOURCE_MINOUTSIDEVOLUMEHF,
400 EAXSOURCE_MAXOUTSIDEVOLUMEHF);
404 struct Eax2SourceAirAbsorptionFactorValidator {
405 void operator()(float flAirAbsorptionFactor) const
407 eax_validate_range<Exception>(
408 "Air Absorption Factor",
409 flAirAbsorptionFactor,
410 EAXSOURCE_MINAIRABSORPTIONFACTOR,
411 EAXSOURCE_MAXAIRABSORPTIONFACTOR);
415 struct Eax2SourceFlagsValidator {
416 void operator()(unsigned long dwFlags) const
418 eax_validate_range<Exception>(
419 "Flags",
420 dwFlags,
421 0UL,
422 ~EAX20SOURCEFLAGS_RESERVED);
426 struct Eax3SourceOcclusionDirectRatioValidator {
427 void operator()(float flOcclusionDirectRatio) const
429 eax_validate_range<Exception>(
430 "Occlusion Direct Ratio",
431 flOcclusionDirectRatio,
432 EAXSOURCE_MINOCCLUSIONDIRECTRATIO,
433 EAXSOURCE_MAXOCCLUSIONDIRECTRATIO);
437 struct Eax3SourceExclusionValidator {
438 void operator()(long lExclusion) const
440 eax_validate_range<Exception>(
441 "Exclusion",
442 lExclusion,
443 EAXSOURCE_MINEXCLUSION,
444 EAXSOURCE_MAXEXCLUSION);
448 struct Eax3SourceExclusionLfRatioValidator {
449 void operator()(float flExclusionLFRatio) const
451 eax_validate_range<Exception>(
452 "Exclusion LF Ratio",
453 flExclusionLFRatio,
454 EAXSOURCE_MINEXCLUSIONLFRATIO,
455 EAXSOURCE_MAXEXCLUSIONLFRATIO);
459 struct Eax3SourceDopplerFactorValidator {
460 void operator()(float flDopplerFactor) const
462 eax_validate_range<Exception>(
463 "Doppler Factor",
464 flDopplerFactor,
465 EAXSOURCE_MINDOPPLERFACTOR,
466 EAXSOURCE_MAXDOPPLERFACTOR);
470 struct Eax3SourceRolloffFactorValidator {
471 void operator()(float flRolloffFactor) const
473 eax_validate_range<Exception>(
474 "Rolloff Factor",
475 flRolloffFactor,
476 EAXSOURCE_MINROLLOFFFACTOR,
477 EAXSOURCE_MAXROLLOFFFACTOR);
481 struct Eax5SourceMacroFXFactorValidator {
482 void operator()(float flMacroFXFactor) const
484 eax_validate_range<Exception>(
485 "Macro FX Factor",
486 flMacroFXFactor,
487 EAXSOURCE_MINMACROFXFACTOR,
488 EAXSOURCE_MAXMACROFXFACTOR);
492 struct Eax5SourceFlagsValidator {
493 void operator()(unsigned long dwFlags) const
495 eax_validate_range<Exception>(
496 "Flags",
497 dwFlags,
498 0UL,
499 ~EAX50SOURCEFLAGS_RESERVED);
503 struct Eax1SourceAllValidator {
504 void operator()(const Eax1Props& props) const
506 Eax1SourceReverbMixValidator{}(props.fMix);
510 struct Eax2SourceAllValidator {
511 void operator()(const Eax2Props& props) const
513 Eax2SourceDirectValidator{}(props.lDirect);
514 Eax2SourceDirectHfValidator{}(props.lDirectHF);
515 Eax2SourceRoomValidator{}(props.lRoom);
516 Eax2SourceRoomHfValidator{}(props.lRoomHF);
517 Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
518 Eax2SourceObstructionValidator{}(props.lObstruction);
519 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
520 Eax2SourceOcclusionValidator{}(props.lOcclusion);
521 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
522 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
523 Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
524 Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
525 Eax2SourceFlagsValidator{}(props.dwFlags);
529 struct Eax3SourceAllValidator {
530 void operator()(const Eax3Props& props) const
532 Eax2SourceDirectValidator{}(props.lDirect);
533 Eax2SourceDirectHfValidator{}(props.lDirectHF);
534 Eax2SourceRoomValidator{}(props.lRoom);
535 Eax2SourceRoomHfValidator{}(props.lRoomHF);
536 Eax2SourceObstructionValidator{}(props.lObstruction);
537 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
538 Eax2SourceOcclusionValidator{}(props.lOcclusion);
539 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
540 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
541 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
542 Eax3SourceExclusionValidator{}(props.lExclusion);
543 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
544 Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
545 Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
546 Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
547 Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
548 Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
549 Eax2SourceFlagsValidator{}(props.ulFlags);
553 struct Eax5SourceAllValidator {
554 void operator()(const EAX50SOURCEPROPERTIES& props) const
556 Eax3SourceAllValidator{}(static_cast<const Eax3Props&>(props));
557 Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor);
561 struct Eax5SourceAll2dValidator {
562 void operator()(const EAXSOURCE2DPROPERTIES& props) const
564 Eax2SourceDirectValidator{}(props.lDirect);
565 Eax2SourceDirectHfValidator{}(props.lDirectHF);
566 Eax2SourceRoomValidator{}(props.lRoom);
567 Eax2SourceRoomHfValidator{}(props.lRoomHF);
568 Eax5SourceFlagsValidator{}(props.ulFlags);
572 struct Eax4ObstructionValidator {
573 void operator()(const EAXOBSTRUCTIONPROPERTIES& props) const
575 Eax2SourceObstructionValidator{}(props.lObstruction);
576 Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
580 struct Eax4OcclusionValidator {
581 void operator()(const EAXOCCLUSIONPROPERTIES& props) const
583 Eax2SourceOcclusionValidator{}(props.lOcclusion);
584 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
585 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
586 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
590 struct Eax4ExclusionValidator {
591 void operator()(const EAXEXCLUSIONPROPERTIES& props) const
593 Eax3SourceExclusionValidator{}(props.lExclusion);
594 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
598 // Source validators
599 // ----------------------------------------------------------------------
600 // Send validators
602 struct Eax4SendReceivingFxSlotIdValidator {
603 void operator()(const GUID& guidReceivingFXSlotID) const
605 if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 &&
606 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 &&
607 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 &&
608 guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3)
610 eax_fail_unknown_receiving_fx_slot_id();
615 struct Eax5SendReceivingFxSlotIdValidator {
616 void operator()(const GUID& guidReceivingFXSlotID) const
618 if (guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 &&
619 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 &&
620 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 &&
621 guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3)
623 eax_fail_unknown_receiving_fx_slot_id();
628 struct Eax4SendSendValidator {
629 void operator()(long lSend) const
631 eax_validate_range<Exception>(
632 "Send",
633 lSend,
634 EAXSOURCE_MINSEND,
635 EAXSOURCE_MAXSEND);
639 struct Eax4SendSendHfValidator {
640 void operator()(long lSendHF) const
642 eax_validate_range<Exception>(
643 "Send HF",
644 lSendHF,
645 EAXSOURCE_MINSENDHF,
646 EAXSOURCE_MAXSENDHF);
650 template<typename TIdValidator>
651 struct EaxSendValidator {
652 void operator()(const EAXSOURCESENDPROPERTIES& props) const
654 TIdValidator{}(props.guidReceivingFXSlotID);
655 Eax4SendSendValidator{}(props.lSend);
656 Eax4SendSendHfValidator{}(props.lSendHF);
660 struct Eax4SendValidator : EaxSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
661 struct Eax5SendValidator : EaxSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
663 template<typename TIdValidator>
664 struct EaxOcclusionSendValidator {
665 void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES& props) const
667 TIdValidator{}(props.guidReceivingFXSlotID);
668 Eax2SourceOcclusionValidator{}(props.lOcclusion);
669 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
670 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
671 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
675 struct Eax4OcclusionSendValidator : EaxOcclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
676 struct Eax5OcclusionSendValidator : EaxOcclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
678 template<typename TIdValidator>
679 struct EaxExclusionSendValidator {
680 void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES& props) const
682 TIdValidator{}(props.guidReceivingFXSlotID);
683 Eax3SourceExclusionValidator{}(props.lExclusion);
684 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
688 struct Eax4ExclusionSendValidator : EaxExclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
689 struct Eax5ExclusionSendValidator : EaxExclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
691 template<typename TIdValidator>
692 struct EaxAllSendValidator {
693 void operator()(const EAXSOURCEALLSENDPROPERTIES& props) const
695 TIdValidator{}(props.guidReceivingFXSlotID);
696 Eax4SendSendValidator{}(props.lSend);
697 Eax4SendSendHfValidator{}(props.lSendHF);
698 Eax2SourceOcclusionValidator{}(props.lOcclusion);
699 Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
700 Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
701 Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
702 Eax3SourceExclusionValidator{}(props.lExclusion);
703 Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
707 struct Eax4AllSendValidator : EaxAllSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
708 struct Eax5AllSendValidator : EaxAllSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
710 // Send validators
711 // ----------------------------------------------------------------------
712 // Active FX slot ID validators
714 struct Eax4ActiveFxSlotIdValidator {
715 void operator()(const GUID &guid) const
717 if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
718 && guid != EAXPROPERTYID_EAX40_FXSlot0 && guid != EAXPROPERTYID_EAX40_FXSlot1
719 && guid != EAXPROPERTYID_EAX40_FXSlot2 && guid != EAXPROPERTYID_EAX40_FXSlot3)
721 eax_fail_unknown_active_fx_slot_id();
726 struct Eax5ActiveFxSlotIdValidator {
727 void operator()(const GUID &guid) const
729 if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
730 && guid != EAXPROPERTYID_EAX50_FXSlot0 && guid != EAXPROPERTYID_EAX50_FXSlot1
731 && guid != EAXPROPERTYID_EAX50_FXSlot2 && guid != EAXPROPERTYID_EAX50_FXSlot3)
733 eax_fail_unknown_active_fx_slot_id();
738 // Active FX slot ID validators
739 // ----------------------------------------------------------------------
740 // Speaker level validators.
742 struct Eax5SpeakerIdValidator {
743 void operator()(long lSpeakerID) const
745 switch (lSpeakerID) {
746 case EAXSPEAKER_FRONT_LEFT:
747 case EAXSPEAKER_FRONT_CENTER:
748 case EAXSPEAKER_FRONT_RIGHT:
749 case EAXSPEAKER_SIDE_RIGHT:
750 case EAXSPEAKER_REAR_RIGHT:
751 case EAXSPEAKER_REAR_CENTER:
752 case EAXSPEAKER_REAR_LEFT:
753 case EAXSPEAKER_SIDE_LEFT:
754 case EAXSPEAKER_LOW_FREQUENCY:
755 break;
757 default:
758 eax_fail("Unknown speaker ID.");
763 struct Eax5SpeakerLevelValidator {
764 void operator()(long lLevel) const
766 // TODO Use a range when the feature will be implemented.
767 if (lLevel != EAXSOURCE_DEFAULTSPEAKERLEVEL)
768 eax_fail("Speaker level out of range.");
772 struct Eax5SpeakerAllValidator {
773 void operator()(const EAXSPEAKERLEVELPROPERTIES& all) const
775 Eax5SpeakerIdValidator{}(all.lSpeakerID);
776 Eax5SpeakerLevelValidator{}(all.lLevel);
780 // Speaker level validators.
781 // ----------------------------------------------------------------------
783 struct Eax4SendIndexGetter {
784 EaxFxSlotIndexValue operator()(const GUID &guid) const
786 if(guid == EAXPROPERTYID_EAX40_FXSlot0)
787 return 0;
788 if(guid == EAXPROPERTYID_EAX40_FXSlot1)
789 return 1;
790 if(guid == EAXPROPERTYID_EAX40_FXSlot2)
791 return 2;
792 if(guid == EAXPROPERTYID_EAX40_FXSlot3)
793 return 3;
794 eax_fail_unknown_receiving_fx_slot_id();
798 struct Eax5SendIndexGetter {
799 EaxFxSlotIndexValue operator()(const GUID &guid) const
801 if(guid == EAXPROPERTYID_EAX50_FXSlot0)
802 return 0;
803 if(guid == EAXPROPERTYID_EAX50_FXSlot1)
804 return 1;
805 if(guid == EAXPROPERTYID_EAX50_FXSlot2)
806 return 2;
807 if(guid == EAXPROPERTYID_EAX50_FXSlot3)
808 return 3;
809 eax_fail_unknown_receiving_fx_slot_id();
813 [[noreturn]] static void eax_fail(const char* message);
814 [[noreturn]] static void eax_fail_unknown_property_id();
815 [[noreturn]] static void eax_fail_unknown_version();
816 [[noreturn]] static void eax_fail_unknown_active_fx_slot_id();
817 [[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id();
819 void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
820 void eax1_set_defaults(Eax1Props& props) noexcept;
821 void eax1_set_defaults() noexcept;
822 void eax2_set_defaults(Eax2Props& props) noexcept;
823 void eax2_set_defaults() noexcept;
824 void eax3_set_defaults(Eax3Props& props) noexcept;
825 void eax3_set_defaults() noexcept;
826 void eax4_set_sends_defaults(EaxSends& sends) noexcept;
827 void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
828 void eax4_set_defaults() noexcept;
829 void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
830 void eax5_set_sends_defaults(EaxSends& sends) noexcept;
831 void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
832 void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
833 void eax5_set_defaults(Eax5Props& props) noexcept;
834 void eax5_set_defaults() noexcept;
835 void eax_set_defaults() noexcept;
837 void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
838 void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
839 void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
840 void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
842 static float eax_calculate_dst_occlusion_mb(
843 long src_occlusion_mb,
844 float path_ratio,
845 float lf_ratio) noexcept;
847 EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;
849 EaxAlLowPassParam eax_create_room_filter_param(
850 const ALeffectslot& fx_slot,
851 const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;
853 void eax_update_direct_filter();
854 void eax_update_room_filters();
855 void eax_commit_filters();
857 static void eax_copy_send_for_get(
858 const EAXSOURCEALLSENDPROPERTIES& src,
859 EAXSOURCESENDPROPERTIES& dst) noexcept
861 dst = reinterpret_cast<const EAXSOURCESENDPROPERTIES&>(src);
864 static void eax_copy_send_for_get(
865 const EAXSOURCEALLSENDPROPERTIES& src,
866 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
868 dst = src;
871 static void eax_copy_send_for_get(
872 const EAXSOURCEALLSENDPROPERTIES& src,
873 EAXSOURCEOCCLUSIONSENDPROPERTIES& dst) noexcept
875 dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
876 dst.lOcclusion = src.lOcclusion;
877 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
878 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
879 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
882 static void eax_copy_send_for_get(
883 const EAXSOURCEALLSENDPROPERTIES& src,
884 EAXSOURCEEXCLUSIONSENDPROPERTIES& dst) noexcept
886 dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
887 dst.lExclusion = src.lExclusion;
888 dst.flExclusionLFRatio = src.flExclusionLFRatio;
891 template<typename TDstSend>
892 void eax_get_sends(const EaxCall& call, const EaxSends& src_sends)
894 const auto dst_sends = call.get_values<TDstSend>(EAX_MAX_FXSLOTS);
895 const auto count = dst_sends.size();
897 for (auto i = decltype(count){}; i < count; ++i) {
898 const auto& src_send = src_sends[i];
899 auto& dst_send = dst_sends[i];
900 eax_copy_send_for_get(src_send, dst_send);
904 void eax1_get(const EaxCall& call, const Eax1Props& props);
905 void eax2_get(const EaxCall& call, const Eax2Props& props);
906 void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
907 void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
908 void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
909 void eax3_get(const EaxCall& call, const Eax3Props& props);
910 void eax4_get(const EaxCall& call, const Eax4Props& props);
911 void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
912 void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
913 void eax5_get(const EaxCall& call, const Eax5Props& props);
914 void eax_get(const EaxCall& call);
916 static void eax_copy_send_for_set(
917 const EAXSOURCESENDPROPERTIES& src,
918 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
920 dst.lSend = src.lSend;
921 dst.lSendHF = src.lSendHF;
924 static void eax_copy_send_for_set(
925 const EAXSOURCEALLSENDPROPERTIES& src,
926 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
928 dst.lSend = src.lSend;
929 dst.lSendHF = src.lSendHF;
930 dst.lOcclusion = src.lOcclusion;
931 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
932 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
933 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
934 dst.lExclusion = src.lExclusion;
935 dst.flExclusionLFRatio = src.flExclusionLFRatio;
938 static void eax_copy_send_for_set(
939 const EAXSOURCEOCCLUSIONSENDPROPERTIES& src,
940 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
942 dst.lOcclusion = src.lOcclusion;
943 dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
944 dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
945 dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
948 static void eax_copy_send_for_set(
949 const EAXSOURCEEXCLUSIONSENDPROPERTIES& src,
950 EAXSOURCEALLSENDPROPERTIES& dst) noexcept
952 dst.lExclusion = src.lExclusion;
953 dst.flExclusionLFRatio = src.flExclusionLFRatio;
956 template<typename TValidator, typename TIndexGetter, typename TSrcSend>
957 void eax_defer_sends(const EaxCall& call, EaxSends& dst_sends)
959 const auto src_sends = call.get_values<const TSrcSend>(EAX_MAX_FXSLOTS);
960 std::for_each(src_sends.cbegin(), src_sends.cend(), TValidator{});
961 const auto count = src_sends.size();
962 const auto index_getter = TIndexGetter{};
964 for (auto i = decltype(count){}; i < count; ++i) {
965 const auto& src_send = src_sends[i];
966 const auto dst_index = index_getter(src_send.guidReceivingFXSlotID);
967 auto& dst_send = dst_sends[dst_index];
968 eax_copy_send_for_set(src_send, dst_send);
972 template<typename TValidator, typename TSrcSend>
973 void eax4_defer_sends(const EaxCall& call, EaxSends& dst_sends)
975 eax_defer_sends<TValidator, Eax4SendIndexGetter, TSrcSend>(call, dst_sends);
978 template<typename TValidator, typename TSrcSend>
979 void eax5_defer_sends(const EaxCall& call, EaxSends& dst_sends)
981 eax_defer_sends<TValidator, Eax5SendIndexGetter, TSrcSend>(call, dst_sends);
984 template<typename TValidator, size_t TIdCount>
985 void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
987 const auto src_ids = call.get_values<const GUID>(TIdCount);
988 std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
989 std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids);
992 template<size_t TIdCount>
993 void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
995 eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
998 template<size_t TIdCount>
999 void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
1001 eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
1004 template<typename TValidator, typename TProperty>
1005 static void eax_defer(const EaxCall& call, TProperty& property)
1007 const auto& value = call.get_value<Exception, const TProperty>();
1008 TValidator{}(value);
1009 property = value;
1012 // Defers source's sub-properties (obstruction, occlusion, exclusion).
1013 template<typename TValidator, typename TSubproperty, typename TProperty>
1014 void eax_defer_sub(const EaxCall& call, TProperty& property)
1016 const auto& src_props = call.get_value<Exception, const TSubproperty>();
1017 TValidator{}(src_props);
1018 auto& dst_props = reinterpret_cast<TSubproperty&>(property);
1019 dst_props = src_props;
1022 void eax_set_efx_outer_gain_hf();
1023 void eax_set_efx_doppler_factor();
1024 void eax_set_efx_rolloff_factor();
1025 void eax_set_efx_room_rolloff_factor();
1026 void eax_set_efx_air_absorption_factor();
1027 void eax_set_efx_dry_gain_hf_auto();
1028 void eax_set_efx_wet_gain_auto();
1029 void eax_set_efx_wet_gain_hf_auto();
1031 void eax1_set(const EaxCall& call, Eax1Props& props);
1032 void eax2_set(const EaxCall& call, Eax2Props& props);
1033 void eax3_set(const EaxCall& call, Eax3Props& props);
1034 void eax4_set(const EaxCall& call, Eax4Props& props);
1035 void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
1036 void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
1037 void eax5_set(const EaxCall& call, Eax5Props& props);
1038 void eax_set(const EaxCall& call);
1040 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
1041 void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx,
1042 const EaxAlLowPassParam &filter);
1044 void eax_commit_active_fx_slots();
1045 void eax_commit(EaxCommitType commit_type);
1046 #endif // ALSOFT_EAX
1049 void UpdateAllSourceProps(ALCcontext *context);
1051 #endif