diff options
Diffstat (limited to 'OpenAL32/Include/alu.h')
-rw-r--r-- | OpenAL32/Include/alu.h | 454 |
1 files changed, 329 insertions, 125 deletions
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a309c4ab..c572fd71 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -12,31 +12,56 @@ #include "alMain.h" #include "alBuffer.h" -#include "alFilter.h" #include "hrtf.h" #include "align.h" #include "math_defs.h" +#include "filters/defs.h" +#include "filters/nfc.h" #define MAX_PITCH (255) -/* Maximum number of buffer samples before the current pos needed for resampling. */ -#define MAX_PRE_SAMPLES 12 - -/* Maximum number of buffer samples after the current pos needed for resampling. */ -#define MAX_POST_SAMPLES 12 +/* 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 #ifdef __cplusplus extern "C" { #endif +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 +}; -/* The number of distinct scale and phase intervals within the filter table. */ +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + BSinc12Resampler, + BSinc24Resampler, + + ResamplerMax = BSinc24Resampler +}; +extern enum 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<<BSINC_SCALE_BITS) #define BSINC_PHASE_BITS 4 @@ -48,16 +73,29 @@ struct ALvoice; */ typedef struct BsincState { ALfloat sf; /* Scale interpolation factor. */ - ALuint m; /* Coefficient count. */ - ALint l; /* Left coefficient offset. */ - struct { - const ALfloat *filter; /* Filter coefficients. */ - const ALfloat *scDelta; /* Scale deltas. */ - const ALfloat *phDelta; /* Phase deltas. */ - const ALfloat *spDelta; /* Scale-phase deltas. */ - } coeffs[BSINC_PHASE_COUNT]; + ALsizei m; /* Coefficient count. */ + ALsizei l; /* Left coefficient offset. */ + /* Filter coefficients, followed by the scale, phase, and scale-phase + * delta coefficients. Starting at phase index 0, each subsequent phase + * index follows contiguously. + */ + const ALfloat *filter; } BsincState; +typedef union InterpState { + BsincState bsinc; +} InterpState; + +typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, + const ALfloat *restrict src, ALsizei frac, ALint increment, + ALfloat *restrict dst, ALsizei dstlen +); + +void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); + +extern const struct BSincTable bsinc12; +extern const struct BSincTable bsinc24; + typedef union aluVector { alignas(16) ALfloat v[4]; @@ -75,6 +113,7 @@ inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALf typedef union aluMatrixf { alignas(16) ALfloat m[4][4]; } aluMatrixf; +extern const aluMatrixf IdentityMatrixf; inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) @@ -97,31 +136,6 @@ inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat } -typedef union aluMatrixd { - alignas(16) ALdouble m[4][4]; -} aluMatrixd; - -inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row, - ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3) -{ - matrix->m[row][0] = m0; - matrix->m[row][1] = m1; - matrix->m[row][2] = m2; - matrix->m[row][3] = m3; -} - -inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03, - ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13, - ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23, - ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33) -{ - aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03); - aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13); - aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23); - aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33); -} - - enum ActiveFilters { AF_None = 0, AF_LowPass = 1, @@ -130,74 +144,199 @@ enum ActiveFilters { }; -typedef struct MixGains { - ALfloat Current; - ALfloat Step; - ALfloat Target; -} MixGains; +typedef struct MixHrtfParams { + const ALfloat (*Coeffs)[2]; + ALsizei Delay[2]; + ALfloat Gain; + ALfloat GainStep; +} MixHrtfParams; typedef struct DirectParams { - ALfloat (*OutBuffer)[BUFFERSIZE]; - ALuint OutChannels; + BiquadFilter LowPass; + BiquadFilter HighPass; - /* If not 'moving', gain/coefficients are set directly without fading. */ - ALboolean Moving; - /* Stepping counter for gain/coefficient fading. */ - ALuint Counter; - /* Last direction (relative to listener) and gain of a moving source. */ - aluVector LastDir; - ALfloat LastGain; + NfcFilter NFCtrlFilter; struct { - enum ActiveFilters ActiveType; - ALfilterState LowPass; - ALfilterState HighPass; - } Filters[MAX_INPUT_CHANNELS]; + HrtfParams Old; + HrtfParams Target; + HrtfState State; + } Hrtf; struct { - HrtfParams Params; - HrtfState State; - } Hrtf[MAX_INPUT_CHANNELS]; - MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS]; + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; } DirectParams; typedef struct SendParams { - ALfloat (*OutBuffer)[BUFFERSIZE]; - - ALboolean Moving; - ALuint Counter; + BiquadFilter LowPass; + BiquadFilter HighPass; struct { - enum ActiveFilters ActiveType; - ALfilterState LowPass; - ALfilterState HighPass; - } Filters[MAX_INPUT_CHANNELS]; - - /* Gain control, which applies to each input channel to a single (mono) - * output buffer. */ - MixGains Gains[MAX_INPUT_CHANNELS]; + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; } SendParams; -typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, - const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen -); +struct ALvoiceProps { + ATOMIC(struct ALvoiceProps*) next; + + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Direction[3]; + ALfloat Orientation[2][3]; + ALboolean HeadRelative; + enum DistanceModel DistanceModel; + enum Resampler Resampler; + ALboolean DirectChannels; + enum SpatializeMode SpatializeMode; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + ALfloat StereoPan[2]; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct { + struct ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Send[]; +}; + +#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) + +typedef struct ALvoice { + struct ALvoiceProps *Props; + + ATOMIC(struct ALvoiceProps*) Update; + + ATOMIC(struct ALsource*) Source; + ATOMIC(bool) Playing; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue, and the fractional (fixed-point) offset to the next + * sample. + */ + ATOMIC(ALuint) position; + ATOMIC(ALsizei) position_fraction; + + /* Current buffer queue item being played. */ + ATOMIC(struct ALbufferlistitem*) current_buffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + ATOMIC(struct ALbufferlistitem*) loop_buffer; + + /** + * Number of channels and bytes-per-sample for the attached source's + * buffer(s). + */ + ALsizei NumChannels; + ALsizei SampleSize; -typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, - ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, - ALuint Counter, ALuint OutPos, ALuint BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const HrtfParams *hrtfparams, - HrtfState *hrtfstate, ALuint BufferSize); + /** Current target parameters used for mixing. */ + ALint Step; + ResamplerFunc Resampler; + + ALuint Flags; + + ALuint Offset; /* Number of output samples mixed since starting. */ + + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING]; + + InterpState ResampleState; + + struct { + enum ActiveFilters FilterType; + DirectParams Params[MAX_INPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei Channels; + ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; + } Direct; + + struct { + enum ActiveFilters FilterType; + SendParams Params[MAX_INPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei Channels; + } Send[]; +} ALvoice; + +void DeinitVoice(ALvoice *voice); + + +typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, + ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, + const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); +typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); +typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, + HrtfState *hrtfstate, ALsizei BufferSize); +typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); +typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat (*restrict Values)[2], ALsizei BufferSize); + + +#define GAIN_MIX_MAX (16.0f) /* +24dB */ #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<<FRACTIONBITS) #define FRACTIONMASK (FRACTIONONE-1) @@ -245,83 +384,148 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b) inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) { return minu64(max, maxu64(min, val)); } - -union ResamplerCoeffs { - ALfloat FIR4[FRACTIONONE][4]; - ALfloat FIR8[FRACTIONONE][8]; -}; -extern alignas(16) union ResamplerCoeffs ResampleCoeffs; - -extern alignas(16) const ALfloat bsincTab[18840]; +inline size_t minz(size_t a, size_t b) +{ return ((a > b) ? b : a); } +inline size_t maxz(size_t a, size_t b) +{ return ((a > b) ? a : b); } +inline size_t clampz(size_t val, size_t min, size_t max) +{ return minz(max, maxz(min, val)); } inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) { return val1 + (val2-val1)*mu; } -inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac) -{ - const ALfloat *k = ResampleCoeffs.FIR4[frac]; - return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3; -} -inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac) +inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu) { - const ALfloat *k = ResampleCoeffs.FIR8[frac]; - return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 + - k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7; + ALfloat mu2 = mu*mu, mu3 = mu2*mu; + ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu; + ALfloat a1 = 1.5f*mu3 + -2.5f*mu2 + 1.0f; + ALfloat a2 = -1.5f*mu3 + 2.0f*mu2 + 0.5f*mu; + ALfloat a3 = 0.5f*mu3 + -0.5f*mu2; + return val1*a0 + val2*a1 + val3*a2 + val4*a3; } +enum HrtfRequestMode { + Hrtf_Default = 0, + Hrtf_Enable = 1, + Hrtf_Disable = 2, +}; + +void aluInit(void); + void aluInitMixer(void); -ALvoid aluInitPanning(ALCdevice *Device); +ResamplerFunc SelectResampler(enum Resampler resampler); + +/* aluInitRenderer + * + * Set up the appropriate panning method and mixing method given the device + * properties. + */ +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq); + +void aluInitEffectPanning(struct ALeffectslot *slot); + +void aluSelectPostProcess(ALCdevice *device); /** - * ComputeDirectionalGains + * Calculates ambisonic encoder coefficients using the X, Y, and Z direction + * components, which must represent a normalized (unit length) vector, and the + * spread is the angular width of the sound (0...tau). + * + * NOTE: The components use ambisonic coordinates. As a result: + * + * Ambisonic Y = OpenAL -X + * Ambisonic Z = OpenAL Y + * Ambisonic X = OpenAL -Z * - * Sets channel gains based on a direction. The direction must be a 3-component - * vector no longer than 1 unit. + * The components are ordered such that OpenAL's X, Y, and Z are the first, + * second, and third parameters respectively -- simply negate X and Z. */ -void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat coeffs[MAX_AMBI_COEFFS]); /** - * ComputeAngleGains + * CalcDirectionCoeffs * - * Sets channel gains based on angle and elevation. The angle and elevation - * parameters are in radians, going right and up respectively. + * Calculates ambisonic coefficients based on an OpenAL direction vector. The + * vector must be normalized (unit length), and the spread is the angular width + * of the sound (0...tau). */ -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + /* Convert from OpenAL coords to Ambisonics. */ + CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs); +} /** - * ComputeAmbientGains + * CalcAngleCoeffs * - * Sets channel gains for ambient, omni-directional sounds. + * Calculates ambisonic coefficients based on azimuth and elevation. The + * azimuth and elevation parameters are in radians, going right and up + * respectively. */ -void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + ALfloat x = -sinf(azimuth) * cosf(elevation); + ALfloat y = sinf(elevation); + ALfloat z = cosf(azimuth) * cosf(elevation); + + CalcAmbiCoeffs(x, y, z, spread, coeffs); +} /** - * ComputeBFormatGains + * ScaleAzimuthFront * - * Sets channel gains for a given (first-order) B-Format channel. The matrix is - * a 1x4 'slice' of the rotation matrix for a given channel used to orient the - * coefficients. + * Scales the given azimuth toward the side (+/- pi/2 radians) for positions in + * front. */ -void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline float ScaleAzimuthFront(float azimuth, float scale) +{ + ALfloat sign = copysignf(1.0f, azimuth); + if(!(fabsf(azimuth) > F_PI_2)) + return minf(fabsf(azimuth) * scale, F_PI_2) * sign; + return azimuth; +} + + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +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]) +{ + if(dry->CoeffCount > 0) + ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, + coeffs, ingain, gains); + else + ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains); +} -ALvoid UpdateContextSources(ALCcontext *context); +ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); -ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext); -ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext); +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); +/* Caller must lock the device, and the mixer must not be running. */ +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); -ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo); +void UpdateContextProps(ALCcontext *context); -ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); -/* Caller must lock the device. */ -ALvoid aluHandleDisconnect(ALCdevice *device); +extern MixerFunc MixSamples; +extern RowMixerFunc MixRowSamples; extern ALfloat ConeScale; extern ALfloat ZScale; +extern ALboolean OverrideReverbSpeedOfSound; #ifdef __cplusplus } |