Use unsigned indices for the iface maps
[openal-soft.git] / al / auxeffectslot.h
blob4c7d573394ce8375f5004fc4367630a77f261aad
1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
4 #include <array>
5 #include <atomic>
6 #include <cstdint>
7 #include <string_view>
8 #include <utility>
10 #include "AL/al.h"
11 #include "AL/alc.h"
13 #include "almalloc.h"
14 #include "alnumeric.h"
15 #include "core/effects/base.h"
16 #include "core/effectslot.h"
17 #include "intrusive_ptr.h"
19 #ifdef ALSOFT_EAX
20 #include <memory>
21 #include "eax/api.h"
22 #include "eax/call.h"
23 #include "eax/effect.h"
24 #include "eax/exception.h"
25 #include "eax/fx_slot_index.h"
26 #include "eax/utils.h"
27 #endif // ALSOFT_EAX
29 struct ALbuffer;
31 #ifdef ALSOFT_EAX
32 class EaxFxSlotException : public EaxException {
33 public:
34 explicit EaxFxSlotException(const char* message)
35 : EaxException{"EAX_FX_SLOT", message}
38 #endif // ALSOFT_EAX
40 enum class SlotState : ALenum {
41 Initial = AL_INITIAL,
42 Playing = AL_PLAYING,
43 Stopped = AL_STOPPED,
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 #ifdef 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 Eax5OcclusionValidator {
198 void operator()(long lOcclusion) const
200 EaxRangeValidator{}(
201 "Occlusion",
202 lOcclusion,
203 EAXFXSLOT_MINOCCLUSION,
204 EAXFXSLOT_MAXOCCLUSION);
208 struct Eax5OcclusionLfRatioValidator {
209 void operator()(float flOcclusionLFRatio) const
211 EaxRangeValidator{}(
212 "Occlusion LF Ratio",
213 flOcclusionLFRatio,
214 EAXFXSLOT_MINOCCLUSIONLFRATIO,
215 EAXFXSLOT_MAXOCCLUSIONLFRATIO);
219 struct Eax5FlagsValidator {
220 void operator()(unsigned long ulFlags) const
222 EaxRangeValidator{}(
223 "Flags",
224 ulFlags,
225 0UL,
226 ~EAX50FXSLOTFLAGS_RESERVED);
230 struct Eax5AllValidator {
231 void operator()(const EAX50FXSLOTPROPERTIES& all) const
233 Eax4AllValidator{}(static_cast<const EAX40FXSLOTPROPERTIES&>(all));
234 Eax5OcclusionValidator{}(all.lOcclusion);
235 Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
239 ALCcontext* eax_al_context_{};
240 EaxFxSlotIndexValue eax_fx_slot_index_{};
241 int eax_version_{}; // Current EAX version.
242 EaxDirtyFlags eax_df_{}; // Dirty flags for the current EAX version.
243 EaxEffectUPtr eax_effect_{};
244 Eax5State eax123_{}; // EAX1/EAX2/EAX3 state.
245 Eax4State eax4_{}; // EAX4 state.
246 Eax5State eax5_{}; // EAX5 state.
247 Eax5Props eax_{}; // Current EAX state.
249 [[noreturn]] static void eax_fail(const char* message);
250 [[noreturn]] static void eax_fail_unknown_effect_id();
251 [[noreturn]] static void eax_fail_unknown_property_id();
252 [[noreturn]] static void eax_fail_unknown_version();
254 // Gets a new value from EAX call,
255 // validates it,
256 // sets a dirty flag only if the new value differs form the old one,
257 // and assigns the new value.
258 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
259 static void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags)
261 const auto& src = call.get_value<Exception, const TProperties>();
262 TValidator{}(src);
263 dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
264 dst = src;
267 // Gets a new value from EAX call,
268 // validates it,
269 // sets a dirty flag without comparing the values,
270 // and assigns the new value.
271 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
272 static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
273 EaxDirtyFlags& dirty_flags)
275 const auto& src = call.get_value<Exception, const TProperties>();
276 TValidator{}(src);
277 dirty_flags |= TDirtyBit;
278 dst = src;
281 [[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
282 { return eax_fx_slot_index_ < 2; }
284 void eax4_fx_slot_ensure_unlocked() const;
286 [[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
287 [[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
288 [[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
290 void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
291 void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
292 void eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept;
293 void eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept;
294 void eax_fx_slot_set_current_defaults();
295 void eax_fx_slot_set_defaults();
297 static void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props);
298 static void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props);
299 void eax_fx_slot_get(const EaxCall& call) const;
300 // Returns `true` if all sources should be updated, or `false` otherwise.
301 bool eax_get(const EaxCall& call);
303 void eax_fx_slot_load_effect(int version, ALenum altype);
304 void eax_fx_slot_set_volume();
305 void eax_fx_slot_set_environment_flag();
306 void eax_fx_slot_set_flags();
308 void eax4_fx_slot_set_all(const EaxCall& call);
309 void eax5_fx_slot_set_all(const EaxCall& call);
311 [[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
313 // Returns `true` if all sources should be updated, or `false` otherwise.
314 bool eax4_fx_slot_set(const EaxCall& call);
315 // Returns `true` if all sources should be updated, or `false` otherwise.
316 bool eax5_fx_slot_set(const EaxCall& call);
317 // Returns `true` if all sources should be updated, or `false` otherwise.
318 bool eax_fx_slot_set(const EaxCall& call);
319 // Returns `true` if all sources should be updated, or `false` otherwise.
320 bool eax_set(const EaxCall& call);
322 template<
323 EaxDirtyFlags TDirtyBit,
324 typename TMemberResult,
325 typename TProps,
326 typename TState>
327 void eax_fx_slot_commit_property(TState& state, EaxDirtyFlags& dst_df,
328 TMemberResult TProps::*member) noexcept
330 auto& src_i = state.i;
331 auto& dst_i = eax_;
333 if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
335 dst_df |= TDirtyBit;
336 dst_i.*member = src_i.*member;
340 void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
341 void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
343 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
344 void eax_set_efx_slot_effect(EaxEffect &effect);
346 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
347 void eax_set_efx_slot_send_auto(bool is_send_auto);
349 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
350 void eax_set_efx_slot_gain(ALfloat gain);
352 public:
353 class EaxDeleter {
354 public:
355 void operator()(ALeffectslot *effect_slot);
357 #endif // ALSOFT_EAX
360 void UpdateAllEffectSlotProps(ALCcontext *context);
362 #ifdef ALSOFT_EAX
363 using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
365 EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
366 void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
367 #endif // ALSOFT_EAX
369 struct EffectSlotSubList {
370 uint64_t FreeMask{~0_u64};
371 gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
373 EffectSlotSubList() noexcept = default;
374 EffectSlotSubList(const EffectSlotSubList&) = delete;
375 EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
376 : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
377 { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
378 ~EffectSlotSubList();
380 EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
381 EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
382 { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
385 #endif