#ifndef _ALU_H_ #define _ALU_H_ #include #include #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_IEEEFP_H #include #endif #include "alMain.h" #include "alBuffer.h" #include "hrtf.h" #include "math_defs.h" #include "filters/defs.h" #include "filters/nfc.h" enum class DistanceModel; #define MAX_PITCH (255) /* 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 }; 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< b) ? b : a); } inline ALfloat maxf(ALfloat a, ALfloat b) noexcept { return ((a > b) ? a : b); } inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max) noexcept { return minf(max, maxf(min, val)); } inline ALdouble mind(ALdouble a, ALdouble b) noexcept { return ((a > b) ? b : a); } inline ALdouble maxd(ALdouble a, ALdouble b) noexcept { return ((a > b) ? a : b); } inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max) noexcept { return mind(max, maxd(min, val)); } inline ALuint minu(ALuint a, ALuint b) noexcept { return ((a > b) ? b : a); } inline ALuint maxu(ALuint a, ALuint b) noexcept { return ((a > b) ? a : b); } inline ALuint clampu(ALuint val, ALuint min, ALuint max) noexcept { return minu(max, maxu(min, val)); } inline ALint mini(ALint a, ALint b) noexcept { return ((a > b) ? b : a); } inline ALint maxi(ALint a, ALint b) noexcept { return ((a > b) ? a : b); } inline ALint clampi(ALint val, ALint min, ALint max) noexcept { return mini(max, maxi(min, val)); } inline ALint64 mini64(ALint64 a, ALint64 b) noexcept { return ((a > b) ? b : a); } inline ALint64 maxi64(ALint64 a, ALint64 b) noexcept { return ((a > b) ? a : b); } inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max) noexcept { return mini64(max, maxi64(min, val)); } inline ALuint64 minu64(ALuint64 a, ALuint64 b) noexcept { return ((a > b) ? b : a); } inline ALuint64 maxu64(ALuint64 a, ALuint64 b) noexcept { return ((a > b) ? a : b); } inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) noexcept { return minu64(max, maxu64(min, val)); } inline size_t minz(size_t a, size_t b) noexcept { return ((a > b) ? b : a); } inline size_t maxz(size_t a, size_t b) noexcept { return ((a > b) ? a : b); } inline size_t clampz(size_t val, size_t min, size_t max) noexcept { return minz(max, maxz(min, val)); } inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) noexcept { return val1 + (val2-val1)*mu; } inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu) noexcept { 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); 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); /** * 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 * * 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 CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); /** * CalcDirectionCoeffs * * 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). */ 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); } /** * CalcAngleCoeffs * * Calculates ambisonic coefficients based on azimuth and elevation. The * azimuth and elevation parameters are in radians, going right and up * respectively. */ 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); } /** * ScaleAzimuthFront * * Scales the given azimuth toward the side (+/- pi/2 radians) for positions in * front. */ 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); } ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); 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); extern MixerFunc MixSamples; extern RowMixerFunc MixRowSamples; extern ALfloat ConeScale; extern ALfloat ZScale; extern ALboolean OverrideReverbSpeedOfSound; #ifdef __cplusplus } #endif #endif