2019-10-02 23:53:23 +00:00
|
|
|
#ifndef VOICE_H
|
|
|
|
#define VOICE_H
|
|
|
|
|
2019-10-06 04:23:31 +00:00
|
|
|
#include <array>
|
|
|
|
|
2019-10-02 23:53:23 +00:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alext.h"
|
|
|
|
|
2019-10-03 02:13:07 +00:00
|
|
|
#include "al/buffer.h"
|
2020-03-22 18:34:37 +00:00
|
|
|
#include "almalloc.h"
|
2019-10-02 23:53:23 +00:00
|
|
|
#include "alspan.h"
|
|
|
|
#include "alu.h"
|
2019-12-02 20:50:18 +00:00
|
|
|
#include "devformat.h"
|
2019-10-02 23:53:23 +00:00
|
|
|
#include "filters/biquad.h"
|
|
|
|
#include "filters/nfc.h"
|
|
|
|
#include "filters/splitter.h"
|
|
|
|
#include "hrtf.h"
|
|
|
|
|
2019-10-03 02:13:07 +00:00
|
|
|
enum class DistanceModel;
|
|
|
|
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
enum SpatializeMode {
|
|
|
|
SpatializeOff = AL_FALSE,
|
|
|
|
SpatializeOn = AL_TRUE,
|
|
|
|
SpatializeAuto = AL_AUTO_SOFT
|
|
|
|
};
|
|
|
|
|
2019-12-28 19:33:19 +00:00
|
|
|
enum class DirectMode : unsigned char {
|
|
|
|
Off = AL_FALSE,
|
|
|
|
DropMismatch = AL_DROP_UNMATCHED_SOFT,
|
|
|
|
RemixMismatch = AL_REMIX_UNMATCHED_SOFT
|
|
|
|
};
|
|
|
|
|
2019-10-02 23:53:23 +00:00
|
|
|
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. */
|
2019-10-03 02:22:14 +00:00
|
|
|
/* Filter coefficients, followed by the phase, scale, and scale-phase
|
2019-10-02 23:53:23 +00:00
|
|
|
* 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;
|
2020-02-03 00:11:43 +00:00
|
|
|
std::array<ALuint,2> Delay;
|
2019-10-02 23:53:23 +00:00
|
|
|
float Gain;
|
|
|
|
float GainStep;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct DirectParams {
|
|
|
|
BiquadFilter LowPass;
|
|
|
|
BiquadFilter HighPass;
|
|
|
|
|
|
|
|
NfcFilter NFCtrlFilter;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
HrtfFilter Old;
|
|
|
|
HrtfFilter Target;
|
2020-01-14 03:45:13 +00:00
|
|
|
alignas(16) std::array<float,HRTF_HISTORY_LENGTH> History;
|
2019-10-02 23:53:23 +00:00
|
|
|
} Hrtf;
|
|
|
|
|
|
|
|
struct {
|
2019-10-06 04:23:31 +00:00
|
|
|
std::array<float,MAX_OUTPUT_CHANNELS> Current;
|
|
|
|
std::array<float,MAX_OUTPUT_CHANNELS> Target;
|
2019-10-02 23:53:23 +00:00
|
|
|
} Gains;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SendParams {
|
|
|
|
BiquadFilter LowPass;
|
|
|
|
BiquadFilter HighPass;
|
|
|
|
|
|
|
|
struct {
|
2019-10-06 04:23:31 +00:00
|
|
|
std::array<float,MAX_OUTPUT_CHANNELS> Current;
|
|
|
|
std::array<float,MAX_OUTPUT_CHANNELS> Target;
|
2019-10-02 23:53:23 +00:00
|
|
|
} Gains;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
struct VoiceProps {
|
2019-10-02 23:53:23 +00:00
|
|
|
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;
|
2019-12-28 19:33:19 +00:00
|
|
|
DirectMode DirectChannels;
|
2019-10-02 23:53:23 +00:00
|
|
|
SpatializeMode mSpatializeMode;
|
|
|
|
|
|
|
|
bool DryGainHFAuto;
|
|
|
|
bool WetGainAuto;
|
|
|
|
bool WetGainHFAuto;
|
2019-10-03 00:07:23 +00:00
|
|
|
float OuterGainHF;
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
};
|
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
struct VoicePropsItem : public VoiceProps {
|
|
|
|
std::atomic<VoicePropsItem*> next{nullptr};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
DEF_NEWDEL(VoicePropsItem)
|
2019-10-02 23:53:23 +00:00
|
|
|
};
|
|
|
|
|
2020-02-18 01:13:00 +00:00
|
|
|
#define VOICE_IS_STATIC (1u<<0)
|
|
|
|
#define VOICE_IS_CALLBACK (1u<<1)
|
|
|
|
#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */
|
|
|
|
#define VOICE_CALLBACK_STOPPED (1u<<3)
|
|
|
|
#define VOICE_IS_FADING (1u<<4) /* Fading sources use gain stepping for smooth transitions. */
|
|
|
|
#define VOICE_HAS_HRTF (1u<<5)
|
|
|
|
#define VOICE_HAS_NFC (1u<<6)
|
2020-02-17 12:50:00 +00:00
|
|
|
|
|
|
|
#define VOICE_TYPE_MASK (VOICE_IS_STATIC | VOICE_IS_CALLBACK)
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
struct Voice {
|
2019-10-02 23:53:23 +00:00
|
|
|
enum State {
|
2020-03-04 18:09:44 +00:00
|
|
|
Stopped,
|
|
|
|
Playing,
|
|
|
|
Stopping,
|
|
|
|
Pending
|
2019-10-02 23:53:23 +00:00
|
|
|
};
|
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
std::atomic<VoicePropsItem*> mUpdate{nullptr};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
VoiceProps mProps;
|
2020-02-21 03:18:07 +00:00
|
|
|
|
2019-10-02 23:53:23 +00:00
|
|
|
std::atomic<ALuint> mSourceID{0u};
|
|
|
|
std::atomic<State> mPlayState{Stopped};
|
2020-02-26 09:48:59 +00:00
|
|
|
std::atomic<bool> mPendingChange{false};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 mSampleSize;
|
2019-12-02 20:50:18 +00:00
|
|
|
AmbiLayout mAmbiLayout;
|
|
|
|
AmbiNorm mAmbiScaling;
|
|
|
|
ALuint mAmbiOrder;
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
/** Current target parameters used for mixing. */
|
2020-02-18 01:13:00 +00:00
|
|
|
ALuint mStep{0};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
ResamplerFunc mResampler;
|
|
|
|
|
|
|
|
InterpState mResampleState;
|
|
|
|
|
2020-02-18 01:13:00 +00:00
|
|
|
ALuint mFlags{};
|
|
|
|
ALuint mNumCallbackSamples{0};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2019-10-05 23:11:38 +00:00
|
|
|
struct TargetData {
|
2019-10-02 23:53:23 +00:00
|
|
|
int FilterType;
|
|
|
|
al::span<FloatBufferLine> Buffer;
|
|
|
|
};
|
2019-10-05 23:11:38 +00:00
|
|
|
TargetData mDirect;
|
|
|
|
std::array<TargetData,MAX_SENDS> mSend;
|
2019-10-02 23:53:23 +00:00
|
|
|
|
|
|
|
struct ChannelData {
|
2019-10-03 00:07:23 +00:00
|
|
|
alignas(16) std::array<float,MAX_RESAMPLER_PADDING> mPrevSamples;
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2019-10-03 00:07:23 +00:00
|
|
|
float mAmbiScale;
|
2019-10-02 23:53:23 +00:00
|
|
|
BandSplitter mAmbiSplitter;
|
|
|
|
|
|
|
|
DirectParams mDryParams;
|
|
|
|
std::array<SendParams,MAX_SENDS> mWetParams;
|
|
|
|
};
|
2020-03-26 04:06:24 +00:00
|
|
|
al::vector<ChannelData> mChans{2};
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
Voice() = default;
|
|
|
|
Voice(const Voice&) = delete;
|
|
|
|
~Voice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); }
|
|
|
|
Voice& operator=(const Voice&) = delete;
|
2019-10-02 23:53:23 +00:00
|
|
|
|
2019-10-15 03:45:23 +00:00
|
|
|
void mix(const State vstate, ALCcontext *Context, const ALuint SamplesToDo);
|
2020-03-22 18:34:37 +00:00
|
|
|
|
2020-03-29 00:20:38 +00:00
|
|
|
DEF_NEWDEL(Voice)
|
2019-10-02 23:53:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* VOICE_H */
|