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};
54 class EaxSourceException
: public EaxException
{
56 explicit EaxSourceException(const char* message
)
57 : EaxException
{"EAX_SOURCE", message
}
63 /** Source properties. */
66 float OuterGain
{0.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
};
75 // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
77 float RolloffFactor2
{0.0f
};
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};
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
}};
108 float EnhWidth
{0.593f
};
111 /** Direct filter and auxiliary send info. */
122 ALeffectslot
*Slot
{};
129 std::array
<SendData
,MaxSendCount
> Send
;
132 * Last user-specified offset, and the offset type (bytes, samples, or
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
};
161 ALsource(const ALsource
&) = delete;
162 ALsource
& operator=(const ALsource
&) = delete;
164 static void SetName(ALCcontext
*context
, ALuint id
, std::string_view name
);
170 void eaxInitialize(ALCcontext
*context
) noexcept
;
171 void eaxDispatch(const EaxCall
& call
);
173 void eaxMarkAsChanged() noexcept
{ mEaxChanged
= true; }
175 static ALsource
* EaxLookupSource(ALCcontext
& al_context
, ALuint source_id
) noexcept
;
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
;
204 Eax1Props i
; // Immediate.
205 Eax1Props d
; // Deferred.
208 using Eax2Props
= EAX20BUFFERPROPERTIES
;
210 Eax2Props i
; // Immediate.
211 Eax2Props d
; // Deferred.
214 using Eax3Props
= EAX30SOURCEPROPERTIES
;
216 Eax3Props i
; // Immediate.
217 Eax3Props d
; // Deferred.
223 EAX40ACTIVEFXSLOTS active_fx_slots
;
227 Eax4Props i
; // Immediate.
228 Eax4Props d
; // Deferred.
232 EAX50SOURCEPROPERTIES source
;
234 EAX50ACTIVEFXSLOTS active_fx_slots
;
235 EaxSpeakerLevels speaker_levels
;
239 Eax5Props i
; // Immediate.
240 Eax5Props d
; // Deferred.
243 ALCcontext
* mEaxAlContext
{};
244 EaxFxSlotIndex mEaxPrimaryFxSlotId
{};
245 EaxActiveFxSlots mEaxActiveFxSlots
{};
255 // ----------------------------------------------------------------------
258 struct Eax1SourceReverbMixValidator
{
259 void operator()(float reverb_mix
) const
261 if (reverb_mix
== EAX_REVERBMIX_USEDISTANCE
)
264 eax_validate_range
<Exception
>(
267 EAX_BUFFER_MINREVERBMIX
,
268 EAX_BUFFER_MAXREVERBMIX
);
272 struct Eax2SourceDirectValidator
{
273 void operator()(long lDirect
) const
275 eax_validate_range
<Exception
>(
279 EAXSOURCE_MAXDIRECT
);
283 struct Eax2SourceDirectHfValidator
{
284 void operator()(long lDirectHF
) const
286 eax_validate_range
<Exception
>(
289 EAXSOURCE_MINDIRECTHF
,
290 EAXSOURCE_MAXDIRECTHF
);
294 struct Eax2SourceRoomValidator
{
295 void operator()(long lRoom
) const
297 eax_validate_range
<Exception
>(
305 struct Eax2SourceRoomHfValidator
{
306 void operator()(long lRoomHF
) const
308 eax_validate_range
<Exception
>(
312 EAXSOURCE_MAXROOMHF
);
316 struct Eax2SourceRoomRolloffFactorValidator
{
317 void operator()(float flRoomRolloffFactor
) const
319 eax_validate_range
<Exception
>(
320 "Room Rolloff Factor",
322 EAXSOURCE_MINROOMROLLOFFFACTOR
,
323 EAXSOURCE_MAXROOMROLLOFFFACTOR
);
327 struct Eax2SourceObstructionValidator
{
328 void operator()(long lObstruction
) const
330 eax_validate_range
<Exception
>(
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
>(
355 EAXSOURCE_MINOCCLUSION
,
356 EAXSOURCE_MAXOCCLUSION
);
360 struct Eax2SourceOcclusionLfRatioValidator
{
361 void operator()(float flOcclusionLFRatio
) const
363 eax_validate_range
<Exception
>(
364 "Occlusion LF Ratio",
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
>(
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
>(
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
>(
432 EAXSOURCE_MINEXCLUSION
,
433 EAXSOURCE_MAXEXCLUSION
);
437 struct Eax3SourceExclusionLfRatioValidator
{
438 void operator()(float flExclusionLFRatio
) const
440 eax_validate_range
<Exception
>(
441 "Exclusion LF Ratio",
443 EAXSOURCE_MINEXCLUSIONLFRATIO
,
444 EAXSOURCE_MAXEXCLUSIONLFRATIO
);
448 struct Eax3SourceDopplerFactorValidator
{
449 void operator()(float flDopplerFactor
) const
451 eax_validate_range
<Exception
>(
454 EAXSOURCE_MINDOPPLERFACTOR
,
455 EAXSOURCE_MAXDOPPLERFACTOR
);
459 struct Eax3SourceRolloffFactorValidator
{
460 void operator()(float flRolloffFactor
) const
462 eax_validate_range
<Exception
>(
465 EAXSOURCE_MINROLLOFFFACTOR
,
466 EAXSOURCE_MAXROLLOFFFACTOR
);
470 struct Eax5SourceMacroFXFactorValidator
{
471 void operator()(float flMacroFXFactor
) const
473 eax_validate_range
<Exception
>(
476 EAXSOURCE_MINMACROFXFACTOR
,
477 EAXSOURCE_MAXMACROFXFACTOR
);
481 struct Eax5SourceFlagsValidator
{
482 void operator()(unsigned long dwFlags
) const
484 eax_validate_range
<Exception
>(
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
);
588 // ----------------------------------------------------------------------
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
>(
628 struct Eax4SendSendHfValidator
{
629 void operator()(long lSendHF
) const
631 eax_validate_range
<Exception
>(
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
> {};
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
:
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
)
777 if(guid
== EAXPROPERTYID_EAX40_FXSlot1
)
779 if(guid
== EAXPROPERTYID_EAX40_FXSlot2
)
781 if(guid
== EAXPROPERTYID_EAX40_FXSlot3
)
783 eax_fail_unknown_receiving_fx_slot_id();
787 struct Eax5SendIndexGetter
{
788 EaxFxSlotIndexValue
operator()(const GUID
&guid
) const
790 if(guid
== EAXPROPERTYID_EAX50_FXSlot0
)
792 if(guid
== EAXPROPERTYID_EAX50_FXSlot1
)
794 if(guid
== EAXPROPERTYID_EAX50_FXSlot2
)
796 if(guid
== EAXPROPERTYID_EAX50_FXSlot3
)
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
,
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
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 GUID
* ids
, size_t max_count
);
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
>();
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; }
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; }