#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/nfc.h" #include "almalloc.h" #include "alnumeric.h" enum class DistanceModel; #define MAX_PITCH 255 #define MAX_SENDS 16 /* Maximum number of samples to pad on either end of a buffer for resampling. * Note that both the beginning and end need padding! */ #define MAX_RESAMPLE_PADDING 24 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 (1<<0) #define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */ #define VOICE_HAS_HRTF (1<<2) #define VOICE_HAS_NFC (1<<3) struct ALvoice { std::atomic Update{nullptr}; std::atomic SourceID{0u}; std::atomic Playing{false}; ALvoicePropsBase Props; /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue, and the fractional (fixed-point) offset to the next * sample. */ std::atomic position; std::atomic position_fraction; /* Current buffer queue item being played. */ std::atomic current_buffer; /* Buffer queue item to loop to at end of queue (will be NULL for non- * looping voices). */ std::atomic loop_buffer; /** * Number of channels and bytes-per-sample for the attached source's * buffer(s). */ ALsizei NumChannels; ALsizei SampleSize; /** Current target parameters used for mixing. */ ALint Step; ResamplerFunc Resampler; ALuint Flags; ALuint Offset; /* Number of output samples mixed since starting. */ alignas(16) std::array,MAX_INPUT_CHANNELS> PrevSamples; InterpState ResampleState; struct { int FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } Direct; struct SendData { int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; }; al::FlexArray Send; ALvoice(size_t numsends) : Send{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, Send))); } }; 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, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, const ALsizei BufferSize); using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, const ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat (*data)[BUFFERSIZE], 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< al::MathDefs::Pi()*0.5f)) return minf(std::fabs(azimuth) * scale, al::MathDefs::Pi()*0.5f) * sign; return azimuth; } void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); /** * ComputePanGains * * Computes panning gains using the given channel decoder coefficients and the * pre-calculated direction or angle coefficients. For B-Format sources, the * coeffs are a 'slice' of a transform matrix for the input channel, used to * scale and orient the sound samples. */ inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { ComputePanningGainsBF(dry->AmbiMap.data(), dry->NumChannels, coeffs, ingain, gains); } void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); ALboolean MixSource(ALvoice *voice, 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