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
};
127 // For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
129 float RolloffFactor2
{0.0f
};
131 std::array
<float,3> Position
{{0.0f
, 0.0f
, 0.0f
}};
132 std::array
<float,3> Velocity
{{0.0f
, 0.0f
, 0.0f
}};
133 std::array
<float,3> Direction
{{0.0f
, 0.0f
, 0.0f
}};
134 std::array
<float,3> OrientAt
{{0.0f
, 0.0f
, -1.0f
}};
135 std::array
<float,3> OrientUp
{{0.0f
, 1.0f
, 0.0f
}};
136 bool HeadRelative
{false};
138 DistanceModel mDistanceModel
{DistanceModel::Default
};
139 Resampler mResampler
{ResamplerDefault
};
140 DirectMode DirectChannels
{DirectMode::Off
};
141 SpatializeMode mSpatialize
{SpatializeMode::Auto
};
142 SourceStereo mStereoMode
{SourceStereo::Normal
};
144 bool DryGainHFAuto
{true};
145 bool WetGainAuto
{true};
146 bool WetGainHFAuto
{true};
147 float OuterGainHF
{1.0f
};
149 float AirAbsorptionFactor
{0.0f
};
150 float RoomRolloffFactor
{0.0f
};
151 float DopplerFactor
{1.0f
};
153 /* NOTE: Stereo pan angles are specified in radians, counter-clockwise
154 * rather than clockwise.
156 std::array
<float,2> StereoPan
{{al::numbers::pi_v
<float>/6.0f
, -al::numbers::pi_v
<float>/6.0f
}};
159 float EnhWidth
{0.593f
};
161 /** Direct filter and auxiliary send info. */
177 std::array
<SendData
,MAX_SENDS
> Send
;
180 * Last user-specified offset, and the offset type (bytes, samples, or
184 ALenum OffsetType
{AL_NONE
};
186 /** Source type (static, streaming, or undetermined) */
187 ALenum SourceType
{AL_UNDETERMINED
};
189 /** Source state (initial, playing, paused, or stopped) */
190 ALenum state
{AL_INITIAL
};
192 /** Source Buffer Queue head. */
193 al::deque
<ALbufferQueueItem
> mQueue
;
195 bool mPropsDirty
{true};
197 /* Index into the context's Voices array. Lazily updated, only checked and
198 * reset when looking up the voice.
200 ALuint VoiceIdx
{INVALID_VOICE_IDX
};
209 ALsource(const ALsource
&) = delete;
210 ALsource
& operator=(const ALsource
&) = delete;
216 void eax_initialize(ALCcontext
*context
) noexcept
;
219 void eax_dispatch(const EaxEaxCall
& eax_call
)
220 { eax_call
.is_get() ? eax_get(eax_call
) : eax_set(eax_call
); }
223 void eax_update_filters();
226 EaxContextSharedDirtyFlags dirty_flags
);
228 void eax_commit() { eax_apply_deferred(); }
229 void eax_commit_and_update();
231 bool eax_is_initialized() const noexcept
{ return eax_al_context_
; }
234 static ALsource
* eax_lookup_source(
235 ALCcontext
& al_context
,
236 ALuint source_id
) noexcept
;
240 static constexpr auto eax_max_speakers
= 9;
243 using EaxActiveFxSlots
= std::array
<bool, EAX_MAX_FXSLOTS
>;
244 using EaxSpeakerLevels
= std::array
<long, eax_max_speakers
>;
248 using Sends
= std::array
<EAXSOURCEALLSENDPROPERTIES
, EAX_MAX_FXSLOTS
>;
250 EAX50ACTIVEFXSLOTS active_fx_slots
{};
251 EAX50SOURCEPROPERTIES source
{};
253 EaxSpeakerLevels speaker_levels
{};
257 bool eax_uses_primary_id_
{};
258 bool eax_has_active_fx_slots_
{};
259 bool eax_are_active_fx_slots_dirty_
{};
261 ALCcontext
* eax_al_context_
{};
263 EAXBUFFER_REVERBPROPERTIES eax1_
{};
266 EaxActiveFxSlots eax_active_fx_slots_
{};
268 EaxSourceSendsDirtyFlags eax_sends_dirty_flags_
{};
269 EaxSourceSourceFilterDirtyFlags eax_source_dirty_filter_flags_
{};
270 EaxSourceSourceMiscDirtyFlags eax_source_dirty_misc_flags_
{};
274 static void eax_fail(
275 const char* message
);
278 void eax_set_source_defaults() noexcept
;
279 void eax_set_active_fx_slots_defaults() noexcept
;
280 void eax_set_send_defaults(EAXSOURCEALLSENDPROPERTIES
& eax_send
) noexcept
;
281 void eax_set_sends_defaults() noexcept
;
282 void eax_set_speaker_levels_defaults() noexcept
;
283 void eax_set_defaults() noexcept
;
286 static float eax_calculate_dst_occlusion_mb(
287 long src_occlusion_mb
,
289 float lf_ratio
) noexcept
;
291 EaxAlLowPassParam
eax_create_direct_filter_param() const noexcept
;
293 EaxAlLowPassParam
eax_create_room_filter_param(
294 const ALeffectslot
& fx_slot
,
295 const EAXSOURCEALLSENDPROPERTIES
& send
) const noexcept
;
297 void eax_set_fx_slots();
299 void eax_initialize_fx_slots();
301 void eax_update_direct_filter_internal();
303 void eax_update_room_filters_internal();
305 void eax_update_filters_internal();
307 void eax_update_primary_fx_slot_id();
310 void eax_defer_active_fx_slots(
311 const EaxEaxCall
& eax_call
);
314 static const char* eax_get_exclusion_name() noexcept
;
316 static const char* eax_get_exclusion_lf_ratio_name() noexcept
;
319 static const char* eax_get_occlusion_name() noexcept
;
321 static const char* eax_get_occlusion_lf_ratio_name() noexcept
;
323 static const char* eax_get_occlusion_direct_ratio_name() noexcept
;
325 static const char* eax_get_occlusion_room_ratio_name() noexcept
;
328 static void eax1_validate_reverb_mix(float reverb_mix
);
330 static void eax_validate_send_receiving_fx_slot_guid(
331 const GUID
& guidReceivingFXSlotID
);
333 static void eax_validate_send_send(
336 static void eax_validate_send_send_hf(
339 static void eax_validate_send_occlusion(
342 static void eax_validate_send_occlusion_lf_ratio(
343 float flOcclusionLFRatio
);
345 static void eax_validate_send_occlusion_room_ratio(
346 float flOcclusionRoomRatio
);
348 static void eax_validate_send_occlusion_direct_ratio(
349 float flOcclusionDirectRatio
);
351 static void eax_validate_send_exclusion(
354 static void eax_validate_send_exclusion_lf_ratio(
355 float flExclusionLFRatio
);
357 static void eax_validate_send(
358 const EAXSOURCESENDPROPERTIES
& all
);
360 static void eax_validate_send_exclusion_all(
361 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& all
);
363 static void eax_validate_send_occlusion_all(
364 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& all
);
366 static void eax_validate_send_all(
367 const EAXSOURCEALLSENDPROPERTIES
& all
);
370 static EaxFxSlotIndexValue
eax_get_send_index(
371 const GUID
& send_guid
);
374 void eax_defer_send_send(
376 EaxFxSlotIndexValue index
);
378 void eax_defer_send_send_hf(
380 EaxFxSlotIndexValue index
);
382 void eax_defer_send_occlusion(
384 EaxFxSlotIndexValue index
);
386 void eax_defer_send_occlusion_lf_ratio(
387 float flOcclusionLFRatio
,
388 EaxFxSlotIndexValue index
);
390 void eax_defer_send_occlusion_room_ratio(
391 float flOcclusionRoomRatio
,
392 EaxFxSlotIndexValue index
);
394 void eax_defer_send_occlusion_direct_ratio(
395 float flOcclusionDirectRatio
,
396 EaxFxSlotIndexValue index
);
398 void eax_defer_send_exclusion(
400 EaxFxSlotIndexValue index
);
402 void eax_defer_send_exclusion_lf_ratio(
403 float flExclusionLFRatio
,
404 EaxFxSlotIndexValue index
);
407 const EAXSOURCESENDPROPERTIES
& all
,
408 EaxFxSlotIndexValue index
);
410 void eax_defer_send_exclusion_all(
411 const EAXSOURCEEXCLUSIONSENDPROPERTIES
& all
,
412 EaxFxSlotIndexValue index
);
414 void eax_defer_send_occlusion_all(
415 const EAXSOURCEOCCLUSIONSENDPROPERTIES
& all
,
416 EaxFxSlotIndexValue index
);
418 void eax_defer_send_all(
419 const EAXSOURCEALLSENDPROPERTIES
& all
,
420 EaxFxSlotIndexValue index
);
424 const EaxEaxCall
& eax_call
);
426 void eax_defer_send_exclusion_all(
427 const EaxEaxCall
& eax_call
);
429 void eax_defer_send_occlusion_all(
430 const EaxEaxCall
& eax_call
);
432 void eax_defer_send_all(
433 const EaxEaxCall
& eax_call
);
436 static void eax_validate_source_direct(
439 static void eax_validate_source_direct_hf(
442 static void eax_validate_source_room(
445 static void eax_validate_source_room_hf(
448 static void eax_validate_source_obstruction(
451 static void eax_validate_source_obstruction_lf_ratio(
452 float obstruction_lf_ratio
);
454 static void eax_validate_source_occlusion(
457 static void eax_validate_source_occlusion_lf_ratio(
458 float occlusion_lf_ratio
);
460 static void eax_validate_source_occlusion_room_ratio(
461 float occlusion_room_ratio
);
463 static void eax_validate_source_occlusion_direct_ratio(
464 float occlusion_direct_ratio
);
466 static void eax_validate_source_exclusion(
469 static void eax_validate_source_exclusion_lf_ratio(
470 float exclusion_lf_ratio
);
472 static void eax_validate_source_outside_volume_hf(
473 long outside_volume_hf
);
475 static void eax_validate_source_doppler_factor(
476 float doppler_factor
);
478 static void eax_validate_source_rolloff_factor(
479 float rolloff_factor
);
481 static void eax_validate_source_room_rolloff_factor(
482 float room_rolloff_factor
);
484 static void eax_validate_source_air_absorption_factor(
485 float air_absorption_factor
);
487 static void eax_validate_source_flags(
491 static void eax_validate_source_macro_fx_factor(
492 float macro_fx_factor
);
494 static void eax_validate_source_2d_all(
495 const EAXSOURCE2DPROPERTIES
& all
,
498 static void eax_validate_source_obstruction_all(
499 const EAXOBSTRUCTIONPROPERTIES
& all
);
501 static void eax_validate_source_exclusion_all(
502 const EAXEXCLUSIONPROPERTIES
& all
);
504 static void eax_validate_source_occlusion_all(
505 const EAXOCCLUSIONPROPERTIES
& all
);
507 static void eax_validate_source_all(
508 const EAX20BUFFERPROPERTIES
& all
,
511 static void eax_validate_source_all(
512 const EAX30SOURCEPROPERTIES
& all
,
515 static void eax_validate_source_all(
516 const EAX50SOURCEPROPERTIES
& all
,
519 static void eax_validate_source_speaker_id(
522 static void eax_validate_source_speaker_level(
525 static void eax_validate_source_speaker_level_all(
526 const EAXSPEAKERLEVELPROPERTIES
& all
);
529 void eax_defer_source_direct(
532 void eax_defer_source_direct_hf(
535 void eax_defer_source_room(
538 void eax_defer_source_room_hf(
541 void eax_defer_source_obstruction(
544 void eax_defer_source_obstruction_lf_ratio(
545 float flObstructionLFRatio
);
547 void eax_defer_source_occlusion(
550 void eax_defer_source_occlusion_lf_ratio(
551 float flOcclusionLFRatio
);
553 void eax_defer_source_occlusion_room_ratio(
554 float flOcclusionRoomRatio
);
556 void eax_defer_source_occlusion_direct_ratio(
557 float flOcclusionDirectRatio
);
559 void eax_defer_source_exclusion(
562 void eax_defer_source_exclusion_lf_ratio(
563 float flExclusionLFRatio
);
565 void eax_defer_source_outside_volume_hf(
566 long lOutsideVolumeHF
);
568 void eax_defer_source_doppler_factor(
569 float flDopplerFactor
);
571 void eax_defer_source_rolloff_factor(
572 float flRolloffFactor
);
574 void eax_defer_source_room_rolloff_factor(
575 float flRoomRolloffFactor
);
577 void eax_defer_source_air_absorption_factor(
578 float flAirAbsorptionFactor
);
580 void eax_defer_source_flags(
581 unsigned long ulFlags
);
583 void eax_defer_source_macro_fx_factor(
584 float flMacroFXFactor
);
586 void eax_defer_source_2d_all(
587 const EAXSOURCE2DPROPERTIES
& all
);
589 void eax_defer_source_obstruction_all(
590 const EAXOBSTRUCTIONPROPERTIES
& all
);
592 void eax_defer_source_exclusion_all(
593 const EAXEXCLUSIONPROPERTIES
& all
);
595 void eax_defer_source_occlusion_all(
596 const EAXOCCLUSIONPROPERTIES
& all
);
598 void eax_defer_source_all(
599 const EAX20BUFFERPROPERTIES
& all
);
601 void eax_defer_source_all(
602 const EAX30SOURCEPROPERTIES
& all
);
604 void eax_defer_source_all(
605 const EAX50SOURCEPROPERTIES
& all
);
607 void eax_defer_source_speaker_level_all(
608 const EAXSPEAKERLEVELPROPERTIES
& all
);
611 void eax_defer_source_direct(
612 const EaxEaxCall
& eax_call
);
614 void eax_defer_source_direct_hf(
615 const EaxEaxCall
& eax_call
);
617 void eax_defer_source_room(
618 const EaxEaxCall
& eax_call
);
620 void eax_defer_source_room_hf(
621 const EaxEaxCall
& eax_call
);
623 void eax_defer_source_obstruction(
624 const EaxEaxCall
& eax_call
);
626 void eax_defer_source_obstruction_lf_ratio(
627 const EaxEaxCall
& eax_call
);
629 void eax_defer_source_occlusion(
630 const EaxEaxCall
& eax_call
);
632 void eax_defer_source_occlusion_lf_ratio(
633 const EaxEaxCall
& eax_call
);
635 void eax_defer_source_occlusion_room_ratio(
636 const EaxEaxCall
& eax_call
);
638 void eax_defer_source_occlusion_direct_ratio(
639 const EaxEaxCall
& eax_call
);
641 void eax_defer_source_exclusion(
642 const EaxEaxCall
& eax_call
);
644 void eax_defer_source_exclusion_lf_ratio(
645 const EaxEaxCall
& eax_call
);
647 void eax_defer_source_outside_volume_hf(
648 const EaxEaxCall
& eax_call
);
650 void eax_defer_source_doppler_factor(
651 const EaxEaxCall
& eax_call
);
653 void eax_defer_source_rolloff_factor(
654 const EaxEaxCall
& eax_call
);
656 void eax_defer_source_room_rolloff_factor(
657 const EaxEaxCall
& eax_call
);
659 void eax_defer_source_air_absorption_factor(
660 const EaxEaxCall
& eax_call
);
662 void eax_defer_source_flags(
663 const EaxEaxCall
& eax_call
);
665 void eax_defer_source_macro_fx_factor(
666 const EaxEaxCall
& eax_call
);
668 void eax_defer_source_2d_all(
669 const EaxEaxCall
& eax_call
);
671 void eax_defer_source_obstruction_all(
672 const EaxEaxCall
& eax_call
);
674 void eax_defer_source_exclusion_all(
675 const EaxEaxCall
& eax_call
);
677 void eax_defer_source_occlusion_all(
678 const EaxEaxCall
& eax_call
);
680 void eax_defer_source_all(
681 const EaxEaxCall
& eax_call
);
683 void eax_defer_source_speaker_level_all(
684 const EaxEaxCall
& eax_call
);
687 void eax_set_outside_volume_hf();
689 void eax_set_doppler_factor();
691 void eax_set_rolloff_factor();
693 void eax_set_room_rolloff_factor();
695 void eax_set_air_absorption_factor();
698 void eax_set_direct_hf_auto_flag();
700 void eax_set_room_auto_flag();
702 void eax_set_room_hf_auto_flag();
704 void eax_set_flags();
707 void eax_set_macro_fx_factor();
709 void eax_set_speaker_levels();
713 void eax1_set_reverb_mix(const EaxEaxCall
& eax_call
);
714 void eax1_set(const EaxEaxCall
& eax_call
);
716 void eax_apply_deferred();
719 const EaxEaxCall
& eax_call
);
722 static const GUID
& eax_get_send_fx_slot_guid(
724 EaxFxSlotIndexValue fx_slot_index
);
726 static void eax_copy_send(
727 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
728 EAXSOURCESENDPROPERTIES
& dst_send
);
730 static void eax_copy_send(
731 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
732 EAXSOURCEALLSENDPROPERTIES
& dst_send
);
734 static void eax_copy_send(
735 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
736 EAXSOURCEOCCLUSIONSENDPROPERTIES
& dst_send
);
738 static void eax_copy_send(
739 const EAXSOURCEALLSENDPROPERTIES
& src_send
,
740 EAXSOURCEEXCLUSIONSENDPROPERTIES
& dst_send
);
746 void eax_api_get_send_properties(
747 const EaxEaxCall
& eax_call
) const
749 const auto eax_version
= eax_call
.get_version();
750 const auto dst_sends
= eax_call
.get_values
<TException
, TSrcSend
>();
751 const auto send_count
= dst_sends
.size();
753 for (auto fx_slot_index
= EaxFxSlotIndexValue
{}; fx_slot_index
< send_count
; ++fx_slot_index
)
755 auto& dst_send
= dst_sends
[fx_slot_index
];
756 const auto& src_send
= eax_
.sends
[fx_slot_index
];
758 eax_copy_send(src_send
, dst_send
);
760 dst_send
.guidReceivingFXSlotID
= eax_get_send_fx_slot_guid(eax_version
, fx_slot_index
);
765 void eax1_get(const EaxEaxCall
& eax_call
);
767 void eax_api_get_source_all_v2(
768 const EaxEaxCall
& eax_call
);
770 void eax_api_get_source_all_v3(
771 const EaxEaxCall
& eax_call
);
773 void eax_api_get_source_all_v5(
774 const EaxEaxCall
& eax_call
);
776 void eax_api_get_source_all(
777 const EaxEaxCall
& eax_call
);
779 void eax_api_get_source_all_obstruction(
780 const EaxEaxCall
& eax_call
);
782 void eax_api_get_source_all_occlusion(
783 const EaxEaxCall
& eax_call
);
785 void eax_api_get_source_all_exclusion(
786 const EaxEaxCall
& eax_call
);
788 void eax_api_get_source_active_fx_slot_id(
789 const EaxEaxCall
& eax_call
);
791 void eax_api_get_source_all_2d(
792 const EaxEaxCall
& eax_call
);
794 void eax_api_get_source_speaker_level_all(
795 const EaxEaxCall
& eax_call
);
798 const EaxEaxCall
& eax_call
);
801 // `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
802 void eax_set_al_source_send(ALeffectslot
*slot
, size_t sendidx
,
803 const EaxAlLowPassParam
&filter
);
807 void UpdateAllSourceProps(ALCcontext
*context
);