15 #include "alc/context.h"
16 #include "alc/inprogext.h"
19 #include "alnumeric.h"
21 #include "core/voice.h"
25 #include "eax_eax_call.h"
26 #include "eax_fx_slot_index.h"
27 #include "eax_utils.h"
34 enum class SourceStereo
: bool {
35 Normal
= AL_NORMAL_SOFT
,
36 Enhanced
= AL_SUPER_STEREO_SOFT
39 #define DEFAULT_SENDS 2
41 #define INVALID_VOICE_IDX static_cast<ALuint>(-1)
43 struct ALbufferQueueItem
: public VoiceBufferItem
{
44 ALbuffer
*mBuffer
{nullptr};
51 using EaxSourceSourceFilterDirtyFlagsValue
= std::uint_least16_t;
53 struct EaxSourceSourceFilterDirtyFlags
55 using EaxIsBitFieldStruct
= bool;
57 EaxSourceSourceFilterDirtyFlagsValue lDirect
: 1;
58 EaxSourceSourceFilterDirtyFlagsValue lDirectHF
: 1;
59 EaxSourceSourceFilterDirtyFlagsValue lRoom
: 1;
60 EaxSourceSourceFilterDirtyFlagsValue lRoomHF
: 1;
61 EaxSourceSourceFilterDirtyFlagsValue lObstruction
: 1;
62 EaxSourceSourceFilterDirtyFlagsValue flObstructionLFRatio
: 1;
63 EaxSourceSourceFilterDirtyFlagsValue lOcclusion
: 1;
64 EaxSourceSourceFilterDirtyFlagsValue flOcclusionLFRatio
: 1;
65 EaxSourceSourceFilterDirtyFlagsValue flOcclusionRoomRatio
: 1;
66 EaxSourceSourceFilterDirtyFlagsValue flOcclusionDirectRatio
: 1;
67 EaxSourceSourceFilterDirtyFlagsValue lExclusion
: 1;
68 EaxSourceSourceFilterDirtyFlagsValue flExclusionLFRatio
: 1;
69 }; // EaxSourceSourceFilterDirtyFlags
72 using EaxSourceSourceMiscDirtyFlagsValue
= std::uint_least8_t;
74 struct EaxSourceSourceMiscDirtyFlags
76 using EaxIsBitFieldStruct
= bool;
78 EaxSourceSourceMiscDirtyFlagsValue lOutsideVolumeHF
: 1;
79 EaxSourceSourceMiscDirtyFlagsValue flDopplerFactor
: 1;
80 EaxSourceSourceMiscDirtyFlagsValue flRolloffFactor
: 1;
81 EaxSourceSourceMiscDirtyFlagsValue flRoomRolloffFactor
: 1;
82 EaxSourceSourceMiscDirtyFlagsValue flAirAbsorptionFactor
: 1;
83 EaxSourceSourceMiscDirtyFlagsValue ulFlags
: 1;
84 EaxSourceSourceMiscDirtyFlagsValue flMacroFXFactor
: 1;
85 EaxSourceSourceMiscDirtyFlagsValue speaker_levels
: 1;
86 }; // EaxSourceSourceMiscDirtyFlags
89 using EaxSourceSendDirtyFlagsValue
= std::uint_least8_t;
91 struct EaxSourceSendDirtyFlags
93 using EaxIsBitFieldStruct
= bool;
95 EaxSourceSendDirtyFlagsValue lSend
: 1;
96 EaxSourceSendDirtyFlagsValue lSendHF
: 1;
97 EaxSourceSendDirtyFlagsValue lOcclusion
: 1;
98 EaxSourceSendDirtyFlagsValue flOcclusionLFRatio
: 1;
99 EaxSourceSendDirtyFlagsValue flOcclusionRoomRatio
: 1;
100 EaxSourceSendDirtyFlagsValue flOcclusionDirectRatio
: 1;
101 EaxSourceSendDirtyFlagsValue lExclusion
: 1;
102 EaxSourceSendDirtyFlagsValue flExclusionLFRatio
: 1;
103 }; // EaxSourceSendDirtyFlags
106 struct EaxSourceSendsDirtyFlags
108 using EaxIsBitFieldStruct
= bool;
110 EaxSourceSendDirtyFlags sends
[EAX_MAX_FXSLOTS
];
111 }; // EaxSourceSendsDirtyFlags
115 /** Source properties. */
118 float OuterGain
{0.0f
};
121 float InnerAngle
{360.0f
};
122 float OuterAngle
{360.0f
};
123 float RefDistance
{1.0f
};
124 float MaxDistance
{std::numeric_limits
<float>::max()};
125 float RolloffFactor
{1.0f
};
126 std::array
<float,3> Position
{{0.0f
, 0.0f
, 0.0f
}};
127 std::array
<float,3> Velocity
{{0.0f
, 0.0f
, 0.0f
}};
128 std::array
<float,3> Direction
{{0.0f
, 0.0f
, 0.0f
}};
129 std::array
<float,3> OrientAt
{{0.0f
, 0.0f
, -1.0f
}};
130 std::array
<float,3> OrientUp
{{0.0f
, 1.0f
, 0.0f
}};
131 bool HeadRelative
{false};
133 DistanceModel mDistanceModel
{DistanceModel::Default
};
134 Resampler mResampler
{ResamplerDefault
};
135 DirectMode DirectChannels
{DirectMode::Off
};
136 SpatializeMode mSpatialize
{SpatializeMode::Auto
};
137 SourceStereo mStereoMode
{SourceStereo::Normal
};
139 bool DryGainHFAuto
{true};
140 bool WetGainAuto
{true};
141 bool WetGainHFAuto
{true};
142 float OuterGainHF
{1.0f
};
144 float AirAbsorptionFactor
{0.0f
};
145 float RoomRolloffFactor
{0.0f
};
146 float DopplerFactor
{1.0f
};
148 /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
149 * rather than clockwise.
151 std::array
<float,2> StereoPan
{{al::numbers::pi_v
<float>/6.0f
, -al::numbers::pi_v
<float>/6.0f
}};
154 float EnhWidth
{0.593f
};
156 /** Direct filter and auxiliary send info. */
172 std::array
<SendData
,MAX_SENDS
> Send
;
175 * Last user-specified offset, and the offset type (bytes, samples, or
179 ALenum OffsetType
{AL_NONE
};
181 /** Source type (static, streaming, or undetermined) */
182 ALenum SourceType
{AL_UNDETERMINED
};
184 /** Source state (initial, playing, paused, or stopped) */
185 ALenum state
{AL_INITIAL
};
187 /** Source Buffer Queue head. */
188 al::deque
<ALbufferQueueItem
> mQueue
;
190 bool mPropsDirty
{true};
192 /* Index into the context's Voices array. Lazily updated, only checked and
193 * reset when looking up the voice.
195 ALuint VoiceIdx
{INVALID_VOICE_IDX
};
204 ALsource(const ALsource
&) = delete;
205 ALsource
& operator=(const ALsource
&) = delete;
211 void eax_initialize(ALCcontext
*context
) noexcept
;
215 const EaxEaxCall
& eax_call
);
218 void eax_update_filters();
221 EaxContextSharedDirtyFlags dirty_flags
);
223 void eax_commit() { eax_apply_deferred(); }
224 void eax_commit_and_update();
226 bool eax_is_initialized() const noexcept
{ return eax_al_context_
; }
229 static ALsource
* eax_lookup_source(
230 ALCcontext
& al_context
,
231 ALuint source_id
) noexcept
;
235 static constexpr auto eax_max_speakers
= 9;
238 using EaxActiveFxSlots
= std::array
<bool, EAX_MAX_FXSLOTS
>;
239 using EaxSpeakerLevels
= std::array
<long, eax_max_speakers
>;
243 using Sends
= std::array
<EAXSOURCEALLSENDPROPERTIES
, EAX_MAX_FXSLOTS
>;
245 EAX50ACTIVEFXSLOTS active_fx_slots
{};
246 EAX50SOURCEPROPERTIES source
{};
248 EaxSpeakerLevels speaker_levels
{};
252 bool eax_uses_primary_id_
{};
253 bool eax_has_active_fx_slots_
{};
254 bool eax_are_active_fx_slots_dirty_
{};
256 ALCcontext
* eax_al_context_
{};
258 EAXBUFFER_REVERBPROPERTIES eax1_
{};
261 EaxActiveFxSlots eax_active_fx_slots_
{};
263 EaxSourceSendsDirtyFlags eax_sends_dirty_flags_
{};
264 EaxSourceSourceFilterDirtyFlags eax_source_dirty_filter_flags_
{};
265 EaxSourceSourceMiscDirtyFlags eax_source_dirty_misc_flags_
{};
269 static void eax_fail(
270 const char* message
);
273 void eax_set_source_defaults() noexcept
;
274 void eax_set_active_fx_slots_defaults() noexcept
;
275 void eax_set_send_defaults(EAXSOURCEALLSENDPROPERTIES
& eax_send
) noexcept
;
276 void eax_set_sends_defaults() noexcept
;
277 void eax_set_speaker_levels_defaults() noexcept
;
278 void eax_set_defaults() noexcept
;
281 static float eax_calculate_dst_occlusion_mb(
282 long src_occlusion_mb
,
284 float lf_ratio
) noexcept
;
286 EaxAlLowPassParam
eax_create_direct_filter_param() const noexcept
;
288 EaxAlLowPassParam
eax_create_room_filter_param(
289 const ALeffectslot
& fx_slot
,
290 const EAXSOURCEALLSENDPROPERTIES
& send
) const noexcept
;
292 void eax_set_fx_slots();
294 void eax_initialize_fx_slots();
296 void eax_update_direct_filter_internal();
298 void eax_update_room_filters_internal();
300 void eax_update_filters_internal();
302 void eax_update_primary_fx_slot_id();
305 void eax_defer_active_fx_slots(
306 const EaxEaxCall
& eax_call
);
309 static const char* eax_get_exclusion_name() noexcept
;
311 static const char* eax_get_exclusion_lf_ratio_name() noexcept
;
314 static const char* eax_get_occlusion_name() noexcept
;
316 static const char* eax_get_occlusion_lf_ratio_name() noexcept
;
318 static const char* eax_get_occlusion_direct_ratio_name() noexcept
;
320 static const char* eax_get_occlusion_room_ratio_name() noexcept
;
323 static void eax1_validate_reverb_mix(float reverb_mix
);
325 static void eax_validate_send_receiving_fx_slot_guid(
326 const GUID
& guidReceivingFXSlotID
);
328 static void eax_validate_send_send(
331 static void eax_validate_send_send_hf(
334 static void eax_validate_send_occlusion(
337 static void eax_validate_send_occlusion_lf_ratio(
338 float flOcclusionLFRatio
);
340 static void eax_validate_send_occlusion_room_ratio(
341 float flOcclusionRoomRatio
);
343 static void eax_validate_send_occlusion_direct_ratio(
344 float flOcclusionDirectRatio
);
346 static void eax_validate_send_exclusion(
349 static void eax_validate_send_exclusion_lf_ratio(
350 float flExclusionLFRatio
);
352 static void eax_validate_send(
353 const EAXSOURCESENDPROPERTIES
& all
);
355 static void eax_validate_send_exclusion_all(
356 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& all
);
358 static void eax_validate_send_occlusion_all(
359 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& all
);
361 static void eax_validate_send_all(
362 const EAXSOURCEALLSENDPROPERTIES
& all
);
365 static EaxFxSlotIndexValue
eax_get_send_index(
366 const GUID
& send_guid
);
369 void eax_defer_send_send(
371 EaxFxSlotIndexValue index
);
373 void eax_defer_send_send_hf(
375 EaxFxSlotIndexValue index
);
377 void eax_defer_send_occlusion(
379 EaxFxSlotIndexValue index
);
381 void eax_defer_send_occlusion_lf_ratio(
382 float flOcclusionLFRatio
,
383 EaxFxSlotIndexValue index
);
385 void eax_defer_send_occlusion_room_ratio(
386 float flOcclusionRoomRatio
,
387 EaxFxSlotIndexValue index
);
389 void eax_defer_send_occlusion_direct_ratio(
390 float flOcclusionDirectRatio
,
391 EaxFxSlotIndexValue index
);
393 void eax_defer_send_exclusion(
395 EaxFxSlotIndexValue index
);
397 void eax_defer_send_exclusion_lf_ratio(
398 float flExclusionLFRatio
,
399 EaxFxSlotIndexValue index
);
402 const EAXSOURCESENDPROPERTIES
& all
,
403 EaxFxSlotIndexValue index
);
405 void eax_defer_send_exclusion_all(
406 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& all
,
407 EaxFxSlotIndexValue index
);
409 void eax_defer_send_occlusion_all(
410 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& all
,
411 EaxFxSlotIndexValue index
);
413 void eax_defer_send_all(
414 const EAXSOURCEALLSENDPROPERTIES
& all
,
415 EaxFxSlotIndexValue index
);
419 const EaxEaxCall
& eax_call
);
421 void eax_defer_send_exclusion_all(
422 const EaxEaxCall
& eax_call
);
424 void eax_defer_send_occlusion_all(
425 const EaxEaxCall
& eax_call
);
427 void eax_defer_send_all(
428 const EaxEaxCall
& eax_call
);
431 static void eax_validate_source_direct(
434 static void eax_validate_source_direct_hf(
437 static void eax_validate_source_room(
440 static void eax_validate_source_room_hf(
443 static void eax_validate_source_obstruction(
446 static void eax_validate_source_obstruction_lf_ratio(
447 float obstruction_lf_ratio
);
449 static void eax_validate_source_occlusion(
452 static void eax_validate_source_occlusion_lf_ratio(
453 float occlusion_lf_ratio
);
455 static void eax_validate_source_occlusion_room_ratio(
456 float occlusion_room_ratio
);
458 static void eax_validate_source_occlusion_direct_ratio(
459 float occlusion_direct_ratio
);
461 static void eax_validate_source_exclusion(
464 static void eax_validate_source_exclusion_lf_ratio(
465 float exclusion_lf_ratio
);
467 static void eax_validate_source_outside_volume_hf(
468 long outside_volume_hf
);
470 static void eax_validate_source_doppler_factor(
471 float doppler_factor
);
473 static void eax_validate_source_rolloff_factor(
474 float rolloff_factor
);
476 static void eax_validate_source_room_rolloff_factor(
477 float room_rolloff_factor
);
479 static void eax_validate_source_air_absorption_factor(
480 float air_absorption_factor
);
482 static void eax_validate_source_flags(
486 static void eax_validate_source_macro_fx_factor(
487 float macro_fx_factor
);
489 static void eax_validate_source_2d_all(
490 const EAXSOURCE2DPROPERTIES
& all
,
493 static void eax_validate_source_obstruction_all(
494 const EAXOBSTRUCTIONPROPERTIES
& all
);
496 static void eax_validate_source_exclusion_all(
497 const EAXEXCLUSIONPROPERTIES
& all
);
499 static void eax_validate_source_occlusion_all(
500 const EAXOCCLUSIONPROPERTIES
& all
);
502 static void eax_validate_source_all(
503 const EAX20BUFFERPROPERTIES
& all
,
506 static void eax_validate_source_all(
507 const EAX30SOURCEPROPERTIES
& all
,
510 static void eax_validate_source_all(
511 const EAX50SOURCEPROPERTIES
& all
,
514 static void eax_validate_source_speaker_id(
517 static void eax_validate_source_speaker_level(
520 static void eax_validate_source_speaker_level_all(
521 const EAXSPEAKERLEVELPROPERTIES
& all
);
524 void eax_defer_source_direct(
527 void eax_defer_source_direct_hf(
530 void eax_defer_source_room(
533 void eax_defer_source_room_hf(
536 void eax_defer_source_obstruction(
539 void eax_defer_source_obstruction_lf_ratio(
540 float flObstructionLFRatio
);
542 void eax_defer_source_occlusion(
545 void eax_defer_source_occlusion_lf_ratio(
546 float flOcclusionLFRatio
);
548 void eax_defer_source_occlusion_room_ratio(
549 float flOcclusionRoomRatio
);
551 void eax_defer_source_occlusion_direct_ratio(
552 float flOcclusionDirectRatio
);
554 void eax_defer_source_exclusion(
557 void eax_defer_source_exclusion_lf_ratio(
558 float flExclusionLFRatio
);
560 void eax_defer_source_outside_volume_hf(
561 long lOutsideVolumeHF
);
563 void eax_defer_source_doppler_factor(
564 float flDopplerFactor
);
566 void eax_defer_source_rolloff_factor(
567 float flRolloffFactor
);
569 void eax_defer_source_room_rolloff_factor(
570 float flRoomRolloffFactor
);
572 void eax_defer_source_air_absorption_factor(
573 float flAirAbsorptionFactor
);
575 void eax_defer_source_flags(
576 unsigned long ulFlags
);
578 void eax_defer_source_macro_fx_factor(
579 float flMacroFXFactor
);
581 void eax_defer_source_2d_all(
582 const EAXSOURCE2DPROPERTIES
& all
);
584 void eax_defer_source_obstruction_all(
585 const EAXOBSTRUCTIONPROPERTIES
& all
);
587 void eax_defer_source_exclusion_all(
588 const EAXEXCLUSIONPROPERTIES
& all
);
590 void eax_defer_source_occlusion_all(
591 const EAXOCCLUSIONPROPERTIES
& all
);
593 void eax_defer_source_all(
594 const EAX20BUFFERPROPERTIES
& all
);
596 void eax_defer_source_all(
597 const EAX30SOURCEPROPERTIES
& all
);
599 void eax_defer_source_all(
600 const EAX50SOURCEPROPERTIES
& all
);
602 void eax_defer_source_speaker_level_all(
603 const EAXSPEAKERLEVELPROPERTIES
& all
);
606 void eax_defer_source_direct(
607 const EaxEaxCall
& eax_call
);
609 void eax_defer_source_direct_hf(
610 const EaxEaxCall
& eax_call
);
612 void eax_defer_source_room(
613 const EaxEaxCall
& eax_call
);
615 void eax_defer_source_room_hf(
616 const EaxEaxCall
& eax_call
);
618 void eax_defer_source_obstruction(
619 const EaxEaxCall
& eax_call
);
621 void eax_defer_source_obstruction_lf_ratio(
622 const EaxEaxCall
& eax_call
);
624 void eax_defer_source_occlusion(
625 const EaxEaxCall
& eax_call
);
627 void eax_defer_source_occlusion_lf_ratio(
628 const EaxEaxCall
& eax_call
);
630 void eax_defer_source_occlusion_room_ratio(
631 const EaxEaxCall
& eax_call
);
633 void eax_defer_source_occlusion_direct_ratio(
634 const EaxEaxCall
& eax_call
);
636 void eax_defer_source_exclusion(
637 const EaxEaxCall
& eax_call
);
639 void eax_defer_source_exclusion_lf_ratio(
640 const EaxEaxCall
& eax_call
);
642 void eax_defer_source_outside_volume_hf(
643 const EaxEaxCall
& eax_call
);
645 void eax_defer_source_doppler_factor(
646 const EaxEaxCall
& eax_call
);
648 void eax_defer_source_rolloff_factor(
649 const EaxEaxCall
& eax_call
);
651 void eax_defer_source_room_rolloff_factor(
652 const EaxEaxCall
& eax_call
);
654 void eax_defer_source_air_absorption_factor(
655 const EaxEaxCall
& eax_call
);
657 void eax_defer_source_flags(
658 const EaxEaxCall
& eax_call
);
660 void eax_defer_source_macro_fx_factor(
661 const EaxEaxCall
& eax_call
);
663 void eax_defer_source_2d_all(
664 const EaxEaxCall
& eax_call
);
666 void eax_defer_source_obstruction_all(
667 const EaxEaxCall
& eax_call
);
669 void eax_defer_source_exclusion_all(
670 const EaxEaxCall
& eax_call
);
672 void eax_defer_source_occlusion_all(
673 const EaxEaxCall
& eax_call
);
675 void eax_defer_source_all(
676 const EaxEaxCall
& eax_call
);
678 void eax_defer_source_speaker_level_all(
679 const EaxEaxCall
& eax_call
);
682 void eax_set_outside_volume_hf();
684 void eax_set_doppler_factor();
686 void eax_set_rolloff_factor();
688 void eax_set_room_rolloff_factor();
690 void eax_set_air_absorption_factor();
693 void eax_set_direct_hf_auto_flag();
695 void eax_set_room_auto_flag();
697 void eax_set_room_hf_auto_flag();
699 void eax_set_flags();
702 void eax_set_macro_fx_factor();
704 void eax_set_speaker_levels();
708 void eax1_set_reverb_mix(const EaxEaxCall
& eax_call
);
709 void eax1_set(const EaxEaxCall
& eax_call
);
711 void eax_apply_deferred();
714 const EaxEaxCall
& eax_call
);
717 static const GUID
& eax_get_send_fx_slot_guid(
719 EaxFxSlotIndexValue fx_slot_index
);
721 static void eax_copy_send(
722 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
723 EAXSOURCESENDPROPERTIES
& dst_send
);
725 static void eax_copy_send(
726 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
727 EAXSOURCEALLSENDPROPERTIES
& dst_send
);
729 static void eax_copy_send(
730 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
731 EAXSOURCEOCCLUSIONSENDPROPERTIES
& dst_send
);
733 static void eax_copy_send(
734 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
735 EAXSOURCEEXCLUSIONSENDPROPERTIES
& dst_send
);
741 void eax_api_get_send_properties(
742 const EaxEaxCall
& eax_call
) const
744 const auto eax_version
= eax_call
.get_version();
745 const auto dst_sends
= eax_call
.get_values
<TException
, TSrcSend
>();
746 const auto send_count
= dst_sends
.size();
748 for (auto fx_slot_index
= EaxFxSlotIndexValue
{}; fx_slot_index
< send_count
; ++fx_slot_index
)
750 auto& dst_send
= dst_sends
[fx_slot_index
];
751 const auto& src_send
= eax_
.sends
[fx_slot_index
];
753 eax_copy_send(src_send
, dst_send
);
755 dst_send
.guidReceivingFXSlotID
= eax_get_send_fx_slot_guid(eax_version
, fx_slot_index
);
760 void eax1_get(const EaxEaxCall
& eax_call
);
762 void eax_api_get_source_all_v2(
763 const EaxEaxCall
& eax_call
);
765 void eax_api_get_source_all_v3(
766 const EaxEaxCall
& eax_call
);
768 void eax_api_get_source_all_v5(
769 const EaxEaxCall
& eax_call
);
771 void eax_api_get_source_all(
772 const EaxEaxCall
& eax_call
);
774 void eax_api_get_source_all_obstruction(
775 const EaxEaxCall
& eax_call
);
777 void eax_api_get_source_all_occlusion(
778 const EaxEaxCall
& eax_call
);
780 void eax_api_get_source_all_exclusion(
781 const EaxEaxCall
& eax_call
);
783 void eax_api_get_source_active_fx_slot_id(
784 const EaxEaxCall
& eax_call
);
786 void eax_api_get_source_all_2d(
787 const EaxEaxCall
& eax_call
);
789 void eax_api_get_source_speaker_level_all(
790 const EaxEaxCall
& eax_call
);
793 const EaxEaxCall
& eax_call
);
796 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
797 void eax_set_al_source_send(ALeffectslot
*slot
, size_t sendidx
,
798 const EaxAlLowPassParam
&filter
);
802 void UpdateAllSourceProps(ALCcontext
*context
);