diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/effects/base.h | 205 | ||||
-rw-r--r-- | core/effectslot.cpp | 25 | ||||
-rw-r--r-- | core/effectslot.h | 88 |
3 files changed, 318 insertions, 0 deletions
diff --git a/core/effects/base.h b/core/effects/base.h new file mode 100644 index 00000000..3094f627 --- /dev/null +++ b/core/effects/base.h @@ -0,0 +1,205 @@ +#ifndef CORE_EFFECTS_BASE_H +#define CORE_EFFECTS_BASE_H + +#include <stddef.h> + +#include "albyte.h" +#include "almalloc.h" +#include "alspan.h" +#include "atomic.h" +#include "core/bufferline.h" +#include "intrusive_ptr.h" + +struct BufferStorage; +struct ContextBase; +struct DeviceBase; +struct EffectSlot; +struct MixParams; +struct RealMixParams; + + +/** Target gain for the reverb decay feedback reaching the decay time. */ +constexpr float ReverbDecayGain{0.001f}; /* -60 dB */ + +constexpr float ReverbMaxReflectionsDelay{0.3f}; +constexpr float ReverbMaxLateReverbDelay{0.1f}; + +enum class ChorusWaveform { + Sinusoid, + Triangle +}; + +constexpr float ChorusMaxDelay{0.016f}; +constexpr float FlangerMaxDelay{0.004f}; + +constexpr float EchoMaxDelay{0.207f}; +constexpr float EchoMaxLRDelay{0.404f}; + +enum class FShifterDirection { + Down, + Up, + Off +}; + +enum class ModulatorWaveform { + Sinusoid, + Sawtooth, + Square +}; + +enum class VMorpherPhenome { + A, E, I, O, U, + AA, AE, AH, AO, EH, ER, IH, IY, UH, UW, + B, D, F, G, J, K, L, M, N, P, R, S, T, V, Z +}; + +enum class VMorpherWaveform { + Sinusoid, + Triangle, + Sawtooth +}; + +union EffectProps { + struct { + // Shared Reverb Properties + float Density; + float Diffusion; + float Gain; + float GainHF; + float DecayTime; + float DecayHFRatio; + float ReflectionsGain; + float ReflectionsDelay; + float LateReverbGain; + float LateReverbDelay; + float AirAbsorptionGainHF; + float RoomRolloffFactor; + bool DecayHFLimit; + + // Additional EAX Reverb Properties + float GainLF; + float DecayLFRatio; + float ReflectionsPan[3]; + float LateReverbPan[3]; + float EchoTime; + float EchoDepth; + float ModulationTime; + float ModulationDepth; + float HFReference; + float LFReference; + } Reverb; + + struct { + float AttackTime; + float ReleaseTime; + float Resonance; + float PeakGain; + } Autowah; + + struct { + ChorusWaveform Waveform; + int Phase; + float Rate; + float Depth; + float Feedback; + float Delay; + } Chorus; /* Also Flanger */ + + struct { + bool OnOff; + } Compressor; + + struct { + float Edge; + float Gain; + float LowpassCutoff; + float EQCenter; + float EQBandwidth; + } Distortion; + + struct { + float Delay; + float LRDelay; + + float Damping; + float Feedback; + + float Spread; + } Echo; + + struct { + float LowCutoff; + float LowGain; + float Mid1Center; + float Mid1Gain; + float Mid1Width; + float Mid2Center; + float Mid2Gain; + float Mid2Width; + float HighCutoff; + float HighGain; + } Equalizer; + + struct { + float Frequency; + FShifterDirection LeftDirection; + FShifterDirection RightDirection; + } Fshifter; + + struct { + float Frequency; + float HighPassCutoff; + ModulatorWaveform Waveform; + } Modulator; + + struct { + int CoarseTune; + int FineTune; + } Pshifter; + + struct { + float Rate; + VMorpherPhenome PhonemeA; + VMorpherPhenome PhonemeB; + int PhonemeACoarseTuning; + int PhonemeBCoarseTuning; + VMorpherWaveform Waveform; + } Vmorpher; + + struct { + float Gain; + } Dedicated; +}; + + +struct EffectTarget { + MixParams *Main; + RealMixParams *RealOut; +}; + +struct EffectState : public al::intrusive_ref<EffectState> { + struct Buffer { + const BufferStorage *storage; + al::span<const al::byte> samples; + }; + + al::span<FloatBufferLine> mOutTarget; + + + virtual ~EffectState() = default; + + virtual void deviceUpdate(const DeviceBase *device, const Buffer &buffer) = 0; + virtual void update(const ContextBase *context, const EffectSlot *slot, + const EffectProps *props, const EffectTarget target) = 0; + virtual void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, + const al::span<FloatBufferLine> samplesOut) = 0; +}; + + +struct EffectStateFactory { + virtual ~EffectStateFactory() = default; + + virtual al::intrusive_ptr<EffectState> create() = 0; +}; + +#endif /* CORE_EFFECTS_BASE_H */ diff --git a/core/effectslot.cpp b/core/effectslot.cpp new file mode 100644 index 00000000..51fb8d46 --- /dev/null +++ b/core/effectslot.cpp @@ -0,0 +1,25 @@ + +#include "config.h" + +#include "effectslot.h" + +#include <stddef.h> + +#include "almalloc.h" +#include "context.h" + + +EffectSlotArray *EffectSlot::CreatePtrArray(size_t count) noexcept +{ + /* Allocate space for twice as many pointers, so the mixer has scratch + * space to store a sorted list during mixing. + */ + void *ptr{al_calloc(alignof(EffectSlotArray), EffectSlotArray::Sizeof(count*2))}; + return al::construct_at(static_cast<EffectSlotArray*>(ptr), count); +} + +EffectSlot::~EffectSlot() +{ + if(mWetBuffer) + mWetBuffer->mInUse = false; +} diff --git a/core/effectslot.h b/core/effectslot.h new file mode 100644 index 00000000..8b7b977c --- /dev/null +++ b/core/effectslot.h @@ -0,0 +1,88 @@ +#ifndef CORE_EFFECTSLOT_H +#define CORE_EFFECTSLOT_H + +#include <atomic> + +#include "almalloc.h" +#include "device.h" +#include "effects/base.h" +#include "intrusive_ptr.h" + +struct EffectSlot; +struct WetBuffer; + +using EffectSlotArray = al::FlexArray<EffectSlot*>; + + +enum class EffectSlotType : unsigned char { + None, + Reverb, + Chorus, + Distortion, + Echo, + Flanger, + FrequencyShifter, + VocalMorpher, + PitchShifter, + RingModulator, + Autowah, + Compressor, + Equalizer, + EAXReverb, + DedicatedLFE, + DedicatedDialog, + Convolution +}; + +struct EffectSlotProps { + float Gain; + bool AuxSendAuto; + EffectSlot *Target; + + EffectSlotType Type; + EffectProps Props; + + al::intrusive_ptr<EffectState> State; + + std::atomic<EffectSlotProps*> next; + + DEF_NEWDEL(EffectSlotProps) +}; + + +struct EffectSlot { + std::atomic<EffectSlotProps*> Update{nullptr}; + + /* Wet buffer configuration is ACN channel order with N3D scaling. + * Consequently, effects that only want to work with mono input can use + * channel 0 by itself. Effects that want multichannel can process the + * ambisonics signal and make a B-Format source pan. + */ + MixParams Wet; + + float Gain{1.0f}; + bool AuxSendAuto{true}; + EffectSlot *Target{nullptr}; + + EffectSlotType EffectType{EffectSlotType::None}; + EffectProps mEffectProps{}; + EffectState *mEffectState{nullptr}; + + float RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ + float DecayTime{0.0f}; + float DecayLFRatio{0.0f}; + float DecayHFRatio{0.0f}; + bool DecayHFLimit{false}; + float AirAbsorptionGainHF{1.0f}; + + /* Mixing buffer used by the Wet mix. */ + WetBuffer *mWetBuffer{nullptr}; + + ~EffectSlot(); + + static EffectSlotArray *CreatePtrArray(size_t count) noexcept; + + DISABLE_ALLOC() +}; + +#endif /* CORE_EFFECTSLOT_H */ |