aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-04-24 10:46:32 -0700
committerChris Robinson <[email protected]>2021-04-24 10:46:32 -0700
commit6d5dfbd09b6657c15ccc93f81ac556041bbd8d5f (patch)
treeb99dbe9719d072558a7e05017534267edee9947e
parent581174ef98e92de89244412ddc94ae93d172e69c (diff)
Move the DeviceBase declaraction to core
-rw-r--r--CMakeLists.txt2
-rw-r--r--alc/alc.cpp16
-rw-r--r--alc/alcmain.h241
-rw-r--r--core/device.cpp7
-rw-r--r--core/device.h274
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 */