🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

441 lines
12 KiB

#ifndef _ALU_H_
#define _ALU_H_
#include <limits.h>
#include <math.h>
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#include <cmath>
#include <array>
#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<<BSINC_SCALE_BITS)
#define BSINC_PHASE_BITS 4
#define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
/* Interpolator state. Kind of a misnomer since the interpolator itself is
* stateless. This just keeps it from having to recompute scale-related
* mappings for every sample.
*/
struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
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;
};
union InterpState {
BsincState bsinc;
};
using ResamplerFunc = const ALfloat*(*)(const InterpState *state,
const ALfloat *RESTRICT src, ALsizei frac, ALint increment,
ALfloat *RESTRICT dst, ALsizei dstlen);
void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table);
extern const BSincTable bsinc12;
extern const BSincTable bsinc24;
enum {
AF_None = 0,
AF_LowPass = 1,
AF_HighPass = 2,
AF_BandPass = AF_LowPass | AF_HighPass
};
struct MixHrtfParams {
const HrirArray<ALfloat> *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<ALfloat,3> Position;
std::array<ALfloat,3> Velocity;
std::array<ALfloat,3> Direction;
std::array<ALfloat,3> OrientAt;
std::array<ALfloat,3> 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<ALfloat,2> 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<ALvoiceProps*> 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<ALvoiceProps*> mUpdate{nullptr};
std::atomic<ALuint> mSourceID{0u};
std::atomic<State> mPlayState{Stopped};
ALvoicePropsBase mProps;
/**
* Source offset in samples, relative to the currently playing buffer, NOT
* the whole queue.
*/
std::atomic<ALuint> mPosition;
/** Fractional (fixed-point) offset to the next sample. */
std::atomic<ALsizei> mPositionFrac;
/* Current buffer queue item being played. */
std::atomic<ALbufferlistitem*> mCurrentBuffer;
/* Buffer queue item to loop to at end of queue (will be NULL for non-
* looping voices).
*/
std::atomic<ALbufferlistitem*> 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<ALfloat,MAX_RESAMPLE_PADDING*2> mPrevSamples;
ALfloat mAmbiScale;
BandSplitter mAmbiSplitter;
};
std::array<ResampleData,MAX_INPUT_CHANNELS> 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<SendData> 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<SendData>::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<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
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(Resampler resampler);
/* aluInitRenderer
*
* Set up the appropriate panning method and mixing method given the device
* properties.
*/
void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq);
void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device);
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_CHANNELS]);
/**
* 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_CHANNELS])
{
/* 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_CHANNELS])
{
ALfloat x = -std::sin(azimuth) * std::cos(elevation);
ALfloat y = std::sin(elevation);
ALfloat z = std::cos(azimuth) * std::cos(elevation);
CalcAmbiCoeffs(x, y, z, spread, coeffs);
}
/**
* 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.
*/
void ComputePanGains(const MixParams *mix, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]);
inline std::array<ALfloat,MAX_AMBI_CHANNELS> GetAmbiIdentityRow(size_t i) noexcept
{
std::array<ALfloat,MAX_AMBI_CHANNELS> 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