11 #include <string_view>
19 #include "alnumbers.h"
20 #include "alnumeric.h"
22 #include "core/context.h"
23 #include "core/voice.h"
28 #include "eax/exception.h"
29 #include "eax/fx_slot_index.h"
30 #include "eax/utils.h"
35 enum class Resampler
: uint8_t;
37 enum class SourceStereo
: bool {
38 Normal
= AL_NORMAL_SOFT
,
39 Enhanced
= AL_SUPER_STEREO_SOFT
42 inline constexpr size_t DefaultSendCount
{2};
44 inline constexpr ALuint InvalidVoiceIndex
{std::numeric_limits
<ALuint
>::max()};
46 inline bool sBufferSubDataCompat
{false};
48 struct ALbufferQueueItem
: public VoiceBufferItem
{
49 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 Eax2SourceDirectValidator
{}(props
.lDirect
);
546 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
547 Eax2SourceRoomValidator
{}(props
.lRoom
);
548 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
549 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
550 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
551 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
552 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
553 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
554 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
555 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
556 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
557 Eax2SourceOutsideVolumeHfValidator
{}(props
.lOutsideVolumeHF
);
558 Eax3SourceDopplerFactorValidator
{}(props
.flDopplerFactor
);
559 Eax3SourceRolloffFactorValidator
{}(props
.flRolloffFactor
);
560 Eax2SourceRoomRolloffFactorValidator
{}(props
.flRoomRolloffFactor
);
561 Eax2SourceAirAbsorptionFactorValidator
{}(props
.flAirAbsorptionFactor
);
562 Eax5SourceFlagsValidator
{}(props
.ulFlags
);
563 Eax5SourceMacroFXFactorValidator
{}(props
.flMacroFXFactor
);
567 struct Eax5SourceAll2dValidator
{
568 void operator()(const EAXSOURCE2DPROPERTIES
& props
) const
570 Eax2SourceDirectValidator
{}(props
.lDirect
);
571 Eax2SourceDirectHfValidator
{}(props
.lDirectHF
);
572 Eax2SourceRoomValidator
{}(props
.lRoom
);
573 Eax2SourceRoomHfValidator
{}(props
.lRoomHF
);
574 Eax5SourceFlagsValidator
{}(props
.ulFlags
);
578 struct Eax4ObstructionValidator
{
579 void operator()(const EAXOBSTRUCTIONPROPERTIES
& props
) const
581 Eax2SourceObstructionValidator
{}(props
.lObstruction
);
582 Eax2SourceObstructionLfRatioValidator
{}(props
.flObstructionLFRatio
);
586 struct Eax4OcclusionValidator
{
587 void operator()(const EAXOCCLUSIONPROPERTIES
& props
) const
589 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
590 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
591 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
592 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
596 struct Eax4ExclusionValidator
{
597 void operator()(const EAXEXCLUSIONPROPERTIES
& props
) const
599 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
600 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
605 // ----------------------------------------------------------------------
608 struct Eax4SendReceivingFxSlotIdValidator
{
609 void operator()(const GUID
& guidReceivingFXSlotID
) const
611 if (guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot0
&&
612 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot1
&&
613 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot2
&&
614 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX40_FXSlot3
)
616 eax_fail_unknown_receiving_fx_slot_id();
621 struct Eax5SendReceivingFxSlotIdValidator
{
622 void operator()(const GUID
& guidReceivingFXSlotID
) const
624 if (guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot0
&&
625 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot1
&&
626 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot2
&&
627 guidReceivingFXSlotID
!= EAXPROPERTYID_EAX50_FXSlot3
)
629 eax_fail_unknown_receiving_fx_slot_id();
634 struct Eax4SendSendValidator
{
635 void operator()(long lSend
) const
637 eax_validate_range
<Exception
>(
645 struct Eax4SendSendHfValidator
{
646 void operator()(long lSendHF
) const
648 eax_validate_range
<Exception
>(
652 EAXSOURCE_MAXSENDHF
);
656 template<typename TIdValidator
>
657 struct EaxSendValidator
{
658 void operator()(const EAXSOURCESENDPROPERTIES
& props
) const
660 TIdValidator
{}(props
.guidReceivingFXSlotID
);
661 Eax4SendSendValidator
{}(props
.lSend
);
662 Eax4SendSendHfValidator
{}(props
.lSendHF
);
666 struct Eax4SendValidator
: EaxSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
667 struct Eax5SendValidator
: EaxSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
669 template<typename TIdValidator
>
670 struct EaxOcclusionSendValidator
{
671 void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES
& props
) const
673 TIdValidator
{}(props
.guidReceivingFXSlotID
);
674 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
675 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
676 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
677 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
681 struct Eax4OcclusionSendValidator
: EaxOcclusionSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
682 struct Eax5OcclusionSendValidator
: EaxOcclusionSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
684 template<typename TIdValidator
>
685 struct EaxExclusionSendValidator
{
686 void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES
& props
) const
688 TIdValidator
{}(props
.guidReceivingFXSlotID
);
689 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
690 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
694 struct Eax4ExclusionSendValidator
: EaxExclusionSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
695 struct Eax5ExclusionSendValidator
: EaxExclusionSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
697 template<typename TIdValidator
>
698 struct EaxAllSendValidator
{
699 void operator()(const EAXSOURCEALLSENDPROPERTIES
& props
) const
701 TIdValidator
{}(props
.guidReceivingFXSlotID
);
702 Eax4SendSendValidator
{}(props
.lSend
);
703 Eax4SendSendHfValidator
{}(props
.lSendHF
);
704 Eax2SourceOcclusionValidator
{}(props
.lOcclusion
);
705 Eax2SourceOcclusionLfRatioValidator
{}(props
.flOcclusionLFRatio
);
706 Eax2SourceOcclusionRoomRatioValidator
{}(props
.flOcclusionRoomRatio
);
707 Eax3SourceOcclusionDirectRatioValidator
{}(props
.flOcclusionDirectRatio
);
708 Eax3SourceExclusionValidator
{}(props
.lExclusion
);
709 Eax3SourceExclusionLfRatioValidator
{}(props
.flExclusionLFRatio
);
713 struct Eax4AllSendValidator
: EaxAllSendValidator
<Eax4SendReceivingFxSlotIdValidator
> {};
714 struct Eax5AllSendValidator
: EaxAllSendValidator
<Eax5SendReceivingFxSlotIdValidator
> {};
717 // ----------------------------------------------------------------------
718 // Active FX slot ID validators
720 struct Eax4ActiveFxSlotIdValidator
{
721 void operator()(const GUID
&guid
) const
723 if(guid
!= EAX_NULL_GUID
&& guid
!= EAX_PrimaryFXSlotID
724 && guid
!= EAXPROPERTYID_EAX40_FXSlot0
&& guid
!= EAXPROPERTYID_EAX40_FXSlot1
725 && guid
!= EAXPROPERTYID_EAX40_FXSlot2
&& guid
!= EAXPROPERTYID_EAX40_FXSlot3
)
727 eax_fail_unknown_active_fx_slot_id();
732 struct Eax5ActiveFxSlotIdValidator
{
733 void operator()(const GUID
&guid
) const
735 if(guid
!= EAX_NULL_GUID
&& guid
!= EAX_PrimaryFXSlotID
736 && guid
!= EAXPROPERTYID_EAX50_FXSlot0
&& guid
!= EAXPROPERTYID_EAX50_FXSlot1
737 && guid
!= EAXPROPERTYID_EAX50_FXSlot2
&& guid
!= EAXPROPERTYID_EAX50_FXSlot3
)
739 eax_fail_unknown_active_fx_slot_id();
744 // Active FX slot ID validators
745 // ----------------------------------------------------------------------
746 // Speaker level validators.
748 struct Eax5SpeakerIdValidator
{
749 void operator()(long lSpeakerID
) const
751 switch (lSpeakerID
) {
752 case EAXSPEAKER_FRONT_LEFT
:
753 case EAXSPEAKER_FRONT_CENTER
:
754 case EAXSPEAKER_FRONT_RIGHT
:
755 case EAXSPEAKER_SIDE_RIGHT
:
756 case EAXSPEAKER_REAR_RIGHT
:
757 case EAXSPEAKER_REAR_CENTER
:
758 case EAXSPEAKER_REAR_LEFT
:
759 case EAXSPEAKER_SIDE_LEFT
:
760 case EAXSPEAKER_LOW_FREQUENCY
:
764 eax_fail("Unknown speaker ID.");
769 struct Eax5SpeakerLevelValidator
{
770 void operator()(long lLevel
) const
772 // TODO Use a range when the feature will be implemented.
773 if (lLevel
!= EAXSOURCE_DEFAULTSPEAKERLEVEL
)
774 eax_fail("Speaker level out of range.");
778 struct Eax5SpeakerAllValidator
{
779 void operator()(const EAXSPEAKERLEVELPROPERTIES
& all
) const
781 Eax5SpeakerIdValidator
{}(all
.lSpeakerID
);
782 Eax5SpeakerLevelValidator
{}(all
.lLevel
);
786 // Speaker level validators.
787 // ----------------------------------------------------------------------
789 struct Eax4SendIndexGetter
{
790 EaxFxSlotIndexValue
operator()(const GUID
&guid
) const
792 if(guid
== EAXPROPERTYID_EAX40_FXSlot0
)
794 if(guid
== EAXPROPERTYID_EAX40_FXSlot1
)
796 if(guid
== EAXPROPERTYID_EAX40_FXSlot2
)
798 if(guid
== EAXPROPERTYID_EAX40_FXSlot3
)
800 eax_fail_unknown_receiving_fx_slot_id();
804 struct Eax5SendIndexGetter
{
805 EaxFxSlotIndexValue
operator()(const GUID
&guid
) const
807 if(guid
== EAXPROPERTYID_EAX50_FXSlot0
)
809 if(guid
== EAXPROPERTYID_EAX50_FXSlot1
)
811 if(guid
== EAXPROPERTYID_EAX50_FXSlot2
)
813 if(guid
== EAXPROPERTYID_EAX50_FXSlot3
)
815 eax_fail_unknown_receiving_fx_slot_id();
819 [[noreturn
]] static void eax_fail(const char* message
);
820 [[noreturn
]] static void eax_fail_unknown_property_id();
821 [[noreturn
]] static void eax_fail_unknown_version();
822 [[noreturn
]] static void eax_fail_unknown_active_fx_slot_id();
823 [[noreturn
]] static void eax_fail_unknown_receiving_fx_slot_id();
825 static void eax_set_sends_defaults(EaxSends
& sends
, const EaxFxSlotIds
& ids
) noexcept
;
826 static void eax1_set_defaults(Eax1Props
& props
) noexcept
;
827 void eax1_set_defaults() noexcept
;
828 static void eax2_set_defaults(Eax2Props
& props
) noexcept
;
829 void eax2_set_defaults() noexcept
;
830 static void eax3_set_defaults(Eax3Props
& props
) noexcept
;
831 void eax3_set_defaults() noexcept
;
832 static void eax4_set_sends_defaults(EaxSends
& sends
) noexcept
;
833 static void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS
& slots
) noexcept
;
834 void eax4_set_defaults() noexcept
;
835 static void eax5_set_source_defaults(EAX50SOURCEPROPERTIES
& props
) noexcept
;
836 static void eax5_set_sends_defaults(EaxSends
& sends
) noexcept
;
837 static void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS
& slots
) noexcept
;
838 static void eax5_set_speaker_levels_defaults(EaxSpeakerLevels
& speaker_levels
) noexcept
;
839 static void eax5_set_defaults(Eax5Props
& props
) noexcept
;
840 void eax5_set_defaults() noexcept
;
841 void eax_set_defaults() noexcept
;
843 static void eax1_translate(const Eax1Props
& src
, Eax5Props
& dst
) noexcept
;
844 static void eax2_translate(const Eax2Props
& src
, Eax5Props
& dst
) noexcept
;
845 static void eax3_translate(const Eax3Props
& src
, Eax5Props
& dst
) noexcept
;
846 static void eax4_translate(const Eax4Props
& src
, Eax5Props
& dst
) noexcept
;
848 static float eax_calculate_dst_occlusion_mb(
849 long src_occlusion_mb
,
851 float lf_ratio
) noexcept
;
853 [[nodiscard
]] auto eax_create_direct_filter_param() const noexcept
-> EaxAlLowPassParam
;
855 [[nodiscard
]] auto eax_create_room_filter_param(const ALeffectslot
& fx_slot
,
856 const EAXSOURCEALLSENDPROPERTIES
& send
) const noexcept
-> EaxAlLowPassParam
;
858 void eax_update_direct_filter();
859 void eax_update_room_filters();
860 void eax_commit_filters();
862 static void eax_copy_send_for_get(
863 const EAXSOURCEALLSENDPROPERTIES
& src
,
864 EAXSOURCESENDPROPERTIES
& dst
) noexcept
866 dst
= reinterpret_cast<const EAXSOURCESENDPROPERTIES
&>(src
);
869 static void eax_copy_send_for_get(
870 const EAXSOURCEALLSENDPROPERTIES
& src
,
871 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
876 static void eax_copy_send_for_get(
877 const EAXSOURCEALLSENDPROPERTIES
& src
,
878 EAXSOURCEOCCLUSIONSENDPROPERTIES
& dst
) noexcept
880 dst
.guidReceivingFXSlotID
= src
.guidReceivingFXSlotID
;
881 dst
.lOcclusion
= src
.lOcclusion
;
882 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
883 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
884 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
887 static void eax_copy_send_for_get(
888 const EAXSOURCEALLSENDPROPERTIES
& src
,
889 EAXSOURCEEXCLUSIONSENDPROPERTIES
& dst
) noexcept
891 dst
.guidReceivingFXSlotID
= src
.guidReceivingFXSlotID
;
892 dst
.lExclusion
= src
.lExclusion
;
893 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
896 template<typename TDstSend
>
897 void eax_get_sends(const EaxCall
& call
, const EaxSends
& src_sends
)
899 const auto dst_sends
= call
.get_values
<TDstSend
>(EAX_MAX_FXSLOTS
);
900 const auto count
= dst_sends
.size();
902 for (auto i
= decltype(count
){}; i
< count
; ++i
) {
903 const auto& src_send
= src_sends
[i
];
904 auto& dst_send
= dst_sends
[i
];
905 eax_copy_send_for_get(src_send
, dst_send
);
909 static void eax_get_active_fx_slot_id(const EaxCall
& call
, const al::span
<const GUID
> src_ids
);
910 static void eax1_get(const EaxCall
& call
, const Eax1Props
& props
);
911 static void eax2_get(const EaxCall
& call
, const Eax2Props
& props
);
912 static void eax3_get_obstruction(const EaxCall
& call
, const Eax3Props
& props
);
913 static void eax3_get_occlusion(const EaxCall
& call
, const Eax3Props
& props
);
914 static void eax3_get_exclusion(const EaxCall
& call
, const Eax3Props
& props
);
915 static void eax3_get(const EaxCall
& call
, const Eax3Props
& props
);
916 void eax4_get(const EaxCall
& call
, const Eax4Props
& props
);
917 static void eax5_get_all_2d(const EaxCall
& call
, const EAX50SOURCEPROPERTIES
& props
);
918 static void eax5_get_speaker_levels(const EaxCall
& call
, const EaxSpeakerLevels
& props
);
919 void eax5_get(const EaxCall
& call
, const Eax5Props
& props
);
920 void eax_get(const EaxCall
& call
);
922 static void eax_copy_send_for_set(
923 const EAXSOURCESENDPROPERTIES
& src
,
924 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
926 dst
.lSend
= src
.lSend
;
927 dst
.lSendHF
= src
.lSendHF
;
930 static void eax_copy_send_for_set(
931 const EAXSOURCEALLSENDPROPERTIES
& src
,
932 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
934 dst
.lSend
= src
.lSend
;
935 dst
.lSendHF
= src
.lSendHF
;
936 dst
.lOcclusion
= src
.lOcclusion
;
937 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
938 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
939 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
940 dst
.lExclusion
= src
.lExclusion
;
941 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
944 static void eax_copy_send_for_set(
945 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& src
,
946 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
948 dst
.lOcclusion
= src
.lOcclusion
;
949 dst
.flOcclusionLFRatio
= src
.flOcclusionLFRatio
;
950 dst
.flOcclusionRoomRatio
= src
.flOcclusionRoomRatio
;
951 dst
.flOcclusionDirectRatio
= src
.flOcclusionDirectRatio
;
954 static void eax_copy_send_for_set(
955 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& src
,
956 EAXSOURCEALLSENDPROPERTIES
& dst
) noexcept
958 dst
.lExclusion
= src
.lExclusion
;
959 dst
.flExclusionLFRatio
= src
.flExclusionLFRatio
;
962 template<typename TValidator
, typename TIndexGetter
, typename TSrcSend
>
963 void eax_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
965 const auto src_sends
= call
.get_values
<const TSrcSend
>(EAX_MAX_FXSLOTS
);
966 std::for_each(src_sends
.cbegin(), src_sends
.cend(), TValidator
{});
967 const auto count
= src_sends
.size();
968 const auto index_getter
= TIndexGetter
{};
970 for (auto i
= decltype(count
){}; i
< count
; ++i
) {
971 const auto& src_send
= src_sends
[i
];
972 const auto dst_index
= index_getter(src_send
.guidReceivingFXSlotID
);
973 auto& dst_send
= dst_sends
[dst_index
];
974 eax_copy_send_for_set(src_send
, dst_send
);
978 template<typename TValidator
, typename TSrcSend
>
979 void eax4_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
981 eax_defer_sends
<TValidator
, Eax4SendIndexGetter
, TSrcSend
>(call
, dst_sends
);
984 template<typename TValidator
, typename TSrcSend
>
985 void eax5_defer_sends(const EaxCall
& call
, EaxSends
& dst_sends
)
987 eax_defer_sends
<TValidator
, Eax5SendIndexGetter
, TSrcSend
>(call
, dst_sends
);
990 template<typename TValidator
, size_t TIdCount
>
991 void eax_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
993 const auto src_ids
= call
.get_values
<const GUID
>(TIdCount
);
994 std::for_each(src_ids
.cbegin(), src_ids
.cend(), TValidator
{});
995 std::uninitialized_copy(src_ids
.cbegin(), src_ids
.cend(), dst_ids
.begin());
998 template<size_t TIdCount
>
999 void eax4_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
1001 eax_defer_active_fx_slot_id
<Eax4ActiveFxSlotIdValidator
>(call
, dst_ids
);
1004 template<size_t TIdCount
>
1005 void eax5_defer_active_fx_slot_id(const EaxCall
& call
, const al::span
<GUID
,TIdCount
> dst_ids
)
1007 eax_defer_active_fx_slot_id
<Eax5ActiveFxSlotIdValidator
>(call
, dst_ids
);
1010 template<typename TValidator
, typename TProperty
>
1011 static void eax_defer(const EaxCall
& call
, TProperty
& property
)
1013 const auto& value
= call
.get_value
<Exception
, const TProperty
>();
1014 TValidator
{}(value
);
1018 // Defers source's sub-properties (obstruction, occlusion, exclusion).
1019 template<typename TValidator
, typename TSubproperty
, typename TProperty
>
1020 void eax_defer_sub(const EaxCall
& call
, TProperty
& property
)
1022 const auto& src_props
= call
.get_value
<Exception
, const TSubproperty
>();
1023 TValidator
{}(src_props
);
1024 auto& dst_props
= reinterpret_cast<TSubproperty
&>(property
);
1025 dst_props
= src_props
;
1028 void eax_set_efx_outer_gain_hf();
1029 void eax_set_efx_doppler_factor();
1030 void eax_set_efx_rolloff_factor();
1031 void eax_set_efx_room_rolloff_factor();
1032 void eax_set_efx_air_absorption_factor();
1033 void eax_set_efx_dry_gain_hf_auto();
1034 void eax_set_efx_wet_gain_auto();
1035 void eax_set_efx_wet_gain_hf_auto();
1037 static void eax1_set(const EaxCall
& call
, Eax1Props
& props
);
1038 static void eax2_set(const EaxCall
& call
, Eax2Props
& props
);
1039 void eax3_set(const EaxCall
& call
, Eax3Props
& props
);
1040 void eax4_set(const EaxCall
& call
, Eax4Props
& props
);
1041 static void eax5_defer_all_2d(const EaxCall
& call
, EAX50SOURCEPROPERTIES
& props
);
1042 static void eax5_defer_speaker_levels(const EaxCall
& call
, EaxSpeakerLevels
& props
);
1043 void eax5_set(const EaxCall
& call
, Eax5Props
& props
);
1044 void eax_set(const EaxCall
& call
);
1046 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
1047 void eax_set_al_source_send(ALeffectslot
*slot
, size_t sendidx
,
1048 const EaxAlLowPassParam
&filter
);
1050 void eax_commit_active_fx_slots();
1051 #endif // ALSOFT_EAX
1054 void UpdateAllSourceProps(ALCcontext
*context
);
1056 struct SourceSubList
{
1057 uint64_t FreeMask
{~0_u64
};
1058 gsl::owner
<std::array
<ALsource
,64>*> Sources
{nullptr};
1060 SourceSubList() noexcept
= default;
1061 SourceSubList(const SourceSubList
&) = delete;
1062 SourceSubList(SourceSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Sources
{rhs
.Sources
}
1063 { rhs
.FreeMask
= ~0_u64
; rhs
.Sources
= nullptr; }
1066 SourceSubList
& operator=(const SourceSubList
&) = delete;
1067 SourceSubList
& operator=(SourceSubList
&& rhs
) noexcept
1068 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Sources
, rhs
.Sources
); return *this; }