#ifndef _ALU_H_ #define _ALU_H_ #include #include #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #include #include #include "alMain.h" #include "alBuffer.h" #include "hrtf.h" #include "logging.h" #include "math_defs.h" #include "filters/biquad.h" #include "filters/splitter.h" #include "filters/nfc.h" #include "almalloc.h" #include "alnumeric.h" enum class DistanceModel; #define MAX_PITCH 255 #define MAX_SENDS 16 struct BSincTable; struct ALsource; struct ALbufferlistitem; struct ALvoice; struct ALeffectslot; #define DITHER_RNG_SEED 22222 enum SpatializeMode { SpatializeOff = AL_FALSE, SpatializeOn = AL_TRUE, SpatializeAuto = AL_AUTO_SOFT }; enum Resampler { PointResampler, LinearResampler, FIR4Resampler, BSinc12Resampler, BSinc24Resampler, ResamplerMax = BSinc24Resampler }; extern Resampler ResamplerDefault; /* The number of distinct scale and phase intervals within the bsinc filter * table. */ #define BSINC_SCALE_BITS 4 #define BSINC_SCALE_COUNT (1< *Coeffs; ALsizei Delay[2]; ALfloat Gain; ALfloat GainStep; }; struct DirectParams { BiquadFilter LowPass; BiquadFilter HighPass; NfcFilter NFCtrlFilter; struct { HrtfParams Old; HrtfParams Target; HrtfState State; } Hrtf; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; } Gains; }; struct SendParams { BiquadFilter LowPass; BiquadFilter HighPass; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; } Gains; }; struct ALvoicePropsBase { ALfloat Pitch; ALfloat Gain; ALfloat OuterGain; ALfloat MinGain; ALfloat MaxGain; ALfloat InnerAngle; ALfloat OuterAngle; ALfloat RefDistance; ALfloat MaxDistance; ALfloat RolloffFactor; std::array Position; std::array Velocity; std::array Direction; std::array OrientAt; std::array OrientUp; ALboolean HeadRelative; DistanceModel mDistanceModel; Resampler mResampler; ALboolean DirectChannels; SpatializeMode mSpatializeMode; ALboolean DryGainHFAuto; ALboolean WetGainAuto; ALboolean WetGainHFAuto; ALfloat OuterGainHF; ALfloat AirAbsorptionFactor; ALfloat RoomRolloffFactor; ALfloat DopplerFactor; std::array StereoPan; ALfloat Radius; /** Direct filter and auxiliary send info. */ struct { ALfloat Gain; ALfloat GainHF; ALfloat HFReference; ALfloat GainLF; ALfloat LFReference; } Direct; struct SendData { ALeffectslot *Slot; ALfloat Gain; ALfloat GainHF; ALfloat HFReference; ALfloat GainLF; ALfloat LFReference; } Send[MAX_SENDS]; }; struct ALvoiceProps : public ALvoicePropsBase { std::atomic next{nullptr}; DEF_NEWDEL(ALvoiceProps) }; #define VOICE_IS_STATIC (1u<<0) #define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ #define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ #define VOICE_HAS_HRTF (1u<<3) #define VOICE_HAS_NFC (1u<<4) struct ALvoice { enum State { Stopped = 0, Playing = 1, Stopping = 2 }; std::atomic mUpdate{nullptr}; std::atomic mSourceID{0u}; std::atomic mPlayState{Stopped}; ALvoicePropsBase mProps; /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue. */ std::atomic mPosition; /** Fractional (fixed-point) offset to the next sample. */ std::atomic mPositionFrac; /* Current buffer queue item being played. */ std::atomic mCurrentBuffer; /* Buffer queue item to loop to at end of queue (will be NULL for non- * looping voices). */ std::atomic mLoopBuffer; /* Properties for the attached buffer(s). */ FmtChannels mFmtChannels; ALuint mFrequency; ALsizei mNumChannels; ALsizei mSampleSize; /** Current target parameters used for mixing. */ ALint mStep; ResamplerFunc mResampler; InterpState mResampleState; ALuint mFlags; struct ResampleData { alignas(16) std::array mPrevSamples; ALfloat mAmbiScale; BandSplitter mAmbiSplitter; }; std::array mResampleData; struct { int FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } mDirect; struct SendData { int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; }; al::FlexArray mSend; ALvoice(size_t numsends) : mSend{numsends} { } ALvoice(const ALvoice&) = delete; ALvoice& operator=(const ALvoice&) = delete; static constexpr size_t Sizeof(size_t numsends) noexcept { return maxz(sizeof(ALvoice), al::FlexArray::Sizeof(numsends, offsetof(ALvoice, mSend))); } }; void DeinitVoice(ALvoice *voice) noexcept; using MixerFunc = void(*)(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*data)[BUFFERSIZE], const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize); using HrtfMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize); #define GAIN_MIX_MAX (1000.0f) /* +60dB */ #define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ #define SPEEDOFSOUNDMETRESPERSEC (343.3f) #define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ /* Target gain for the reverb decay feedback reaching the decay time. */ #define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ #define FRACTIONBITS (12) #define FRACTIONONE (1< GetAmbiIdentityRow(size_t i) noexcept { std::array ret{}; ret[i] = 1.0f; return ret; } void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device state, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); extern MixerFunc MixSamples; extern RowMixerFunc MixRowSamples; extern const ALfloat ConeScale; extern const ALfloat ZScale; extern const ALboolean OverrideReverbSpeedOfSound; #endif