Separate ALCdevice from the implementation
[openal-soft.git] / al / auxeffectslot.h
blob40c352956d1ca0201e6252d6bd1ff99dc7851e1d
1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
4 #include "config.h"
6 #include <array>
7 #include <atomic>
8 #include <cstdint>
9 #include <string_view>
10 #include <utility>
12 #include "AL/al.h"
13 #include "AL/alc.h"
15 #include "almalloc.h"
16 #include "alnumeric.h"
17 #include "core/effects/base.h"
18 #include "core/effectslot.h"
19 #include "intrusive_ptr.h"
21 #if ALSOFT_EAX
22 #include <memory>
23 #include "eax/api.h"
24 #include "eax/call.h"
25 #include "eax/effect.h"
26 #include "eax/exception.h"
27 #include "eax/fx_slot_index.h"
28 #include "eax/utils.h"
29 #endif // ALSOFT_EAX
31 struct ALbuffer;
33 #if ALSOFT_EAX
34 class EaxFxSlotException : public EaxException {
35 public:
36 explicit EaxFxSlotException(const char* message)
37 : EaxException{"EAX_FX_SLOT", message}
40 #endif // ALSOFT_EAX
42 enum class SlotState : bool {
43 Initial, Playing,
46 struct ALeffectslot {
47 ALuint EffectId{};
48 float Gain{1.0f};
49 bool AuxSendAuto{true};
50 ALeffectslot *Target{nullptr};
51 ALbuffer *Buffer{nullptr};
53 struct EffectData {
54 EffectSlotType Type{EffectSlotType::None};
55 EffectProps Props{};
57 al::intrusive_ptr<EffectState> State;
59 EffectData Effect;
61 bool mPropsDirty{true};
63 SlotState mState{SlotState::Initial};
65 std::atomic<ALuint> ref{0u};
67 EffectSlot *mSlot{nullptr};
69 /* Self ID */
70 ALuint id{};
72 ALeffectslot(ALCcontext *context);
73 ALeffectslot(const ALeffectslot&) = delete;
74 ALeffectslot& operator=(const ALeffectslot&) = delete;
75 ~ALeffectslot();
77 ALenum initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps,
78 ALCcontext *context);
79 void updateProps(ALCcontext *context) const;
81 static void SetName(ALCcontext *context, ALuint id, std::string_view name);
84 #if ALSOFT_EAX
85 public:
86 void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
88 [[nodiscard]] auto eax_get_index() const noexcept -> EaxFxSlotIndexValue { return eax_fx_slot_index_; }
89 [[nodiscard]] auto eax_get_eax_fx_slot() const noexcept -> const EAX50FXSLOTPROPERTIES&
90 { return eax_; }
92 // Returns `true` if all sources should be updated, or `false` otherwise.
93 [[nodiscard]] auto eax_dispatch(const EaxCall& call) -> bool
94 { return call.is_get() ? eax_get(call) : eax_set(call); }
96 void eax_commit();
98 private:
99 static constexpr auto eax_load_effect_dirty_bit = EaxDirtyFlags{1} << 0;
100 static constexpr auto eax_volume_dirty_bit = EaxDirtyFlags{1} << 1;
101 static constexpr auto eax_lock_dirty_bit = EaxDirtyFlags{1} << 2;
102 static constexpr auto eax_flags_dirty_bit = EaxDirtyFlags{1} << 3;
103 static constexpr auto eax_occlusion_dirty_bit = EaxDirtyFlags{1} << 4;
104 static constexpr auto eax_occlusion_lf_ratio_dirty_bit = EaxDirtyFlags{1} << 5;
106 using Exception = EaxFxSlotException;
108 using Eax4Props = EAX40FXSLOTPROPERTIES;
110 struct Eax4State {
111 Eax4Props i; // Immediate.
114 using Eax5Props = EAX50FXSLOTPROPERTIES;
116 struct Eax5State {
117 Eax5Props i; // Immediate.
120 struct EaxRangeValidator {
121 template<typename TValue>
122 void operator()(
123 const char* name,
124 const TValue& value,
125 const TValue& min_value,
126 const TValue& max_value) const
128 eax_validate_range<Exception>(name, value, min_value, max_value);
132 struct Eax4GuidLoadEffectValidator {
133 void operator()(const GUID& guidLoadEffect) const
135 if (guidLoadEffect != EAX_NULL_GUID &&
136 guidLoadEffect != EAX_REVERB_EFFECT &&
137 guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT &&
138 guidLoadEffect != EAX_AUTOWAH_EFFECT &&
139 guidLoadEffect != EAX_CHORUS_EFFECT &&
140 guidLoadEffect != EAX_DISTORTION_EFFECT &&
141 guidLoadEffect != EAX_ECHO_EFFECT &&
142 guidLoadEffect != EAX_EQUALIZER_EFFECT &&
143 guidLoadEffect != EAX_FLANGER_EFFECT &&
144 guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT &&
145 guidLoadEffect != EAX_VOCALMORPHER_EFFECT &&
146 guidLoadEffect != EAX_PITCHSHIFTER_EFFECT &&
147 guidLoadEffect != EAX_RINGMODULATOR_EFFECT)
149 eax_fail_unknown_effect_id();
154 struct Eax4VolumeValidator {
155 void operator()(long lVolume) const
157 EaxRangeValidator{}(
158 "Volume",
159 lVolume,
160 EAXFXSLOT_MINVOLUME,
161 EAXFXSLOT_MAXVOLUME);
165 struct Eax4LockValidator {
166 void operator()(long lLock) const
168 EaxRangeValidator{}(
169 "Lock",
170 lLock,
171 EAXFXSLOT_MINLOCK,
172 EAXFXSLOT_MAXLOCK);
176 struct Eax4FlagsValidator {
177 void operator()(unsigned long ulFlags) const
179 EaxRangeValidator{}(
180 "Flags",
181 ulFlags,
182 0UL,
183 ~EAX40FXSLOTFLAGS_RESERVED);
187 struct Eax4AllValidator {
188 void operator()(const EAX40FXSLOTPROPERTIES& all) const
190 Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
191 Eax4VolumeValidator{}(all.lVolume);
192 Eax4LockValidator{}(all.lLock);
193 Eax4FlagsValidator{}(all.ulFlags);
197 struct Eax5FlagsValidator {
198 void operator()(unsigned long ulFlags) const
200 EaxRangeValidator{}(
201 "Flags",
202 ulFlags,
203 0UL,
204 ~EAX50FXSLOTFLAGS_RESERVED);
208 struct Eax5OcclusionValidator {
209 void operator()(long lOcclusion) const
211 EaxRangeValidator{}(
212 "Occlusion",
213 lOcclusion,
214 EAXFXSLOT_MINOCCLUSION,
215 EAXFXSLOT_MAXOCCLUSION);
219 struct Eax5OcclusionLfRatioValidator {
220 void operator()(float flOcclusionLFRatio) const
222 EaxRangeValidator{}(
223 "Occlusion LF Ratio",
224 flOcclusionLFRatio,
225 EAXFXSLOT_MINOCCLUSIONLFRATIO,
226 EAXFXSLOT_MAXOCCLUSIONLFRATIO);
230 struct Eax5AllValidator {
231 void operator()(const EAX50FXSLOTPROPERTIES& all) const
233 Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
234 Eax4VolumeValidator{}(all.lVolume);
235 Eax4LockValidator{}(all.lLock);
236 Eax5FlagsValidator{}(all.ulFlags);
237 Eax5OcclusionValidator{}(all.lOcclusion);
238 Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
242 ALCcontext* eax_al_context_{};
243 EaxFxSlotIndexValue eax_fx_slot_index_{};
244 int eax_version_{}; // Current EAX version.
245 EaxDirtyFlags eax_df_{}; // Dirty flags for the current EAX version.
246 EaxEffectUPtr eax_effect_{};
247 Eax5State eax123_{}; // EAX1/EAX2/EAX3 state.
248 Eax4State eax4_{}; // EAX4 state.
249 Eax5State eax5_{}; // EAX5 state.
250 Eax5Props eax_{}; // Current EAX state.
252 [[noreturn]] static void eax_fail(const char* message);
253 [[noreturn]] static void eax_fail_unknown_effect_id();
254 [[noreturn]] static void eax_fail_unknown_property_id();
255 [[noreturn]] static void eax_fail_unknown_version();
257 // Gets a new value from EAX call,
258 // validates it,
259 // sets a dirty flag only if the new value differs form the old one,
260 // and assigns the new value.
261 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
262 static void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags)
264 const auto& src = call.get_value<Exception, const TProperties>();
265 TValidator{}(src);
266 dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
267 dst = src;
270 // Gets a new value from EAX call,
271 // validates it,
272 // sets a dirty flag without comparing the values,
273 // and assigns the new value.
274 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
275 static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
276 EaxDirtyFlags& dirty_flags)
278 const auto& src = call.get_value<Exception, const TProperties>();
279 TValidator{}(src);
280 dirty_flags |= TDirtyBit;
281 dst = src;
284 [[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
285 { return eax_fx_slot_index_ < 2; }
287 void eax4_fx_slot_ensure_unlocked() const;
289 [[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
290 [[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
291 [[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
293 void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
294 void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
295 void eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept;
296 void eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept;
297 void eax_fx_slot_set_current_defaults();
298 void eax_fx_slot_set_defaults();
300 static void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props);
301 static void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props);
302 void eax_fx_slot_get(const EaxCall& call) const;
303 // Returns `true` if all sources should be updated, or `false` otherwise.
304 bool eax_get(const EaxCall& call);
306 void eax_fx_slot_load_effect(int version, ALenum altype);
307 void eax_fx_slot_set_volume();
308 void eax_fx_slot_set_environment_flag();
309 void eax_fx_slot_set_flags();
311 void eax4_fx_slot_set_all(const EaxCall& call);
312 void eax5_fx_slot_set_all(const EaxCall& call);
314 [[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
316 // Returns `true` if all sources should be updated, or `false` otherwise.
317 bool eax4_fx_slot_set(const EaxCall& call);
318 // Returns `true` if all sources should be updated, or `false` otherwise.
319 bool eax5_fx_slot_set(const EaxCall& call);
320 // Returns `true` if all sources should be updated, or `false` otherwise.
321 bool eax_fx_slot_set(const EaxCall& call);
322 // Returns `true` if all sources should be updated, or `false` otherwise.
323 bool eax_set(const EaxCall& call);
325 template<
326 EaxDirtyFlags TDirtyBit,
327 typename TMemberResult,
328 typename TProps,
329 typename TState>
330 void eax_fx_slot_commit_property(TState& state, EaxDirtyFlags& dst_df,
331 TMemberResult TProps::*member) noexcept
333 auto& src_i = state.i;
334 auto& dst_i = eax_;
336 if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
338 dst_df |= TDirtyBit;
339 dst_i.*member = src_i.*member;
343 void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
344 void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
346 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
347 void eax_set_efx_slot_effect(EaxEffect &effect);
349 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
350 void eax_set_efx_slot_send_auto(bool is_send_auto);
352 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
353 void eax_set_efx_slot_gain(ALfloat gain);
355 public:
356 class EaxDeleter {
357 public:
358 void operator()(ALeffectslot *effect_slot);
360 #endif // ALSOFT_EAX
363 void UpdateAllEffectSlotProps(ALCcontext *context);
365 #if ALSOFT_EAX
366 using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
368 EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
369 void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
370 #endif // ALSOFT_EAX
372 struct EffectSlotSubList {
373 uint64_t FreeMask{~0_u64};
374 gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
376 EffectSlotSubList() noexcept = default;
377 EffectSlotSubList(const EffectSlotSubList&) = delete;
378 EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
379 : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
380 { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
381 ~EffectSlotSubList();
383 EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
384 EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
385 { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
388 #endif