diff options
Diffstat (limited to 'core/voice.h')
-rw-r--r-- | core/voice.h | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/core/voice.h b/core/voice.h new file mode 100644 index 00000000..c3347cda --- /dev/null +++ b/core/voice.h @@ -0,0 +1,270 @@ +#ifndef CORE_VOICE_H +#define CORE_VOICE_H + +#include <array> +#include <atomic> +#include <memory> +#include <stddef.h> +#include <string> + +#include "albyte.h" +#include "almalloc.h" +#include "aloptional.h" +#include "alspan.h" +#include "bufferline.h" +#include "buffer_storage.h" +#include "devformat.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "mixer/defs.h" +#include "mixer/hrtfdefs.h" +#include "resampler_limits.h" +#include "uhjfilter.h" +#include "vector.h" + +struct ContextBase; +struct DeviceBase; +struct EffectSlot; +enum class DistanceModel : unsigned char; + +using uint = unsigned int; + + +#define MAX_SENDS 6 + + +enum class SpatializeMode : unsigned char { + Off, + On, + Auto +}; + +enum class DirectMode : unsigned char { + Off, + DropMismatch, + RemixMismatch +}; + + +/* Maximum number of extra source samples that may need to be loaded, for + * resampling or conversion purposes. + */ +constexpr uint MaxPostVoiceLoad{MaxResamplerEdge + UhjDecoder::sFilterDelay}; + + +enum { + AF_None = 0, + AF_LowPass = 1, + AF_HighPass = 2, + AF_BandPass = AF_LowPass | AF_HighPass +}; + + +struct DirectParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + NfcFilter NFCtrlFilter; + + struct { + HrtfFilter Old; + HrtfFilter Target; + alignas(16) std::array<float,HrtfHistoryLength> History; + } Hrtf; + + struct { + std::array<float,MAX_OUTPUT_CHANNELS> Current; + std::array<float,MAX_OUTPUT_CHANNELS> Target; + } Gains; +}; + +struct SendParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + struct { + std::array<float,MAX_OUTPUT_CHANNELS> Current; + std::array<float,MAX_OUTPUT_CHANNELS> Target; + } Gains; +}; + + +struct VoiceBufferItem { + std::atomic<VoiceBufferItem*> mNext{nullptr}; + + CallbackType mCallback{nullptr}; + void *mUserData{nullptr}; + + uint mSampleLen{0u}; + uint mLoopStart{0u}; + uint mLoopEnd{0u}; + + al::byte *mSamples{nullptr}; +}; + + +struct VoiceProps { + 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; + DirectMode DirectChannels; + SpatializeMode mSpatializeMode; + + bool DryGainHFAuto; + bool WetGainAuto; + bool WetGainHFAuto; + 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 { + EffectSlot *Slot; + float Gain; + float GainHF; + float HFReference; + float GainLF; + float LFReference; + } Send[MAX_SENDS]; +}; + +struct VoicePropsItem : public VoiceProps { + std::atomic<VoicePropsItem*> next{nullptr}; + + DEF_NEWDEL(VoicePropsItem) +}; + +constexpr uint VoiceIsStatic{ 1u<<0}; +constexpr uint VoiceIsCallback{ 1u<<1}; +constexpr uint VoiceIsAmbisonic{ 1u<<2}; /* Needs HF scaling for ambisonic upsampling. */ +constexpr uint VoiceCallbackStopped{1u<<3}; +constexpr uint VoiceIsFading{ 1u<<4}; /* Use gain stepping for smooth transitions. */ +constexpr uint VoiceHasHrtf{ 1u<<5}; +constexpr uint VoiceHasNfc{ 1u<<6}; + +struct Voice { + enum State { + Stopped, + Playing, + Stopping, + Pending + }; + + std::atomic<VoicePropsItem*> mUpdate{nullptr}; + + VoiceProps mProps; + + std::atomic<uint> mSourceID{0u}; + std::atomic<State> mPlayState{Stopped}; + std::atomic<bool> mPendingChange{false}; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue. + */ + std::atomic<uint> mPosition; + /** Fractional (fixed-point) offset to the next sample. */ + std::atomic<uint> mPositionFrac; + + /* Current buffer queue item being played. */ + std::atomic<VoiceBufferItem*> mCurrentBuffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + std::atomic<VoiceBufferItem*> mLoopBuffer; + + /* Properties for the attached buffer(s). */ + FmtChannels mFmtChannels; + FmtType mFmtType; + uint mFrequency; + uint mFrameSize; + AmbiLayout mAmbiLayout; + AmbiScaling mAmbiScaling; + uint mAmbiOrder; + + std::unique_ptr<UhjDecoder> mDecoder; + + /** Current target parameters used for mixing. */ + uint mStep{0}; + + ResamplerFunc mResampler; + + InterpState mResampleState; + + uint mFlags{}; + uint mNumCallbackSamples{0}; + + struct TargetData { + int FilterType; + al::span<FloatBufferLine> Buffer; + }; + TargetData mDirect; + std::array<TargetData,MAX_SENDS> mSend; + + /* The first MaxResamplerPadding/2 elements are the sample history from the + * previous mix, with an additional MaxResamplerPadding/2 elements that are + * now current (which may be overwritten if the buffer data is still + * available). + */ + static constexpr size_t LineSize{BufferLineSize + MaxResamplerPadding + + UhjDecoder::sFilterDelay}; + using BufferLine = std::array<float,LineSize>; + al::vector<BufferLine,16> mVoiceSamples{2}; + + struct ChannelData { + float mAmbiScale; + BandSplitter mAmbiSplitter; + + DirectParams mDryParams; + std::array<SendParams,MAX_SENDS> mWetParams; + }; + al::vector<ChannelData> mChans{2}; + + Voice() = default; + ~Voice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } + + Voice(const Voice&) = delete; + Voice& operator=(const Voice&) = delete; + + void mix(const State vstate, ContextBase *Context, const uint SamplesToDo); + + void prepare(DeviceBase *device); + + static void InitMixer(al::optional<std::string> resampler); + + DEF_NEWDEL(Voice) +}; + +extern Resampler ResamplerDefault; + +#endif /* CORE_VOICE_H */ |