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
); }
261 void eax_commit_fx_slots()
262 { eax_fx_slots_
.commit(); }
267 EAX50CONTEXTPROPERTIES context
{};
271 bool eax_is_initialized_
{};
272 bool eax_is_tried_
{};
273 bool eax_are_legacy_fx_slots_unlocked_
{};
275 long eax_last_error_
{};
276 unsigned long eax_speaker_config_
{};
278 EaxFxSlotIndex eax_previous_primary_fx_slot_index_
{};
279 EaxFxSlotIndex eax_primary_fx_slot_index_
{};
280 EaxFxSlots eax_fx_slots_
{};
282 EaxContextSharedDirtyFlags eax_context_shared_dirty_flags_
{};
286 EAXSESSIONPROPERTIES eax_session_
{};
288 ContextDirtyFlags eax_context_dirty_flags_
{};
290 std::string eax_extension_list_
{};
294 static void eax_fail(
295 const char* message
);
298 void eax_initialize_extensions();
300 void eax_initialize();
303 bool eax_has_no_default_effect_slot() const noexcept
;
305 void eax_ensure_no_default_effect_slot() const;
307 bool eax_has_enough_aux_sends() const noexcept
;
309 void eax_ensure_enough_aux_sends() const;
311 void eax_ensure_compatibility();
314 unsigned long eax_detect_speaker_configuration() const;
315 void eax_update_speaker_configuration();
318 void eax_set_last_error_defaults() noexcept
;
320 void eax_set_session_defaults() noexcept
;
322 void eax_set_context_defaults() noexcept
;
324 void eax_set_defaults() noexcept
;
326 void eax_initialize_sources();
329 void eax_unlock_legacy_fx_slots(const EaxEaxCall
& eax_call
) noexcept
;
332 void eax_dispatch_fx_slot(
333 const EaxEaxCall
& eax_call
);
335 void eax_dispatch_source(
336 const EaxEaxCall
& eax_call
);
339 void eax_get_primary_fx_slot_id(
340 const EaxEaxCall
& eax_call
);
342 void eax_get_distance_factor(
343 const EaxEaxCall
& eax_call
);
345 void eax_get_air_absorption_hf(
346 const EaxEaxCall
& eax_call
);
348 void eax_get_hf_reference(
349 const EaxEaxCall
& eax_call
);
351 void eax_get_last_error(
352 const EaxEaxCall
& eax_call
);
354 void eax_get_speaker_config(
355 const EaxEaxCall
& eax_call
);
357 void eax_get_session(
358 const EaxEaxCall
& eax_call
);
360 void eax_get_macro_fx_factor(
361 const EaxEaxCall
& eax_call
);
363 void eax_get_context_all(
364 const EaxEaxCall
& eax_call
);
367 const EaxEaxCall
& eax_call
);
370 void eax_set_primary_fx_slot_id();
372 void eax_set_distance_factor();
374 void eax_set_air_absorbtion_hf();
376 void eax_set_hf_reference();
378 void eax_set_macro_fx_factor();
380 void eax_set_context();
382 void eax_initialize_fx_slots();
385 void eax_update_sources();
388 void eax_validate_primary_fx_slot_id(
389 const GUID
& primary_fx_slot_id
);
391 void eax_validate_distance_factor(
392 float distance_factor
);
394 void eax_validate_air_absorption_hf(
395 float air_absorption_hf
);
397 void eax_validate_hf_reference(
400 void eax_validate_speaker_config(
401 unsigned long speaker_config
);
403 void eax_validate_session_eax_version(
404 unsigned long eax_version
);
406 void eax_validate_session_max_active_sends(
407 unsigned long max_active_sends
);
409 void eax_validate_session(
410 const EAXSESSIONPROPERTIES
& eax_session
);
412 void eax_validate_macro_fx_factor(
413 float macro_fx_factor
);
415 void eax_validate_context_all(
416 const EAX40CONTEXTPROPERTIES
& context_all
);
418 void eax_validate_context_all(
419 const EAX50CONTEXTPROPERTIES
& context_all
);
422 void eax_defer_primary_fx_slot_id(
423 const GUID
& primary_fx_slot_id
);
425 void eax_defer_distance_factor(
426 float distance_factor
);
428 void eax_defer_air_absorption_hf(
429 float air_absorption_hf
);
431 void eax_defer_hf_reference(
434 void eax_defer_macro_fx_factor(
435 float macro_fx_factor
);
437 void eax_defer_context_all(
438 const EAX40CONTEXTPROPERTIES
& context_all
);
440 void eax_defer_context_all(
441 const EAX50CONTEXTPROPERTIES
& context_all
);
444 void eax_defer_context_all(
445 const EaxEaxCall
& eax_call
);
447 void eax_defer_primary_fx_slot_id(
448 const EaxEaxCall
& eax_call
);
450 void eax_defer_distance_factor(
451 const EaxEaxCall
& eax_call
);
453 void eax_defer_air_absorption_hf(
454 const EaxEaxCall
& eax_call
);
456 void eax_defer_hf_reference(
457 const EaxEaxCall
& eax_call
);
459 void eax_set_session(
460 const EaxEaxCall
& eax_call
);
462 void eax_defer_macro_fx_factor(
463 const EaxEaxCall
& eax_call
);
466 const EaxEaxCall
& eax_call
);
468 void eax_apply_deferred();
472 #define SETERR_RETURN(ctx, err, retval, ...) do { \
473 (ctx)->setError((err), __VA_ARGS__); \
478 using ContextRef
= al::intrusive_ptr
<ALCcontext
>;
480 ContextRef
GetContextRef(void);
482 void UpdateContextProps(ALCcontext
*context
);
485 extern bool TrapALError
;
489 ALenum AL_APIENTRY
EAXSet(
490 const GUID
* property_set_id
,
492 ALuint property_source_id
,
493 ALvoid
* property_value
,
494 ALuint property_value_size
) noexcept
;
496 ALenum AL_APIENTRY
EAXGet(
497 const GUID
* property_set_id
,
499 ALuint property_source_id
,
500 ALvoid
* property_value
,
501 ALuint property_value_size
) noexcept
;
504 #endif /* ALC_CONTEXT_H */