AuroraOpenALSoft/alc/voice.h

294 lines
7.2 KiB
C
Raw Normal View History

#ifndef VOICE_H
#define VOICE_H
#include "AL/al.h"
#include "AL/alext.h"
#include "alspan.h"
#include "alu.h"
#include "filters/biquad.h"
#include "filters/nfc.h"
#include "filters/splitter.h"
#include "hrtf.h"
enum SpatializeMode {
SpatializeOff = AL_FALSE,
SpatializeOn = AL_TRUE,
SpatializeAuto = AL_AUTO_SOFT
};
enum class Resampler {
Point,
Linear,
Cubic,
FastBSinc12,
BSinc12,
FastBSinc24,
BSinc24,
Max = BSinc24
};
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 5
#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 {
float sf; /* Scale interpolation factor. */
ALuint m; /* Coefficient count. */
ALuint 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 float *filter;
};
union InterpState {
BsincState bsinc;
};
using ResamplerFunc = const float*(*)(const InterpState *state, const float *RESTRICT src,
ALuint frac, ALuint increment, const al::span<float> dst);
ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state);
enum {
AF_None = 0,
AF_LowPass = 1,
AF_HighPass = 2,
AF_BandPass = AF_LowPass | AF_HighPass
};
struct MixHrtfFilter {
const HrirArray *Coeffs;
ALsizei Delay[2];
float Gain;
float GainStep;
};
struct DirectParams {
BiquadFilter LowPass;
BiquadFilter HighPass;
NfcFilter NFCtrlFilter;
struct {
HrtfFilter Old;
HrtfFilter Target;
HrtfState State;
} Hrtf;
struct {
float Current[MAX_OUTPUT_CHANNELS];
float Target[MAX_OUTPUT_CHANNELS];
} Gains;
};
struct SendParams {
BiquadFilter LowPass;
BiquadFilter HighPass;
struct {
float Current[MAX_OUTPUT_CHANNELS];
float Target[MAX_OUTPUT_CHANNELS];
} Gains;
};
struct ALvoicePropsBase {
float Pitch;
float Gain;
float OuterGain;
float MinGain;
float MaxGain;
float InnerAngle;
float OuterAngle;
float RefDistance;
float MaxDistance;
float RolloffFactor;
std::array<float,3> Position;
std::array<float,3> Velocity;
std::array<float,3> Direction;
std::array<float,3> OrientAt;
std::array<float,3> OrientUp;
bool HeadRelative;
DistanceModel mDistanceModel;
Resampler mResampler;
bool DirectChannels;
SpatializeMode mSpatializeMode;
bool DryGainHFAuto;
bool WetGainAuto;
bool WetGainHFAuto;
2019-10-03 00:07:23 +00:00
float OuterGainHF;
float AirAbsorptionFactor;
float RoomRolloffFactor;
float DopplerFactor;
std::array<float,2> StereoPan;
float Radius;
/** Direct filter and auxiliary send info. */
struct {
float Gain;
float GainHF;
float HFReference;
float GainLF;
float LFReference;
} Direct;
struct SendData {
ALeffectslot *Slot;
float Gain;
float GainHF;
float HFReference;
float GainLF;
float 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<ALuint> 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;
ALuint mNumChannels;
ALuint mSampleSize;
/** Current target parameters used for mixing. */
ALuint mStep;
ResamplerFunc mResampler;
InterpState mResampleState;
ALuint mFlags;
struct DirectData {
int FilterType;
al::span<FloatBufferLine> Buffer;
};
DirectData mDirect;
struct SendData {
int FilterType;
al::span<FloatBufferLine> Buffer;
};
std::array<SendData,MAX_SENDS> mSend;
struct ChannelData {
2019-10-03 00:07:23 +00:00
alignas(16) std::array<float,MAX_RESAMPLER_PADDING> mPrevSamples;
2019-10-03 00:07:23 +00:00
float mAmbiScale;
BandSplitter mAmbiSplitter;
DirectParams mDryParams;
std::array<SendParams,MAX_SENDS> mWetParams;
};
std::array<ChannelData,MAX_INPUT_CHANNELS> mChans;
ALvoice() = default;
ALvoice(const ALvoice&) = delete;
ALvoice(ALvoice&& rhs) noexcept { *this = std::move(rhs); }
~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); }
ALvoice& operator=(const ALvoice&) = delete;
ALvoice& operator=(ALvoice&& rhs) noexcept
{
ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)};
mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed),
std::memory_order_relaxed);
mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed);
mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed),
std::memory_order_relaxed);
mProps = rhs.mProps;
mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed);
mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed),
std::memory_order_relaxed);
mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed),
std::memory_order_relaxed);
mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed),
std::memory_order_relaxed);
mFmtChannels = rhs.mFmtChannels;
mFrequency = rhs.mFrequency;
mNumChannels = rhs.mNumChannels;
mSampleSize = rhs.mSampleSize;
mStep = rhs.mStep;
mResampler = rhs.mResampler;
mResampleState = rhs.mResampleState;
mFlags = rhs.mFlags;
mDirect = rhs.mDirect;
mSend = rhs.mSend;
mChans = rhs.mChans;
return *this;
}
void mix(ALvoice::State vstate, ALCcontext *Context, const ALuint SamplesToDo);
};
#endif /* VOICE_H */