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