17 #include "alnumbers.h"
18 #include "alnumeric.h"
20 #include "core/context.h"
21 #include "core/voice.h"
26 #include "eax/exception.h"
27 #include "eax/fx_slot_index.h"
28 #include "eax/utils.h"
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};
52 class EaxSourceException
: public EaxException
{
54 explicit EaxSourceException(const char* message
)
55 : EaxException
{"EAX_SOURCE", message
}
61 /** Source properties. */
64 float OuterGain
{0.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
};
73 // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
75 float RolloffFactor2
{0.0f
};
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};
84 DistanceModel mDistanceModel
{DistanceModel::Default
};
85 Resampler mResampler
{ResamplerDefault
};
86 DirectMode DirectChannels
{DirectMode::Off
};
87 SpatializeMode mSpatialize
{SpatializeMode::Auto
};
88 SourceStereo mStereoMode
{SourceStereo::Normal
};
89 bool mPanningEnabled
{false};
91 bool DryGainHFAuto
{true};
92 bool WetGainAuto
{true};
93 bool WetGainHFAuto
{true};
94 float OuterGainHF
{1.0f
};
96 float AirAbsorptionFactor
{0.0f
};
97 float RoomRolloffFactor
{0.0f
};
98 float DopplerFactor
{1.0f
};
100 /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
101 * rather than clockwise.
103 std::array
<float,2> StereoPan
{{al::numbers::pi_v
<float>/6.0f
, -al::numbers::pi_v
<float>/6.0f
}};
106 float EnhWidth
{0.593f
};
109 /** Direct filter and auxiliary send info. */
120 ALeffectslot
*Slot
{};
127 std::array
<SendData
,MaxSendCount
> Send
;
130 * Last user-specified offset, and the offset type (bytes, samples, or
134 ALenum OffsetType
{AL_NONE
};
136 /** Source type (static, streaming, or undetermined) */
137 ALenum SourceType
{AL_UNDETERMINED
};
139 /** Source state (initial, playing, paused, or stopped) */
140 ALenum state
{AL_INITIAL
};
142 /** Source Buffer Queue head. */
143 std::deque
<ALbufferQueueItem
> mQueue
;
145 bool mPropsDirty
{true};
147 /* Index into the context's Voices array. Lazily updated, only checked and
148 * reset when looking up the voice.
150 ALuint VoiceIdx
{InvalidVoiceIndex
};
159 ALsource(const ALsource
&) = delete;
160 ALsource
& operator=(const ALsource
&) = delete;
162 static void SetName(ALCcontext
*context
, ALuint id
, std::string_view name
);
168 void eaxInitialize(ALCcontext
*context
) noexcept
;
169 void eaxDispatch(const EaxCall
& call
);
171 void eaxMarkAsChanged() noexcept
{ mEaxChanged
= true; }
173 static ALsource
* EaxLookupSource(ALCcontext
& al_context
, ALuint source_id
) noexcept
;
176 using Exception
= EaxSourceException
;
178 static constexpr auto eax_max_speakers
{9u};
180 using EaxFxSlotIds
= std::array
<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 Eax1Props i
; // Immediate.
203 Eax1Props d
; // Deferred.
206 using Eax2Props
= EAX20BUFFERPROPERTIES
;
208 Eax2Props i
; // Immediate.
209 Eax2Props d
; // Deferred.
212 using Eax3Props
= EAX30SOURCEPROPERTIES
;
214 Eax3Props i
; // Immediate.
215 Eax3Props d
; // Deferred.
221 EAX40ACTIVEFXSLOTS active_fx_slots
;
225 Eax4Props i
; // Immediate.
226 Eax4Props d
; // Deferred.
230 EAX50SOURCEPROPERTIES source
;
232 EAX50ACTIVEFXSLOTS active_fx_slots
;
233 EaxSpeakerLevels speaker_levels
;
237 Eax5Props i
; // Immediate.
238 Eax5Props d
; // Deferred.
241 ALCcontext
* mEaxAlContext
{};
242 EaxFxSlotIndex mEaxPrimaryFxSlotId
{};
243 EaxActiveFxSlots mEaxActiveFxSlots
{};
253 // ----------------------------------------------------------------------
256 struct Eax1SourceReverbMixValidator
{
257 void operator()(float reverb_mix
) const
259 if (reverb_mix
== EAX_REVERBMIX_USEDISTANCE
)
262 eax_validate_range
<Exception
>(
265 EAX_BUFFER_MINREVERBMIX
,
266 EAX_BUFFER_MAXREVERBMIX
);
270 struct Eax2SourceDirectValidator
{
271 void operator()(long lDirect
) const
273 eax_validate_range
<Exception
>(
277 EAXSOURCE_MAXDIRECT
);
281 struct Eax2SourceDirectHfValidator
{
282 void operator()(long lDirectHF
) const
284 eax_validate_range
<Exception
>(
287 EAXSOURCE_MINDIRECTHF
,
288 EAXSOURCE_MAXDIRECTHF
);
292 struct Eax2SourceRoomValidator
{
293 void operator()(long lRoom
) const
295 eax_validate_range
<Exception
>(
303 struct Eax2SourceRoomHfValidator
{
304 void operator()(long lRoomHF
) const
306 eax_validate_range
<Exception
>(
310 EAXSOURCE_MAXROOMHF
);
314 struct Eax2SourceRoomRolloffFactorValidator
{
315 void operator()(float flRoomRolloffFactor
) const
317 eax_validate_range
<Exception
>(
318 "Room Rolloff Factor",
320 EAXSOURCE_MINROOMROLLOFFFACTOR
,
321 EAXSOURCE_MAXROOMROLLOFFFACTOR
);
325 struct Eax2SourceObstructionValidator
{
326 void operator()(long lObstruction
) const
328 eax_validate_range
<Exception
>(
331 EAXSOURCE_MINOBSTRUCTION
,
332 EAXSOURCE_MAXOBSTRUCTION
);
336 struct Eax2SourceObstructionLfRatioValidator
{
337 void operator()(float flObstructionLFRatio
) const
339 eax_validate_range
<Exception
>(
340 "Obstruction LF Ratio",
341 flObstructionLFRatio
,
342 EAXSOURCE_MINOBSTRUCTIONLFRATIO
,
343 EAXSOURCE_MAXOBSTRUCTIONLFRATIO
);
347 struct Eax2SourceOcclusionValidator
{
348 void operator()(long lOcclusion
) const
350 eax_validate_range
<Exception
>(
353 EAXSOURCE_MINOCCLUSION
,
354 EAXSOURCE_MAXOCCLUSION
);
358 struct Eax2SourceOcclusionLfRatioValidator
{
359 void operator()(float flOcclusionLFRatio
) const
361 eax_validate_range
<Exception
>(
362 "Occlusion LF Ratio",
364 EAXSOURCE_MINOCCLUSIONLFRATIO
,
365 EAXSOURCE_MAXOCCLUSIONLFRATIO
);
369 struct Eax2SourceOcclusionRoomRatioValidator
{
370 void operator()(float flOcclusionRoomRatio
) const
372 eax_validate_range
<Exception
>(
373 "Occlusion Room Ratio",
374 flOcclusionRoomRatio
,
375 EAXSOURCE_MINOCCLUSIONROOMRATIO
,
376 EAXSOURCE_MAXOCCLUSIONROOMRATIO
);
380 struct Eax2SourceOutsideVolumeHfValidator
{
381 void operator()(long lOutsideVolumeHF
) const
383 eax_validate_range
<Exception
>(
386 EAXSOURCE_MINOUTSIDEVOLUMEHF
,
387 EAXSOURCE_MAXOUTSIDEVOLUMEHF
);
391 struct Eax2SourceAirAbsorptionFactorValidator
{
392 void operator()(float flAirAbsorptionFactor
) const
394 eax_validate_range
<Exception
>(
395 "Air Absorption Factor",
396 flAirAbsorptionFactor
,
397 EAXSOURCE_MINAIRABSORPTIONFACTOR
,
398 EAXSOURCE_MAXAIRABSORPTIONFACTOR
);
402 struct Eax2SourceFlagsValidator
{
403 void operator()(unsigned long dwFlags
) const
405 eax_validate_range
<Exception
>(
409 ~EAX20SOURCEFLAGS_RESERVED
);
413 struct Eax3SourceOcclusionDirectRatioValidator
{
414 void operator()(float flOcclusionDirectRatio
) const
416 eax_validate_range
<Exception
>(
417 "Occlusion Direct Ratio",
418 flOcclusionDirectRatio
,
419 EAXSOURCE_MINOCCLUSIONDIRECTRATIO
,
420 EAXSOURCE_MAXOCCLUSIONDIRECTRATIO
);
424 struct Eax3SourceExclusionValidator
{
425 void operator()(long lExclusion
) const
427 eax_validate_range
<Exception
>(
430 EAXSOURCE_MINEXCLUSION
,
431 EAXSOURCE_MAXEXCLUSION
);
435 struct Eax3SourceExclusionLfRatioValidator
{
436 void operator()(float flExclusionLFRatio
) const
438 eax_validate_range
<Exception
>(
439 "Exclusion LF Ratio",
441 EAXSOURCE_MINEXCLUSIONLFRATIO
,
442 EAXSOURCE_MAXEXCLUSIONLFRATIO
);
446 struct Eax3SourceDopplerFactorValidator
{
447 void operator()(float flDopplerFactor
) const
449 eax_validate_range
<Exception
>(
452 EAXSOURCE_MINDOPPLERFACTOR
,
453 EAXSOURCE_MAXDOPPLERFACTOR
);
457 struct Eax3SourceRolloffFactorValidator
{
458 void operator()(float flRolloffFactor
) const
460 eax_validate_range
<Exception
>(
463 EAXSOURCE_MINROLLOFFFACTOR
,
464 EAXSOURCE_MAXROLLOFFFACTOR
);
468 struct Eax5SourceMacroFXFactorValidator
{
469 void operator()(float flMacroFXFactor
) const
471 eax_validate_range
<Exception
>(
474 EAXSOURCE_MINMACROFXFACTOR
,
475 EAXSOURCE_MAXMACROFXFACTOR
);
479 struct Eax5SourceFlagsValidator
{
480 void operator()(unsigned long dwFlags
) const
482 eax_validate_range
<Exception
>(
486 ~EAX50SOURCEFLAGS_RESERVED
);
490 struct Eax1SourceAllValidator
{
491 void operator()(const Eax1Props
& props
) const
493 Eax1SourceReverbMixValidator
{}(props
.fMix
);
497 struct Eax2SourceAllValidator
{
498 void operator()(const Eax2Props
& props
) const
500 Eax2SourceDirectValidator
{}(props
.lDirect
);
501 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
502 Eax2SourceRoomValidator
{}(props
.lRoom
);
503 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
504 Eax2SourceRoomRolloffFactorValidator
{}(props
.flRoomRolloffFactor
);
505 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
506 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
507 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
508 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
509 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
510 Eax2SourceOutsideVolumeHfValidator
{}(props
.lOutsideVolumeHF
);
511 Eax2SourceAirAbsorptionFactorValidator
{}(props
.flAirAbsorptionFactor
);
512 Eax2SourceFlagsValidator
{}(props
.dwFlags
);
516 struct Eax3SourceAllValidator
{
517 void operator()(const Eax3Props
& props
) const
519 Eax2SourceDirectValidator
{}(props
.lDirect
);
520 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
521 Eax2SourceRoomValidator
{}(props
.lRoom
);
522 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
523 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
524 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
525 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
526 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
527 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
528 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
529 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
530 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
531 Eax2SourceOutsideVolumeHfValidator
{}(props
.lOutsideVolumeHF
);
532 Eax3SourceDopplerFactorValidator
{}(props
.flDopplerFactor
);
533 Eax3SourceRolloffFactorValidator
{}(props
.flRolloffFactor
);
534 Eax2SourceRoomRolloffFactorValidator
{}(props
.flRoomRolloffFactor
);
535 Eax2SourceAirAbsorptionFactorValidator
{}(props
.flAirAbsorptionFactor
);
536 Eax2SourceFlagsValidator
{}(props
.ulFlags
);
540 struct Eax5SourceAllValidator
{
541 void operator()(const EAX50SOURCEPROPERTIES
& props
) const
543 Eax2SourceDirectValidator
{}(props
.lDirect
);
544 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
545 Eax2SourceRoomValidator
{}(props
.lRoom
);
546 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
547 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
548 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
549 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
550 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
551 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
552 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
553 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
554 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
555 Eax2SourceOutsideVolumeHfValidator
{}(props
.lOutsideVolumeHF
);
556 Eax3SourceDopplerFactorValidator
{}(props
.flDopplerFactor
);
557 Eax3SourceRolloffFactorValidator
{}(props
.flRolloffFactor
);
558 Eax2SourceRoomRolloffFactorValidator
{}(props
.flRoomRolloffFactor
);
559 Eax2SourceAirAbsorptionFactorValidator
{}(props
.flAirAbsorptionFactor
);
560 Eax5SourceFlagsValidator
{}(props
.ulFlags
);
561 Eax5SourceMacroFXFactorValidator
{}(props
.flMacroFXFactor
);
565 struct Eax5SourceAll2dValidator
{
566 void operator()(const EAXSOURCE2DPROPERTIES
& props
) const
568 Eax2SourceDirectValidator
{}(props
.lDirect
);
569 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
570 Eax2SourceRoomValidator
{}(props
.lRoom
);
571 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
572 Eax5SourceFlagsValidator
{}(props
.ulFlags
);
576 struct Eax4ObstructionValidator
{
577 void operator()(const EAXOBSTRUCTIONPROPERTIES
& props
) const
579 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
580 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
584 struct Eax4OcclusionValidator
{
585 void operator()(const EAXOCCLUSIONPROPERTIES
& props
) const
587 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
588 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
589 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
590 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
594 struct Eax4ExclusionValidator
{
595 void operator()(const EAXEXCLUSIONPROPERTIES
& props
) const
597 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
598 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
603 // ----------------------------------------------------------------------
606 struct Eax4SendReceivingFxSlotIdValidator
{
607 void operator()(const GUID
& guidReceivingFXSlotID
) const
609 if (guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot0
&&
610 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot1
&&
611 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot2
&&
612 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot3
)
614 eax_fail_unknown_receiving_fx_slot_id();
619 struct Eax5SendReceivingFxSlotIdValidator
{
620 void operator()(const GUID
& guidReceivingFXSlotID
) const
622 if (guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot0
&&
623 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot1
&&
624 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot2
&&
625 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot3
)
627 eax_fail_unknown_receiving_fx_slot_id();
632 struct Eax4SendSendValidator
{
633 void operator()(long lSend
) const
635 eax_validate_range
<Exception
>(
643 struct Eax4SendSendHfValidator
{
644 void operator()(long lSendHF
) const
646 eax_validate_range
<Exception
>(
650 EAXSOURCE_MAXSENDHF
);
654 template<typename TIdValidator
>
655 struct EaxSendValidator
{
656 void operator()(const EAXSOURCESENDPROPERTIES
& props
) const
658 TIdValidator
{}(props
.guidReceivingFXSlotID
);
659 Eax4SendSendValidator
{}(props
.lSend
);
660 Eax4SendSendHfValidator
{}(props
.lSendHF
);
664 struct Eax4SendValidator
: EaxSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
665 struct Eax5SendValidator
: EaxSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
667 template<typename TIdValidator
>
668 struct EaxOcclusionSendValidator
{
669 void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES
& props
) const
671 TIdValidator
{}(props
.guidReceivingFXSlotID
);
672 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
673 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
674 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
675 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
679 struct Eax4OcclusionSendValidator
: EaxOcclusionSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
680 struct Eax5OcclusionSendValidator
: EaxOcclusionSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
682 template<typename TIdValidator
>
683 struct EaxExclusionSendValidator
{
684 void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES
& props
) const
686 TIdValidator
{}(props
.guidReceivingFXSlotID
);
687 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
688 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
692 struct Eax4ExclusionSendValidator
: EaxExclusionSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
693 struct Eax5ExclusionSendValidator
: EaxExclusionSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
695 template<typename TIdValidator
>
696 struct EaxAllSendValidator
{
697 void operator()(const EAXSOURCEALLSENDPROPERTIES
& props
) const
699 TIdValidator
{}(props
.guidReceivingFXSlotID
);
700 Eax4SendSendValidator
{}(props
.lSend
);
701 Eax4SendSendHfValidator
{}(props
.lSendHF
);
702 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
703 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
704 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
705 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
706 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
707 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
711 struct Eax4AllSendValidator
: EaxAllSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
712 struct Eax5AllSendValidator
: EaxAllSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
715 // ----------------------------------------------------------------------
716 // Active FX slot ID validators
718 struct Eax4ActiveFxSlotIdValidator
{
719 void operator()(const GUID
&guid
) const
721 if(guid
!= EAX_NULL_GUID
&& guid
!= EAX_PrimaryFXSlotID
722 && guid
!= EAXPROPERTYID_EAX40_FXSlot0
&& guid
!= EAXPROPERTYID_EAX40_FXSlot1
723 && guid
!= EAXPROPERTYID_EAX40_FXSlot2
&& guid
!= EAXPROPERTYID_EAX40_FXSlot3
)
725 eax_fail_unknown_active_fx_slot_id();
730 struct Eax5ActiveFxSlotIdValidator
{
731 void operator()(const GUID
&guid
) const
733 if(guid
!= EAX_NULL_GUID
&& guid
!= EAX_PrimaryFXSlotID
734 && guid
!= EAXPROPERTYID_EAX50_FXSlot0
&& guid
!= EAXPROPERTYID_EAX50_FXSlot1
735 && guid
!= EAXPROPERTYID_EAX50_FXSlot2
&& guid
!= EAXPROPERTYID_EAX50_FXSlot3
)
737 eax_fail_unknown_active_fx_slot_id();
742 // Active FX slot ID validators
743 // ----------------------------------------------------------------------
744 // Speaker level validators.
746 struct Eax5SpeakerIdValidator
{
747 void operator()(long lSpeakerID
) const
749 switch (lSpeakerID
) {
750 case EAXSPEAKER_FRONT_LEFT
:
751 case EAXSPEAKER_FRONT_CENTER
:
752 case EAXSPEAKER_FRONT_RIGHT
:
753 case EAXSPEAKER_SIDE_RIGHT
:
754 case EAXSPEAKER_REAR_RIGHT
:
755 case EAXSPEAKER_REAR_CENTER
:
756 case EAXSPEAKER_REAR_LEFT
:
757 case EAXSPEAKER_SIDE_LEFT
:
758 case EAXSPEAKER_LOW_FREQUENCY
:
762 eax_fail("Unknown speaker ID.");
767 struct Eax5SpeakerLevelValidator
{
768 void operator()(long lLevel
) const
770 // TODO Use a range when the feature will be implemented.
771 if (lLevel
!= EAXSOURCE_DEFAULTSPEAKERLEVEL
)
772 eax_fail("Speaker level out of range.");
776 struct Eax5SpeakerAllValidator
{
777 void operator()(const EAXSPEAKERLEVELPROPERTIES
& all
) const
779 Eax5SpeakerIdValidator
{}(all
.lSpeakerID
);
780 Eax5SpeakerLevelValidator
{}(all
.lLevel
);
784 // Speaker level validators.
785 // ----------------------------------------------------------------------
787 struct Eax4SendIndexGetter
{
788 EaxFxSlotIndexValue
operator()(const GUID
&guid
) const
790 if(guid
== EAXPROPERTYID_EAX40_FXSlot0
)
792 if(guid
== EAXPROPERTYID_EAX40_FXSlot1
)
794 if(guid
== EAXPROPERTYID_EAX40_FXSlot2
)
796 if(guid
== EAXPROPERTYID_EAX40_FXSlot3
)
798 eax_fail_unknown_receiving_fx_slot_id();
802 struct Eax5SendIndexGetter
{
803 EaxFxSlotIndexValue
operator()(const GUID
&guid
) const
805 if(guid
== EAXPROPERTYID_EAX50_FXSlot0
)
807 if(guid
== EAXPROPERTYID_EAX50_FXSlot1
)
809 if(guid
== EAXPROPERTYID_EAX50_FXSlot2
)
811 if(guid
== EAXPROPERTYID_EAX50_FXSlot3
)
813 eax_fail_unknown_receiving_fx_slot_id();
817 [[noreturn
]] static void eax_fail(const char* message
);
818 [[noreturn
]] static void eax_fail_unknown_property_id();
819 [[noreturn
]] static void eax_fail_unknown_version();
820 [[noreturn
]] static void eax_fail_unknown_active_fx_slot_id();
821 [[noreturn
]] static void eax_fail_unknown_receiving_fx_slot_id();
823 static void eax_set_sends_defaults(EaxSends
& sends
, const EaxFxSlotIds
& ids
) noexcept
;
824 static void eax1_set_defaults(Eax1Props
& props
) noexcept
;
825 void eax1_set_defaults() noexcept
;
826 static void eax2_set_defaults(Eax2Props
& props
) noexcept
;
827 void eax2_set_defaults() noexcept
;
828 static void eax3_set_defaults(Eax3Props
& props
) noexcept
;
829 void eax3_set_defaults() noexcept
;
830 static void eax4_set_sends_defaults(EaxSends
& sends
) noexcept
;
831 static void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS
& slots
) noexcept
;
832 void eax4_set_defaults() noexcept
;
833 static void eax5_set_source_defaults(EAX50SOURCEPROPERTIES
& props
) noexcept
;
834 static void eax5_set_sends_defaults(EaxSends
& sends
) noexcept
;
835 static void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS
& slots
) noexcept
;
836 static void eax5_set_speaker_levels_defaults(EaxSpeakerLevels
& speaker_levels
) noexcept
;
837 static void eax5_set_defaults(Eax5Props
& props
) noexcept
;
838 void eax5_set_defaults() noexcept
;
839 void eax_set_defaults() noexcept
;
841 static void eax1_translate(const Eax1Props
& src
, Eax5Props
& dst
) noexcept
;
842 static void eax2_translate(const Eax2Props
& src
, Eax5Props
& dst
) noexcept
;
843 static void eax3_translate(const Eax3Props
& src
, Eax5Props
& dst
) noexcept
;
844 static void eax4_translate(const Eax4Props
& src
, Eax5Props
& dst
) noexcept
;
846 static float eax_calculate_dst_occlusion_mb(
847 long src_occlusion_mb
,
849 float lf_ratio
) noexcept
;
851 [[nodiscard
]] auto eax_create_direct_filter_param() const noexcept
-> EaxAlLowPassParam
;
853 [[nodiscard
]] auto eax_create_room_filter_param(const ALeffectslot
& fx_slot
,
854 const EAXSOURCEALLSENDPROPERTIES
& send
) const noexcept
-> EaxAlLowPassParam
;
856 void eax_update_direct_filter();
857 void eax_update_room_filters();
858 void eax_commit_filters();
860 static void eax_copy_send_for_get(
861 const EAXSOURCEALLSENDPROPERTIES
& src
,
862 EAXSOURCESENDPROPERTIES
& dst
) noexcept
864 dst
= reinterpret_cast<const EAXSOURCESENDPROPERTIES
&>(src
);
867 static void eax_copy_send_for_get(
868 const EAXSOURCEALLSENDPROPERTIES
& src
,
869 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
874 static void eax_copy_send_for_get(
875 const EAXSOURCEALLSENDPROPERTIES
& src
,
876 EAXSOURCEOCCLUSIONSENDPROPERTIES
& dst
) noexcept
878 dst
.guidReceivingFXSlotID
= src
.guidReceivingFXSlotID
;
879 dst
.lOcclusion
= src
.lOcclusion
;
880 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
881 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
882 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
885 static void eax_copy_send_for_get(
886 const EAXSOURCEALLSENDPROPERTIES
& src
,
887 EAXSOURCEEXCLUSIONSENDPROPERTIES
& dst
) noexcept
889 dst
.guidReceivingFXSlotID
= src
.guidReceivingFXSlotID
;
890 dst
.lExclusion
= src
.lExclusion
;
891 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
894 template<typename TDstSend
>
895 void eax_get_sends(const EaxCall
& call
, const EaxSends
& src_sends
)
897 const auto dst_sends
= call
.get_values
<TDstSend
>(EAX_MAX_FXSLOTS
);
898 const auto count
= dst_sends
.size();
900 for (auto i
= decltype(count
){}; i
< count
; ++i
) {
901 const auto& src_send
= src_sends
[i
];
902 auto& dst_send
= dst_sends
[i
];
903 eax_copy_send_for_get(src_send
, dst_send
);
907 static void eax_get_active_fx_slot_id(const EaxCall
& call
, const al::span
<const GUID
> src_ids
);
908 static void eax1_get(const EaxCall
& call
, const Eax1Props
& props
);
909 static void eax2_get(const EaxCall
& call
, const Eax2Props
& props
);
910 static void eax3_get_obstruction(const EaxCall
& call
, const Eax3Props
& props
);
911 static void eax3_get_occlusion(const EaxCall
& call
, const Eax3Props
& props
);
912 static void eax3_get_exclusion(const EaxCall
& call
, const Eax3Props
& props
);
913 static void eax3_get(const EaxCall
& call
, const Eax3Props
& props
);
914 void eax4_get(const EaxCall
& call
, const Eax4Props
& props
);
915 static void eax5_get_all_2d(const EaxCall
& call
, const EAX50SOURCEPROPERTIES
& props
);
916 static void eax5_get_speaker_levels(const EaxCall
& call
, const EaxSpeakerLevels
& props
);
917 void eax5_get(const EaxCall
& call
, const Eax5Props
& props
);
918 void eax_get(const EaxCall
& call
);
920 static void eax_copy_send_for_set(
921 const EAXSOURCESENDPROPERTIES
& src
,
922 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
924 dst
.lSend
= src
.lSend
;
925 dst
.lSendHF
= src
.lSendHF
;
928 static void eax_copy_send_for_set(
929 const EAXSOURCEALLSENDPROPERTIES
& src
,
930 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
932 dst
.lSend
= src
.lSend
;
933 dst
.lSendHF
= src
.lSendHF
;
934 dst
.lOcclusion
= src
.lOcclusion
;
935 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
936 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
937 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
938 dst
.lExclusion
= src
.lExclusion
;
939 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
942 static void eax_copy_send_for_set(
943 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& src
,
944 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
946 dst
.lOcclusion
= src
.lOcclusion
;
947 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
948 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
949 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
952 static void eax_copy_send_for_set(
953 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& src
,
954 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
956 dst
.lExclusion
= src
.lExclusion
;
957 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
960 template<typename TValidator
, typename TIndexGetter
, typename TSrcSend
>
961 void eax_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
963 const auto src_sends
= call
.get_values
<const TSrcSend
>(EAX_MAX_FXSLOTS
);
964 std::for_each(src_sends
.cbegin(), src_sends
.cend(), TValidator
{});
965 const auto count
= src_sends
.size();
966 const auto index_getter
= TIndexGetter
{};
968 for (auto i
= decltype(count
){}; i
< count
; ++i
) {
969 const auto& src_send
= src_sends
[i
];
970 const auto dst_index
= index_getter(src_send
.guidReceivingFXSlotID
);
971 auto& dst_send
= dst_sends
[dst_index
];
972 eax_copy_send_for_set(src_send
, dst_send
);
976 template<typename TValidator
, typename TSrcSend
>
977 void eax4_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
979 eax_defer_sends
<TValidator
, Eax4SendIndexGetter
, TSrcSend
>(call
, dst_sends
);
982 template<typename TValidator
, typename TSrcSend
>
983 void eax5_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
985 eax_defer_sends
<TValidator
, Eax5SendIndexGetter
, TSrcSend
>(call
, dst_sends
);
988 template<typename TValidator
, size_t TIdCount
>
989 void eax_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
991 const auto src_ids
= call
.get_values
<const GUID
>(TIdCount
);
992 std::for_each(src_ids
.cbegin(), src_ids
.cend(), TValidator
{});
993 std::uninitialized_copy(src_ids
.cbegin(), src_ids
.cend(), dst_ids
.begin());
996 template<size_t TIdCount
>
997 void eax4_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
999 eax_defer_active_fx_slot_id
<Eax4ActiveFxSlotIdValidator
>(call
, dst_ids
);
1002 template<size_t TIdCount
>
1003 void eax5_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
1005 eax_defer_active_fx_slot_id
<Eax5ActiveFxSlotIdValidator
>(call
, dst_ids
);
1008 template<typename TValidator
, typename TProperty
>
1009 static void eax_defer(const EaxCall
& call
, TProperty
& property
)
1011 const auto& value
= call
.get_value
<Exception
, const TProperty
>();
1012 TValidator
{}(value
);
1016 // Defers source's sub-properties (obstruction, occlusion, exclusion).
1017 template<typename TValidator
, typename TSubproperty
, typename TProperty
>
1018 void eax_defer_sub(const EaxCall
& call
, TProperty
& property
)
1020 const auto& src_props
= call
.get_value
<Exception
, const TSubproperty
>();
1021 TValidator
{}(src_props
);
1022 auto& dst_props
= reinterpret_cast<TSubproperty
&>(property
);
1023 dst_props
= src_props
;
1026 void eax_set_efx_outer_gain_hf();
1027 void eax_set_efx_doppler_factor();
1028 void eax_set_efx_rolloff_factor();
1029 void eax_set_efx_room_rolloff_factor();
1030 void eax_set_efx_air_absorption_factor();
1031 void eax_set_efx_dry_gain_hf_auto();
1032 void eax_set_efx_wet_gain_auto();
1033 void eax_set_efx_wet_gain_hf_auto();
1035 static void eax1_set(const EaxCall
& call
, Eax1Props
& props
);
1036 static void eax2_set(const EaxCall
& call
, Eax2Props
& props
);
1037 void eax3_set(const EaxCall
& call
, Eax3Props
& props
);
1038 void eax4_set(const EaxCall
& call
, Eax4Props
& props
);
1039 static void eax5_defer_all_2d(const EaxCall
& call
, EAX50SOURCEPROPERTIES
& props
);
1040 static void eax5_defer_speaker_levels(const EaxCall
& call
, EaxSpeakerLevels
& props
);
1041 void eax5_set(const EaxCall
& call
, Eax5Props
& props
);
1042 void eax_set(const EaxCall
& call
);
1044 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
1045 void eax_set_al_source_send(ALeffectslot
*slot
, size_t sendidx
,
1046 const EaxAlLowPassParam
&filter
);
1048 void eax_commit_active_fx_slots();
1049 #endif // ALSOFT_EAX
1052 void UpdateAllSourceProps(ALCcontext
*context
);
1054 struct SourceSubList
{
1055 uint64_t FreeMask
{~0_u64
};
1056 gsl::owner
<std::array
<ALsource
,64>*> Sources
{nullptr};
1058 SourceSubList() noexcept
= default;
1059 SourceSubList(const SourceSubList
&) = delete;
1060 SourceSubList(SourceSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Sources
{rhs
.Sources
}
1061 { rhs
.FreeMask
= ~0_u64
; rhs
.Sources
= nullptr; }
1064 SourceSubList
& operator=(const SourceSubList
&) = delete;
1065 SourceSubList
& operator=(SourceSubList
&& rhs
) noexcept
1066 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Sources
, rhs
.Sources
); return *this; }