14 #include "al/listener.h"
16 #include "alnumeric.h"
18 #include "core/context.h"
19 #include "intrusive_ptr.h"
23 #include "al/eax_eax_call.h"
24 #include "al/eax_fx_slot_index.h"
25 #include "al/eax_fx_slots.h"
26 #include "al/eax_utils.h"
29 using EaxContextSharedDirtyFlagsValue
= std::uint_least8_t;
31 struct EaxContextSharedDirtyFlags
33 using EaxIsBitFieldStruct
= bool;
35 EaxContextSharedDirtyFlagsValue primary_fx_slot_id
: 1;
36 }; // EaxContextSharedDirtyFlags
39 using ContextDirtyFlagsValue
= std::uint_least8_t;
41 struct ContextDirtyFlags
43 using EaxIsBitFieldStruct
= bool;
45 ContextDirtyFlagsValue guidPrimaryFXSlotID
: 1;
46 ContextDirtyFlagsValue flDistanceFactor
: 1;
47 ContextDirtyFlagsValue flAirAbsorptionHF
: 1;
48 ContextDirtyFlagsValue flHFReference
: 1;
49 ContextDirtyFlagsValue flMacroFXFactor
: 1;
50 }; // ContextDirtyFlags
53 struct EaxAlIsExtensionPresentResult
57 }; // EaxAlIsExtensionPresentResult
64 using uint
= unsigned int;
67 struct SourceSubList
{
68 uint64_t FreeMask
{~0_u64
};
69 ALsource
*Sources
{nullptr}; /* 64 */
71 SourceSubList() noexcept
= default;
72 SourceSubList(const SourceSubList
&) = delete;
73 SourceSubList(SourceSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Sources
{rhs
.Sources
}
74 { rhs
.FreeMask
= ~0_u64
; rhs
.Sources
= nullptr; }
77 SourceSubList
& operator=(const SourceSubList
&) = delete;
78 SourceSubList
& operator=(SourceSubList
&& rhs
) noexcept
79 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Sources
, rhs
.Sources
); return *this; }
82 struct EffectSlotSubList
{
83 uint64_t FreeMask
{~0_u64
};
84 ALeffectslot
*EffectSlots
{nullptr}; /* 64 */
86 EffectSlotSubList() noexcept
= default;
87 EffectSlotSubList(const EffectSlotSubList
&) = delete;
88 EffectSlotSubList(EffectSlotSubList
&& rhs
) noexcept
89 : FreeMask
{rhs
.FreeMask
}, EffectSlots
{rhs
.EffectSlots
}
90 { rhs
.FreeMask
= ~0_u64
; rhs
.EffectSlots
= nullptr; }
93 EffectSlotSubList
& operator=(const EffectSlotSubList
&) = delete;
94 EffectSlotSubList
& operator=(EffectSlotSubList
&& rhs
) noexcept
95 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(EffectSlots
, rhs
.EffectSlots
); return *this; }
98 struct ALCcontext
: public al::intrusive_ref
<ALCcontext
>, ContextBase
{
99 const al::intrusive_ptr
<ALCdevice
> mALDevice
;
101 /* Wet buffers used by effect slots. */
102 al::vector
<WetBufferPtr
> mWetBuffers
;
105 bool mPropsDirty
{true};
106 bool mDeferUpdates
{false};
108 std::mutex mPropLock
;
110 std::atomic
<ALenum
> mLastError
{AL_NO_ERROR
};
112 DistanceModel mDistanceModel
{DistanceModel::Default
};
113 bool mSourceDistanceModel
{false};
115 float mDopplerFactor
{1.0f
};
116 float mDopplerVelocity
{1.0f
};
117 float mSpeedOfSound
{SpeedOfSoundMetersPerSec
};
118 float mAirAbsorptionGainHF
{AirAbsorbGainHF
};
120 std::mutex mEventCbLock
;
121 ALEVENTPROCSOFT mEventCb
{};
122 void *mEventParam
{nullptr};
124 ALlistener mListener
{};
126 al::vector
<SourceSubList
> mSourceList
;
127 ALuint mNumSources
{0};
128 std::mutex mSourceLock
;
130 al::vector
<EffectSlotSubList
> mEffectSlotList
;
131 ALuint mNumEffectSlots
{0u};
132 std::mutex mEffectSlotLock
;
134 /* Default effect slot */
135 std::unique_ptr
<ALeffectslot
> mDefaultSlot
;
137 const char *mExtensionList
{nullptr};
140 ALCcontext(al::intrusive_ptr
<ALCdevice
> device
);
141 ALCcontext(const ALCcontext
&) = delete;
142 ALCcontext
& operator=(const ALCcontext
&) = delete;
147 * Removes the context from its device and removes it from being current on
148 * the running thread or globally. Returns true if other contexts still
149 * exist on the device.
154 * Defers/suspends updates for the given context's listener and sources.
155 * This does *NOT* stop mixing, but rather prevents certain property
156 * changes from taking effect. mPropLock must be held when called.
158 void deferUpdates() noexcept
{ mDeferUpdates
= true; }
161 * Resumes update processing after being deferred. mPropLock must be held
164 void processUpdates()
166 if(std::exchange(mDeferUpdates
, false))
171 * Applies all pending updates for the context, listener, effect slots, and
174 void applyAllUpdates();
176 #ifdef __USE_MINGW_ANSI_STDIO
177 [[gnu::format(gnu_printf
, 3, 4)]]
179 [[gnu::format(printf
, 3, 4)]]
181 void setError(ALenum errorCode
, const char *msg
, ...);
183 /* Process-wide current context */
184 static std::atomic
<ALCcontext
*> sGlobalContext
;
187 /* Thread-local current context. */
188 static thread_local ALCcontext
*sLocalContext
;
190 /* Thread-local context handling. This handles attempting to release the
191 * context which may have been left current when the thread is destroyed.
196 void set(ALCcontext
*ctx
) const noexcept
{ sLocalContext
= ctx
; }
198 static thread_local ThreadCtx sThreadContext
;
201 /* HACK: MinGW generates bad code when accessing an extern thread_local
202 * object. Add a wrapper function for it that only accesses it where it's
206 static ALCcontext
*getThreadContext() noexcept
;
207 static void setThreadContext(ALCcontext
*context
) noexcept
;
209 static ALCcontext
*getThreadContext() noexcept
{ return sLocalContext
; }
210 static void setThreadContext(ALCcontext
*context
) noexcept
{ sThreadContext
.set(context
); }
213 /* Default effect that applies to sources that don't have an effect on send 0. */
214 static ALeffect sDefaultEffect
;
216 DEF_NEWDEL(ALCcontext
)
220 bool has_eax() const noexcept
{ return eax_is_initialized_
; }
222 bool eax_is_capable() const noexcept
;
225 void eax_uninitialize() noexcept
;
229 const GUID
* property_set_id
,
231 ALuint property_source_id
,
232 ALvoid
* property_value
,
233 ALuint property_value_size
);
236 const GUID
* property_set_id
,
238 ALuint property_source_id
,
239 ALvoid
* property_value
,
240 ALuint property_value_size
);
243 void eax_update_filters();
245 void eax_commit_and_update_sources();
248 void eax_set_last_error() noexcept
;
251 EaxFxSlotIndex
eax_get_previous_primary_fx_slot_index() const noexcept
252 { return eax_previous_primary_fx_slot_index_
; }
253 EaxFxSlotIndex
eax_get_primary_fx_slot_index() const noexcept
254 { return eax_primary_fx_slot_index_
; }
256 const ALeffectslot
& eax_get_fx_slot(EaxFxSlotIndexValue fx_slot_index
) const
257 { return eax_fx_slots_
.get(fx_slot_index
); }
258 ALeffectslot
& eax_get_fx_slot(EaxFxSlotIndexValue fx_slot_index
)
259 { return eax_fx_slots_
.get(fx_slot_index
); }
263 using SourceList
= al::vector
<SourceSubList
>;
266 struct SourceListIteratorBeginTag
{};
267 struct SourceListIteratorEndTag
{};
269 class SourceListIterator
274 SourceListIteratorBeginTag
) noexcept
;
278 SourceListIteratorEndTag
) noexcept
;
281 const SourceListIterator
& rhs
);
283 SourceListIterator
& operator=(
284 const SourceListIterator
& rhs
) = delete;
286 SourceListIterator
& operator++();
288 ALsource
& operator*() noexcept
;
291 const SourceListIterator
& rhs
) const noexcept
;
294 const SourceListIterator
& rhs
) const noexcept
;
298 SourceList::iterator sub_list_iterator_
;
299 SourceList::iterator sub_list_end_iterator_
;
300 std::uint64_t sub_list_item_index_
;
301 }; // SourceListIterator
303 class SourceListEnumerator
306 explicit SourceListEnumerator(
307 SourceList
& sources
) noexcept
;
309 SourceListEnumerator(
310 const SourceListEnumerator
& rhs
) = delete;
312 SourceListEnumerator
& operator=(
313 const SourceListEnumerator
& rhs
) = delete;
315 SourceListIterator
begin() noexcept
;
317 SourceListIterator
end() noexcept
;
321 SourceList
& sources_
;
322 }; // SourceListEnumerator
327 EAX50CONTEXTPROPERTIES context
{};
331 bool eax_is_initialized_
{};
332 bool eax_is_tried_
{};
333 bool eax_are_legacy_fx_slots_unlocked_
{};
335 long eax_last_error_
{};
336 unsigned long eax_speaker_config_
{};
338 EaxFxSlotIndex eax_previous_primary_fx_slot_index_
{};
339 EaxFxSlotIndex eax_primary_fx_slot_index_
{};
340 EaxFxSlots eax_fx_slots_
{};
342 EaxContextSharedDirtyFlags eax_context_shared_dirty_flags_
{};
346 EAXSESSIONPROPERTIES eax_session_
{};
348 ContextDirtyFlags eax_context_dirty_flags_
{};
350 std::string eax_extension_list_
{};
354 static void eax_fail(
355 const char* message
);
358 void eax_initialize_extensions();
360 void eax_initialize();
363 bool eax_has_no_default_effect_slot() const noexcept
;
365 void eax_ensure_no_default_effect_slot() const;
367 bool eax_has_enough_aux_sends() const noexcept
;
369 void eax_ensure_enough_aux_sends() const;
371 void eax_ensure_compatibility();
374 unsigned long eax_detect_speaker_configuration() const;
375 void eax_update_speaker_configuration();
378 void eax_set_last_error_defaults() noexcept
;
380 void eax_set_session_defaults() noexcept
;
382 void eax_set_context_defaults() noexcept
;
384 void eax_set_defaults() noexcept
;
386 void eax_initialize_sources();
389 void eax_unlock_legacy_fx_slots(const EaxEaxCall
& eax_call
) noexcept
;
392 void eax_dispatch_fx_slot(
393 const EaxEaxCall
& eax_call
);
395 void eax_dispatch_source(
396 const EaxEaxCall
& eax_call
);
399 void eax_get_primary_fx_slot_id(
400 const EaxEaxCall
& eax_call
);
402 void eax_get_distance_factor(
403 const EaxEaxCall
& eax_call
);
405 void eax_get_air_absorption_hf(
406 const EaxEaxCall
& eax_call
);
408 void eax_get_hf_reference(
409 const EaxEaxCall
& eax_call
);
411 void eax_get_last_error(
412 const EaxEaxCall
& eax_call
);
414 void eax_get_speaker_config(
415 const EaxEaxCall
& eax_call
);
417 void eax_get_session(
418 const EaxEaxCall
& eax_call
);
420 void eax_get_macro_fx_factor(
421 const EaxEaxCall
& eax_call
);
423 void eax_get_context_all(
424 const EaxEaxCall
& eax_call
);
427 const EaxEaxCall
& eax_call
);
430 void eax_set_primary_fx_slot_id();
432 void eax_set_distance_factor();
434 void eax_set_air_absorbtion_hf();
436 void eax_set_hf_reference();
438 void eax_set_macro_fx_factor();
440 void eax_set_context();
442 void eax_initialize_fx_slots();
445 void eax_update_sources();
448 void eax_validate_primary_fx_slot_id(
449 const GUID
& primary_fx_slot_id
);
451 void eax_validate_distance_factor(
452 float distance_factor
);
454 void eax_validate_air_absorption_hf(
455 float air_absorption_hf
);
457 void eax_validate_hf_reference(
460 void eax_validate_speaker_config(
461 unsigned long speaker_config
);
463 void eax_validate_session_eax_version(
464 unsigned long eax_version
);
466 void eax_validate_session_max_active_sends(
467 unsigned long max_active_sends
);
469 void eax_validate_session(
470 const EAXSESSIONPROPERTIES
& eax_session
);
472 void eax_validate_macro_fx_factor(
473 float macro_fx_factor
);
475 void eax_validate_context_all(
476 const EAX40CONTEXTPROPERTIES
& context_all
);
478 void eax_validate_context_all(
479 const EAX50CONTEXTPROPERTIES
& context_all
);
482 void eax_defer_primary_fx_slot_id(
483 const GUID
& primary_fx_slot_id
);
485 void eax_defer_distance_factor(
486 float distance_factor
);
488 void eax_defer_air_absorption_hf(
489 float air_absorption_hf
);
491 void eax_defer_hf_reference(
494 void eax_defer_macro_fx_factor(
495 float macro_fx_factor
);
497 void eax_defer_context_all(
498 const EAX40CONTEXTPROPERTIES
& context_all
);
500 void eax_defer_context_all(
501 const EAX50CONTEXTPROPERTIES
& context_all
);
504 void eax_defer_context_all(
505 const EaxEaxCall
& eax_call
);
507 void eax_defer_primary_fx_slot_id(
508 const EaxEaxCall
& eax_call
);
510 void eax_defer_distance_factor(
511 const EaxEaxCall
& eax_call
);
513 void eax_defer_air_absorption_hf(
514 const EaxEaxCall
& eax_call
);
516 void eax_defer_hf_reference(
517 const EaxEaxCall
& eax_call
);
519 void eax_set_session(
520 const EaxEaxCall
& eax_call
);
522 void eax_defer_macro_fx_factor(
523 const EaxEaxCall
& eax_call
);
526 const EaxEaxCall
& eax_call
);
528 void eax_apply_deferred();
532 #define SETERR_RETURN(ctx, err, retval, ...) do { \
533 (ctx)->setError((err), __VA_ARGS__); \
538 using ContextRef
= al::intrusive_ptr
<ALCcontext
>;
540 ContextRef
GetContextRef(void);
542 void UpdateContextProps(ALCcontext
*context
);
545 extern bool TrapALError
;
549 ALenum AL_APIENTRY
EAXSet(
550 const GUID
* property_set_id
,
552 ALuint property_source_id
,
553 ALvoid
* property_value
,
554 ALuint property_value_size
) noexcept
;
556 ALenum AL_APIENTRY
EAXGet(
557 const GUID
* property_set_id
,
559 ALuint property_source_id
,
560 ALvoid
* property_value
,
561 ALuint property_value_size
) noexcept
;
564 #endif /* ALC_CONTEXT_H */