diff options
author | Chris Robinson <[email protected]> | 2021-04-24 10:46:32 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2021-04-24 10:46:32 -0700 |
commit | 6d5dfbd09b6657c15ccc93f81ac556041bbd8d5f (patch) | |
tree | b99dbe9719d072558a7e05017534267edee9947e | |
parent | 581174ef98e92de89244412ddc94ae93d172e69c (diff) |
Move the DeviceBase declaraction to core
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | alc/alc.cpp | 16 | ||||
-rw-r--r-- | alc/alcmain.h | 241 | ||||
-rw-r--r-- | core/device.cpp | 7 | ||||
-rw-r--r-- | core/device.h | 274 |
5 files changed, 289 insertions, 251 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 13d7ee54..b323fa12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,6 +657,8 @@ set(CORE_OBJS core/cpu_caps.h core/devformat.cpp core/devformat.h + core/device.cpp + core/device.h core/except.cpp core/except.h core/filters/biquad.h diff --git a/alc/alc.cpp b/alc/alc.cpp index bbb9a45c..87c8bbf4 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -980,12 +980,6 @@ constexpr int alcEFXMajorVersion{1}; constexpr int alcEFXMinorVersion{0}; -/* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is - * defined globally as a sharable object. - */ -al::FlexArray<ContextBase*> EmptyContextArray{0u}; - - using DeviceRef = al::intrusive_ptr<ALCdevice>; @@ -2301,14 +2295,14 @@ static bool ResetDeviceParams(ALCdevice *device, const int *attrList) } -DeviceBase::DeviceBase(DeviceType type) : Type{type}, mContexts{&EmptyContextArray} +DeviceBase::DeviceBase(DeviceType type) : Type{type}, mContexts{&sEmptyContextArray} { } DeviceBase::~DeviceBase() { auto *oldarray = mContexts.exchange(nullptr, std::memory_order_relaxed); - if(oldarray != &EmptyContextArray) delete oldarray; + if(oldarray != &sEmptyContextArray) delete oldarray; } ALCdevice::~ALCdevice() @@ -2547,7 +2541,7 @@ bool ALCcontext::deinit() using ContextArray = al::FlexArray<ContextBase*>; auto alloc_ctx_array = [](const size_t count) -> ContextArray* { - if(count == 0) return &EmptyContextArray; + if(count == 0) return &DeviceBase::sEmptyContextArray; return ContextArray::Create(count).release(); }; auto *newarray = alloc_ctx_array(oldarray->size() - toremove); @@ -2562,7 +2556,7 @@ bool ALCcontext::deinit() * to finish before deleting the old array. */ mDevice->mContexts.store(newarray); - if(oldarray != &EmptyContextArray) + if(oldarray != &DeviceBase::sEmptyContextArray) { mDevice->waitForMix(); delete oldarray; @@ -3393,7 +3387,7 @@ START_API_FUNC * to finish before deleting the old array. */ dev->mContexts.store(newarray.release()); - if(oldarray != &EmptyContextArray) + if(oldarray != &DeviceBase::sEmptyContextArray) { dev->waitForMix(); delete oldarray; diff --git a/alc/alcmain.h b/alc/alcmain.h index 025ba3d4..e8875184 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -25,6 +25,7 @@ #include "core/ambidefs.h" #include "core/bufferline.h" #include "core/devformat.h" +#include "core/device.h" #include "core/filters/splitter.h" #include "core/hrtf.h" #include "core/mixer/defs.h" @@ -32,253 +33,13 @@ #include "intrusive_ptr.h" #include "vector.h" -class BFormatDec; struct ALbuffer; struct ALeffect; struct ALfilter; -struct BackendBase; -struct Compressor; -struct ContextBase; -struct EffectState; -struct UhjEncoder; -struct bs2b; using uint = unsigned int; -#define MIN_OUTPUT_RATE 8000 -#define MAX_OUTPUT_RATE 192000 -#define DEFAULT_OUTPUT_RATE 44100 - -#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ -#define DEFAULT_NUM_UPDATES 3 - - -enum class DeviceType : unsigned char { - Playback, - Capture, - Loopback -}; - - -enum class RenderMode : unsigned char { - Normal, - Pairwise, - Hrtf -}; - - -struct InputRemixMap { - struct TargetMix { Channel channel; float mix; }; - - Channel channel; - std::array<TargetMix,2> targets; -}; - - -/* Maximum delay in samples for speaker distance compensation. */ -#define MAX_DELAY_LENGTH 1024 - -struct DistanceComp { - struct ChanData { - float Gain{1.0f}; - uint Length{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */ - float *Buffer{nullptr}; - }; - - std::array<ChanData,MAX_OUTPUT_CHANNELS> mChannels; - al::FlexArray<float,16> mSamples; - - DistanceComp(size_t count) : mSamples{count} { } - - static std::unique_ptr<DistanceComp> Create(size_t numsamples) - { return std::unique_ptr<DistanceComp>{new(FamCount(numsamples)) DistanceComp{numsamples}}; } - - DEF_FAM_NEWDEL(DistanceComp, mSamples) -}; - - -struct BFChannelConfig { - float Scale; - uint Index; -}; - - -struct MixParams { - /* Coefficient channel mapping for mixing to the buffer. */ - std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap{}; - - al::span<FloatBufferLine> Buffer; -}; - -struct RealMixParams { - al::span<const InputRemixMap> RemixMap; - std::array<uint,MaxChannels> ChannelIndex{}; - - al::span<FloatBufferLine> Buffer; -}; - -enum { - // Frequency was requested by the app or config file - FrequencyRequest, - // Channel configuration was requested by the config file - ChannelsRequest, - // Sample type was requested by the config file - SampleTypeRequest, - - // Specifies if the DSP is paused at user request - DevicePaused, - // Specifies if the device is currently running - DeviceRunning, - - DeviceFlagsCount -}; - -struct DeviceBase { - std::atomic<bool> Connected{true}; - const DeviceType Type{}; - - uint Frequency{}; - uint UpdateSize{}; - uint BufferSize{}; - - DevFmtChannels FmtChans{}; - DevFmtType FmtType{}; - bool IsHeadphones{false}; - uint mAmbiOrder{0}; - float mXOverFreq{400.0f}; - /* For DevFmtAmbi* output only, specifies the channel order and - * normalization. - */ - DevAmbiLayout mAmbiLayout{DevAmbiLayout::Default}; - DevAmbiScaling mAmbiScale{DevAmbiScaling::Default}; - - std::string DeviceName; - - // Device flags - std::bitset<DeviceFlagsCount> Flags{}; - - uint NumAuxSends{}; - - /* Rendering mode. */ - RenderMode mRenderMode{RenderMode::Normal}; - - /* The average speaker distance as determined by the ambdec configuration, - * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. - */ - float AvgSpeakerDist{0.0f}; - - uint SamplesDone{0u}; - std::chrono::nanoseconds ClockBase{0}; - std::chrono::nanoseconds FixedLatency{0}; - - /* Temp storage used for mixer processing. */ - alignas(16) float ResampledData[BufferLineSize]; - alignas(16) float FilteredData[BufferLineSize]; - union { - alignas(16) float HrtfSourceData[BufferLineSize + HrtfHistoryLength]; - alignas(16) float NfcSampleData[BufferLineSize]; - }; - - /* Persistent storage for HRTF mixing. */ - alignas(16) float2 HrtfAccumData[BufferLineSize + HrirLength + HrtfDirectDelay]; - - /* Mixing buffer used by the Dry mix and Real output. */ - al::vector<FloatBufferLine, 16> MixBuffer; - - /* The "dry" path corresponds to the main output. */ - MixParams Dry; - uint NumChannelsPerOrder[MaxAmbiOrder+1]{}; - - /* "Real" output, which will be written to the device buffer. May alias the - * dry buffer. - */ - RealMixParams RealOut; - - /* HRTF state and info */ - std::unique_ptr<DirectHrtfState> mHrtfState; - al::intrusive_ptr<HrtfStore> mHrtf; - uint mIrSize{0}; - - /* Ambisonic-to-UHJ encoder */ - std::unique_ptr<UhjEncoder> mUhjEncoder; - - /* Ambisonic decoder for speakers */ - std::unique_ptr<BFormatDec> AmbiDecoder; - - /* Stereo-to-binaural filter */ - std::unique_ptr<bs2b> Bs2b; - - using PostProc = void(DeviceBase::*)(const size_t SamplesToDo); - PostProc PostProcess{nullptr}; - - std::unique_ptr<Compressor> Limiter; - - /* Delay buffers used to compensate for speaker distances. */ - std::unique_ptr<DistanceComp> ChannelDelays; - - /* Dithering control. */ - float DitherDepth{0.0f}; - uint DitherSeed{0u}; - - /* Running count of the mixer invocations, in 31.1 fixed point. This - * actually increments *twice* when mixing, first at the start and then at - * the end, so the bottom bit indicates if the device is currently mixing - * and the upper bits indicates how many mixes have been done. - */ - RefCount MixCount{0u}; - - // Contexts created on this device - std::atomic<al::FlexArray<ContextBase*>*> mContexts{nullptr}; - - /* This lock protects the device state (format, update size, etc) from - * being from being changed in multiple threads, or being accessed while - * being changed. It's also used to serialize calls to the backend. - */ - std::mutex StateLock; - std::unique_ptr<BackendBase> Backend; - - - DeviceBase(DeviceType type); - DeviceBase(const DeviceBase&) = delete; - DeviceBase& operator=(const DeviceBase&) = delete; - ~DeviceBase(); - - uint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } - uint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } - uint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } - - uint waitForMix() const noexcept - { - uint refcount; - while((refcount=MixCount.load(std::memory_order_acquire))&1) { - } - return refcount; - } - - void ProcessHrtf(const size_t SamplesToDo); - void ProcessAmbiDec(const size_t SamplesToDo); - void ProcessAmbiDecStablized(const size_t SamplesToDo); - void ProcessUhj(const size_t SamplesToDo); - void ProcessBs2b(const size_t SamplesToDo); - - inline void postProcess(const size_t SamplesToDo) - { if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); } - - void renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep); - - /* Caller must lock the device state, and the mixer must not be running. */ -#ifdef __USE_MINGW_ANSI_STDIO - [[gnu::format(gnu_printf,2,3)]] -#else - [[gnu::format(printf,2,3)]] -#endif - void handleDisconnect(const char *msg, ...); - - DISABLE_ALLOC() -}; - - struct BufferSubList { uint64_t FreeMask{~0_u64}; ALbuffer *Buffers{nullptr}; /* 64 */ diff --git a/core/device.cpp b/core/device.cpp new file mode 100644 index 00000000..9705c0ac --- /dev/null +++ b/core/device.cpp @@ -0,0 +1,7 @@ + +#include "config.h" + +#include "device.h" + + +al::FlexArray<ContextBase*> DeviceBase::sEmptyContextArray{0u}; diff --git a/core/device.h b/core/device.h new file mode 100644 index 00000000..bc6bae52 --- /dev/null +++ b/core/device.h @@ -0,0 +1,274 @@ +#ifndef CORE_DEVICE_H +#define CORE_DEVICE_H + +#include <stddef.h> + +#include <array> +#include <atomic> +#include <bitset> +#include <chrono> +#include <memory> +#include <mutex> +#include <string> + +#include "almalloc.h" +#include "alspan.h" +#include "ambidefs.h" +#include "atomic.h" +#include "core/bufferline.h" +#include "devformat.h" +#include "intrusive_ptr.h" +#include "mixer/hrtfdefs.h" +#include "opthelpers.h" +#include "vector.h" + +struct BackendBase; +class BFormatDec; +struct bs2b; +struct Compressor; +struct ContextBase; +struct DirectHrtfState; +struct HrtfStore; +struct UhjEncoder; + +using uint = unsigned int; + + +#define MIN_OUTPUT_RATE 8000 +#define MAX_OUTPUT_RATE 192000 +#define DEFAULT_OUTPUT_RATE 44100 + +#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ +#define DEFAULT_NUM_UPDATES 3 + + +enum class DeviceType : unsigned char { + Playback, + Capture, + Loopback +}; + + +enum class RenderMode : unsigned char { + Normal, + Pairwise, + Hrtf +}; + + +struct InputRemixMap { + struct TargetMix { Channel channel; float mix; }; + + Channel channel; + std::array<TargetMix,2> targets; +}; + + +/* Maximum delay in samples for speaker distance compensation. */ +#define MAX_DELAY_LENGTH 1024 + +struct DistanceComp { + struct ChanData { + float Gain{1.0f}; + uint Length{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + float *Buffer{nullptr}; + }; + + std::array<ChanData,MAX_OUTPUT_CHANNELS> mChannels; + al::FlexArray<float,16> mSamples; + + DistanceComp(size_t count) : mSamples{count} { } + + static std::unique_ptr<DistanceComp> Create(size_t numsamples) + { return std::unique_ptr<DistanceComp>{new(FamCount(numsamples)) DistanceComp{numsamples}}; } + + DEF_FAM_NEWDEL(DistanceComp, mSamples) +}; + + +struct BFChannelConfig { + float Scale; + uint Index; +}; + + +struct MixParams { + /* Coefficient channel mapping for mixing to the buffer. */ + std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap{}; + + al::span<FloatBufferLine> Buffer; +}; + +struct RealMixParams { + al::span<const InputRemixMap> RemixMap; + std::array<uint,MaxChannels> ChannelIndex{}; + + al::span<FloatBufferLine> Buffer; +}; + +enum { + // Frequency was requested by the app or config file + FrequencyRequest, + // Channel configuration was requested by the config file + ChannelsRequest, + // Sample type was requested by the config file + SampleTypeRequest, + + // Specifies if the DSP is paused at user request + DevicePaused, + // Specifies if the device is currently running + DeviceRunning, + + DeviceFlagsCount +}; + +struct DeviceBase { + /* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is + * defined globally as a sharable object. + */ + static al::FlexArray<ContextBase*> sEmptyContextArray; + + std::atomic<bool> Connected{true}; + const DeviceType Type{}; + + uint Frequency{}; + uint UpdateSize{}; + uint BufferSize{}; + + DevFmtChannels FmtChans{}; + DevFmtType FmtType{}; + bool IsHeadphones{false}; + uint mAmbiOrder{0}; + float mXOverFreq{400.0f}; + /* For DevFmtAmbi* output only, specifies the channel order and + * normalization. + */ + DevAmbiLayout mAmbiLayout{DevAmbiLayout::Default}; + DevAmbiScaling mAmbiScale{DevAmbiScaling::Default}; + + std::string DeviceName; + + // Device flags + std::bitset<DeviceFlagsCount> Flags{}; + + uint NumAuxSends{}; + + /* Rendering mode. */ + RenderMode mRenderMode{RenderMode::Normal}; + + /* The average speaker distance as determined by the ambdec configuration, + * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. + */ + float AvgSpeakerDist{0.0f}; + + uint SamplesDone{0u}; + std::chrono::nanoseconds ClockBase{0}; + std::chrono::nanoseconds FixedLatency{0}; + + /* Temp storage used for mixer processing. */ + alignas(16) float ResampledData[BufferLineSize]; + alignas(16) float FilteredData[BufferLineSize]; + union { + alignas(16) float HrtfSourceData[BufferLineSize + HrtfHistoryLength]; + alignas(16) float NfcSampleData[BufferLineSize]; + }; + + /* Persistent storage for HRTF mixing. */ + alignas(16) float2 HrtfAccumData[BufferLineSize + HrirLength + HrtfDirectDelay]; + + /* Mixing buffer used by the Dry mix and Real output. */ + al::vector<FloatBufferLine, 16> MixBuffer; + + /* The "dry" path corresponds to the main output. */ + MixParams Dry; + uint NumChannelsPerOrder[MaxAmbiOrder+1]{}; + + /* "Real" output, which will be written to the device buffer. May alias the + * dry buffer. + */ + RealMixParams RealOut; + + /* HRTF state and info */ + std::unique_ptr<DirectHrtfState> mHrtfState; + al::intrusive_ptr<HrtfStore> mHrtf; + uint mIrSize{0}; + + /* Ambisonic-to-UHJ encoder */ + std::unique_ptr<UhjEncoder> mUhjEncoder; + + /* Ambisonic decoder for speakers */ + std::unique_ptr<BFormatDec> AmbiDecoder; + + /* Stereo-to-binaural filter */ + std::unique_ptr<bs2b> Bs2b; + + using PostProc = void(DeviceBase::*)(const size_t SamplesToDo); + PostProc PostProcess{nullptr}; + + std::unique_ptr<Compressor> Limiter; + + /* Delay buffers used to compensate for speaker distances. */ + std::unique_ptr<DistanceComp> ChannelDelays; + + /* Dithering control. */ + float DitherDepth{0.0f}; + uint DitherSeed{0u}; + + /* Running count of the mixer invocations, in 31.1 fixed point. This + * actually increments *twice* when mixing, first at the start and then at + * the end, so the bottom bit indicates if the device is currently mixing + * and the upper bits indicates how many mixes have been done. + */ + RefCount MixCount{0u}; + + // Contexts created on this device + std::atomic<al::FlexArray<ContextBase*>*> mContexts{nullptr}; + + /* This lock protects the device state (format, update size, etc) from + * being from being changed in multiple threads, or being accessed while + * being changed. It's also used to serialize calls to the backend. + */ + std::mutex StateLock; + std::unique_ptr<BackendBase> Backend; + + + DeviceBase(DeviceType type); + DeviceBase(const DeviceBase&) = delete; + DeviceBase& operator=(const DeviceBase&) = delete; + ~DeviceBase(); + + uint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } + uint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } + uint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } + + uint waitForMix() const noexcept + { + uint refcount; + while((refcount=MixCount.load(std::memory_order_acquire))&1) { + } + return refcount; + } + + void ProcessHrtf(const size_t SamplesToDo); + void ProcessAmbiDec(const size_t SamplesToDo); + void ProcessAmbiDecStablized(const size_t SamplesToDo); + void ProcessUhj(const size_t SamplesToDo); + void ProcessBs2b(const size_t SamplesToDo); + + inline void postProcess(const size_t SamplesToDo) + { if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); } + + void renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep); + + /* Caller must lock the device state, and the mixer must not be running. */ +#ifdef __USE_MINGW_ANSI_STDIO + [[gnu::format(gnu_printf,2,3)]] +#else + [[gnu::format(printf,2,3)]] +#endif + void handleDisconnect(const char *msg, ...); + + DISABLE_ALLOC() +}; + +#endif /* CORE_DEVICE_H */ |