Return ALC_FALSE on error from alcEventIsSupportedSOFT
[openal-soft.git] / al / auxeffectslot.h
blob5f9913a02ed6136500e7f7ce12b1dc4791c981c8
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 : bool {
41 Initial, Playing,
44 struct ALeffectslot {
45 ALuint EffectId{};
46 float Gain{1.0f};
47 bool AuxSendAuto{true};
48 ALeffectslot *Target{nullptr};
49 ALbuffer *Buffer{nullptr};
51 struct EffectData {
52 EffectSlotType Type{EffectSlotType::None};
53 EffectProps Props{};
55 al::intrusive_ptr<EffectState> State;
57 EffectData Effect;
59 bool mPropsDirty{true};
61 SlotState mState{SlotState::Initial};
63 std::atomic<ALuint> ref{0u};
65 EffectSlot *mSlot{nullptr};
67 /* Self ID */
68 ALuint id{};
70 ALeffectslot(ALCcontext *context);
71 ALeffectslot(const ALeffectslot&) = delete;
72 ALeffectslot& operator=(const ALeffectslot&) = delete;
73 ~ALeffectslot();
75 ALenum initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps,
76 ALCcontext *context);
77 void updateProps(ALCcontext *context) const;
79 static void SetName(ALCcontext *context, ALuint id, std::string_view name);
82 #ifdef ALSOFT_EAX
83 public:
84 void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
86 [[nodiscard]] auto eax_get_index() const noexcept -> EaxFxSlotIndexValue { return eax_fx_slot_index_; }
87 [[nodiscard]] auto eax_get_eax_fx_slot() const noexcept -> const EAX50FXSLOTPROPERTIES&
88 { return eax_; }
90 // Returns `true` if all sources should be updated, or `false` otherwise.
91 [[nodiscard]] auto eax_dispatch(const EaxCall& call) -> bool
92 { return call.is_get() ? eax_get(call) : eax_set(call); }
94 void eax_commit();
96 private:
97 static constexpr auto eax_load_effect_dirty_bit = EaxDirtyFlags{1} << 0;
98 static constexpr auto eax_volume_dirty_bit = EaxDirtyFlags{1} << 1;
99 static constexpr auto eax_lock_dirty_bit = EaxDirtyFlags{1} << 2;
100 static constexpr auto eax_flags_dirty_bit = EaxDirtyFlags{1} << 3;
101 static constexpr auto eax_occlusion_dirty_bit = EaxDirtyFlags{1} << 4;
102 static constexpr auto eax_occlusion_lf_ratio_dirty_bit = EaxDirtyFlags{1} << 5;
104 using Exception = EaxFxSlotException;
106 using Eax4Props = EAX40FXSLOTPROPERTIES;
108 struct Eax4State {
109 Eax4Props i; // Immediate.
112 using Eax5Props = EAX50FXSLOTPROPERTIES;
114 struct Eax5State {
115 Eax5Props i; // Immediate.
118 struct EaxRangeValidator {
119 template<typename TValue>
120 void operator()(
121 const char* name,
122 const TValue& value,
123 const TValue& min_value,
124 const TValue& max_value) const
126 eax_validate_range<Exception>(name, value, min_value, max_value);
130 struct Eax4GuidLoadEffectValidator {
131 void operator()(const GUID& guidLoadEffect) const
133 if (guidLoadEffect != EAX_NULL_GUID &&
134 guidLoadEffect != EAX_REVERB_EFFECT &&
135 guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT &&
136 guidLoadEffect != EAX_AUTOWAH_EFFECT &&
137 guidLoadEffect != EAX_CHORUS_EFFECT &&
138 guidLoadEffect != EAX_DISTORTION_EFFECT &&
139 guidLoadEffect != EAX_ECHO_EFFECT &&
140 guidLoadEffect != EAX_EQUALIZER_EFFECT &&
141 guidLoadEffect != EAX_FLANGER_EFFECT &&
142 guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT &&
143 guidLoadEffect != EAX_VOCALMORPHER_EFFECT &&
144 guidLoadEffect != EAX_PITCHSHIFTER_EFFECT &&
145 guidLoadEffect != EAX_RINGMODULATOR_EFFECT)
147 eax_fail_unknown_effect_id();
152 struct Eax4VolumeValidator {
153 void operator()(long lVolume) const
155 EaxRangeValidator{}(
156 "Volume",
157 lVolume,
158 EAXFXSLOT_MINVOLUME,
159 EAXFXSLOT_MAXVOLUME);
163 struct Eax4LockValidator {
164 void operator()(long lLock) const
166 EaxRangeValidator{}(
167 "Lock",
168 lLock,
169 EAXFXSLOT_MINLOCK,
170 EAXFXSLOT_MAXLOCK);
174 struct Eax4FlagsValidator {
175 void operator()(unsigned long ulFlags) const
177 EaxRangeValidator{}(
178 "Flags",
179 ulFlags,
180 0UL,
181 ~EAX40FXSLOTFLAGS_RESERVED);
185 struct Eax4AllValidator {
186 void operator()(const EAX40FXSLOTPROPERTIES& all) const
188 Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
189 Eax4VolumeValidator{}(all.lVolume);
190 Eax4LockValidator{}(all.lLock);
191 Eax4FlagsValidator{}(all.ulFlags);
195 struct Eax5FlagsValidator {
196 void operator()(unsigned long ulFlags) const
198 EaxRangeValidator{}(
199 "Flags",
200 ulFlags,
201 0UL,
202 ~EAX50FXSLOTFLAGS_RESERVED);
206 struct Eax5OcclusionValidator {
207 void operator()(long lOcclusion) const
209 EaxRangeValidator{}(
210 "Occlusion",
211 lOcclusion,
212 EAXFXSLOT_MINOCCLUSION,
213 EAXFXSLOT_MAXOCCLUSION);
217 struct Eax5OcclusionLfRatioValidator {
218 void operator()(float flOcclusionLFRatio) const
220 EaxRangeValidator{}(
221 "Occlusion LF Ratio",
222 flOcclusionLFRatio,
223 EAXFXSLOT_MINOCCLUSIONLFRATIO,
224 EAXFXSLOT_MAXOCCLUSIONLFRATIO);
228 struct Eax5AllValidator {
229 void operator()(const EAX50FXSLOTPROPERTIES& all) const
231 Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
232 Eax4VolumeValidator{}(all.lVolume);
233 Eax4LockValidator{}(all.lLock);
234 Eax5FlagsValidator{}(all.ulFlags);
235 Eax5OcclusionValidator{}(all.lOcclusion);
236 Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
240 ALCcontext* eax_al_context_{};
241 EaxFxSlotIndexValue eax_fx_slot_index_{};
242 int eax_version_{}; // Current EAX version.
243 EaxDirtyFlags eax_df_{}; // Dirty flags for the current EAX version.
244 EaxEffectUPtr eax_effect_{};
245 Eax5State eax123_{}; // EAX1/EAX2/EAX3 state.
246 Eax4State eax4_{}; // EAX4 state.
247 Eax5State eax5_{}; // EAX5 state.
248 Eax5Props eax_{}; // Current EAX state.
250 [[noreturn]] static void eax_fail(const char* message);
251 [[noreturn]] static void eax_fail_unknown_effect_id();
252 [[noreturn]] static void eax_fail_unknown_property_id();
253 [[noreturn]] static void eax_fail_unknown_version();
255 // Gets a new value from EAX call,
256 // validates it,
257 // sets a dirty flag only if the new value differs form the old one,
258 // and assigns the new value.
259 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
260 static void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags)
262 const auto& src = call.get_value<Exception, const TProperties>();
263 TValidator{}(src);
264 dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
265 dst = src;
268 // Gets a new value from EAX call,
269 // validates it,
270 // sets a dirty flag without comparing the values,
271 // and assigns the new value.
272 template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
273 static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
274 EaxDirtyFlags& dirty_flags)
276 const auto& src = call.get_value<Exception, const TProperties>();
277 TValidator{}(src);
278 dirty_flags |= TDirtyBit;
279 dst = src;
282 [[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
283 { return eax_fx_slot_index_ < 2; }
285 void eax4_fx_slot_ensure_unlocked() const;
287 [[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
288 [[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
289 [[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
291 void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
292 void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
293 void eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept;
294 void eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept;
295 void eax_fx_slot_set_current_defaults();
296 void eax_fx_slot_set_defaults();
298 static void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props);
299 static void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props);
300 void eax_fx_slot_get(const EaxCall& call) const;
301 // Returns `true` if all sources should be updated, or `false` otherwise.
302 bool eax_get(const EaxCall& call);
304 void eax_fx_slot_load_effect(int version, ALenum altype);
305 void eax_fx_slot_set_volume();
306 void eax_fx_slot_set_environment_flag();
307 void eax_fx_slot_set_flags();
309 void eax4_fx_slot_set_all(const EaxCall& call);
310 void eax5_fx_slot_set_all(const EaxCall& call);
312 [[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
314 // Returns `true` if all sources should be updated, or `false` otherwise.
315 bool eax4_fx_slot_set(const EaxCall& call);
316 // Returns `true` if all sources should be updated, or `false` otherwise.
317 bool eax5_fx_slot_set(const EaxCall& call);
318 // Returns `true` if all sources should be updated, or `false` otherwise.
319 bool eax_fx_slot_set(const EaxCall& call);
320 // Returns `true` if all sources should be updated, or `false` otherwise.
321 bool eax_set(const EaxCall& call);
323 template<
324 EaxDirtyFlags TDirtyBit,
325 typename TMemberResult,
326 typename TProps,
327 typename TState>
328 void eax_fx_slot_commit_property(TState& state, EaxDirtyFlags& dst_df,
329 TMemberResult TProps::*member) noexcept
331 auto& src_i = state.i;
332 auto& dst_i = eax_;
334 if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
336 dst_df |= TDirtyBit;
337 dst_i.*member = src_i.*member;
341 void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
342 void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
344 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
345 void eax_set_efx_slot_effect(EaxEffect &effect);
347 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
348 void eax_set_efx_slot_send_auto(bool is_send_auto);
350 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
351 void eax_set_efx_slot_gain(ALfloat gain);
353 public:
354 class EaxDeleter {
355 public:
356 void operator()(ALeffectslot *effect_slot);
358 #endif // ALSOFT_EAX
361 void UpdateAllEffectSlotProps(ALCcontext *context);
363 #ifdef ALSOFT_EAX
364 using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
366 EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
367 void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
368 #endif // ALSOFT_EAX
370 struct EffectSlotSubList {
371 uint64_t FreeMask{~0_u64};
372 gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
374 EffectSlotSubList() noexcept = default;
375 EffectSlotSubList(const EffectSlotSubList&) = delete;
376 EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
377 : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
378 { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
379 ~EffectSlotSubList();
381 EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
382 EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
383 { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
386 #endif