device.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #ifndef CORE_DEVICE_H
  2. #define CORE_DEVICE_H
  3. #include <array>
  4. #include <atomic>
  5. #include <bitset>
  6. #include <chrono>
  7. #include <cstddef>
  8. #include <cstdint>
  9. #include <memory>
  10. #include <string>
  11. #include "almalloc.h"
  12. #include "alspan.h"
  13. #include "ambidefs.h"
  14. #include "atomic.h"
  15. #include "bufferline.h"
  16. #include "devformat.h"
  17. #include "filters/nfc.h"
  18. #include "flexarray.h"
  19. #include "fmt/core.h"
  20. #include "intrusive_ptr.h"
  21. #include "mixer/hrtfdefs.h"
  22. #include "opthelpers.h"
  23. #include "resampler_limits.h"
  24. #include "uhjfilter.h"
  25. #include "vector.h"
  26. class BFormatDec;
  27. namespace Bs2b {
  28. struct bs2b;
  29. } // namespace Bs2b
  30. class Compressor;
  31. struct ContextBase;
  32. struct DirectHrtfState;
  33. struct HrtfStore;
  34. using uint = unsigned int;
  35. inline constexpr std::size_t MinOutputRate{8000};
  36. inline constexpr std::size_t MaxOutputRate{192000};
  37. inline constexpr std::size_t DefaultOutputRate{48000};
  38. inline constexpr std::size_t DefaultUpdateSize{960}; /* 20ms */
  39. inline constexpr std::size_t DefaultNumUpdates{3};
  40. enum class DeviceType : std::uint8_t {
  41. Playback,
  42. Capture,
  43. Loopback
  44. };
  45. enum class RenderMode : std::uint8_t {
  46. Normal,
  47. Pairwise,
  48. Hrtf
  49. };
  50. enum class StereoEncoding : std::uint8_t {
  51. Basic,
  52. Uhj,
  53. Hrtf,
  54. Default = Basic
  55. };
  56. struct InputRemixMap {
  57. struct TargetMix { Channel channel; float mix; };
  58. Channel channel;
  59. al::span<const TargetMix> targets;
  60. };
  61. struct DistanceComp {
  62. /* Maximum delay in samples for speaker distance compensation. */
  63. static constexpr uint MaxDelay{1024};
  64. struct ChanData {
  65. al::span<float> Buffer; /* Valid size is [0...MaxDelay). */
  66. float Gain{1.0f};
  67. };
  68. std::array<ChanData,MaxOutputChannels> mChannels;
  69. al::FlexArray<float,16> mSamples;
  70. explicit DistanceComp(std::size_t count) : mSamples{count} { }
  71. static std::unique_ptr<DistanceComp> Create(std::size_t numsamples)
  72. { return std::unique_ptr<DistanceComp>{new(FamCount(numsamples)) DistanceComp{numsamples}}; }
  73. DEF_FAM_NEWDEL(DistanceComp, mSamples)
  74. };
  75. constexpr auto InvalidChannelIndex = static_cast<std::uint8_t>(~0u);
  76. struct BFChannelConfig {
  77. float Scale;
  78. uint Index;
  79. };
  80. struct MixParams {
  81. /* Coefficient channel mapping for mixing to the buffer. */
  82. std::array<BFChannelConfig,MaxAmbiChannels> AmbiMap{};
  83. al::span<FloatBufferLine> Buffer;
  84. /**
  85. * Helper to set an identity/pass-through panning for ambisonic mixing. The
  86. * source is expected to be a 3D ACN/N3D ambisonic buffer, and for each
  87. * channel [0...count), the given functor is called with the source channel
  88. * index, destination channel index, and the gain for that channel. If the
  89. * destination channel is InvalidChannelIndex, the given source channel is
  90. * not used for output.
  91. */
  92. template<typename F>
  93. void setAmbiMixParams(const MixParams &inmix, const float gainbase, F func) const
  94. {
  95. const std::size_t numIn{inmix.Buffer.size()};
  96. const std::size_t numOut{Buffer.size()};
  97. for(std::size_t i{0};i < numIn;++i)
  98. {
  99. std::uint8_t idx{InvalidChannelIndex};
  100. float gain{0.0f};
  101. for(std::size_t j{0};j < numOut;++j)
  102. {
  103. if(AmbiMap[j].Index == inmix.AmbiMap[i].Index)
  104. {
  105. idx = static_cast<std::uint8_t>(j);
  106. gain = AmbiMap[j].Scale * gainbase;
  107. break;
  108. }
  109. }
  110. func(i, idx, gain);
  111. }
  112. }
  113. };
  114. struct RealMixParams {
  115. al::span<const InputRemixMap> RemixMap;
  116. std::array<std::uint8_t,MaxChannels> ChannelIndex{};
  117. al::span<FloatBufferLine> Buffer;
  118. };
  119. using AmbiRotateMatrix = std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels>;
  120. enum {
  121. // Frequency was requested by the app or config file
  122. FrequencyRequest,
  123. // Channel configuration was requested by the app or config file
  124. ChannelsRequest,
  125. // Sample type was requested by the config file
  126. SampleTypeRequest,
  127. // Specifies if the DSP is paused at user request
  128. DevicePaused,
  129. // Specifies if the output plays directly on/in ears (headphones, headset,
  130. // ear buds, etc).
  131. DirectEar,
  132. /* Specifies if output is using speaker virtualization (e.g. Windows
  133. * Spatial Audio).
  134. */
  135. Virtualization,
  136. DeviceFlagsCount
  137. };
  138. enum class DeviceState : std::uint8_t {
  139. Unprepared,
  140. Configured,
  141. Playing
  142. };
  143. /* NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding) */
  144. struct SIMDALIGN DeviceBase {
  145. std::atomic<bool> Connected{true};
  146. const DeviceType Type{};
  147. std::string mDeviceName;
  148. uint mSampleRate{};
  149. uint mUpdateSize{};
  150. uint mBufferSize{};
  151. DevFmtChannels FmtChans{};
  152. DevFmtType FmtType{};
  153. uint mAmbiOrder{0};
  154. float mXOverFreq{400.0f};
  155. /* If the main device mix is horizontal/2D only. */
  156. bool m2DMixing{false};
  157. /* For DevFmtAmbi* output only, specifies the channel order and
  158. * normalization.
  159. */
  160. DevAmbiLayout mAmbiLayout{DevAmbiLayout::Default};
  161. DevAmbiScaling mAmbiScale{DevAmbiScaling::Default};
  162. // Device flags
  163. std::bitset<DeviceFlagsCount> Flags;
  164. DeviceState mDeviceState{DeviceState::Unprepared};
  165. uint NumAuxSends{};
  166. /* Rendering mode. */
  167. RenderMode mRenderMode{RenderMode::Normal};
  168. /* The average speaker distance as determined by the ambdec configuration,
  169. * HRTF data set, or the NFC-HOA reference delay. Only used for NFC.
  170. */
  171. float AvgSpeakerDist{0.0f};
  172. /* The default NFC filter. Not used directly, but is pre-initialized with
  173. * the control distance from AvgSpeakerDist.
  174. */
  175. NfcFilter mNFCtrlFilter{};
  176. using seconds32 = std::chrono::duration<int32_t>;
  177. using nanoseconds32 = std::chrono::duration<int32_t, std::nano>;
  178. std::atomic<uint> mSamplesDone{0u};
  179. /* Split the clock to avoid a 64-bit atomic for certain 32-bit targets. */
  180. std::atomic<seconds32> mClockBaseSec{seconds32{}};
  181. std::atomic<nanoseconds32> mClockBaseNSec{nanoseconds32{}};
  182. std::chrono::nanoseconds FixedLatency{0};
  183. AmbiRotateMatrix mAmbiRotateMatrix{};
  184. AmbiRotateMatrix mAmbiRotateMatrix2{};
  185. /* Temp storage used for mixer processing. */
  186. static constexpr std::size_t MixerLineSize{BufferLineSize + DecoderBase::sMaxPadding};
  187. static constexpr std::size_t MixerChannelsMax{16};
  188. alignas(16) std::array<float,MixerLineSize*MixerChannelsMax> mSampleData{};
  189. alignas(16) std::array<float,MixerLineSize+MaxResamplerPadding> mResampleData{};
  190. alignas(16) std::array<float,BufferLineSize> FilteredData{};
  191. alignas(16) std::array<float,BufferLineSize+HrtfHistoryLength> ExtraSampleData{};
  192. /* Persistent storage for HRTF mixing. */
  193. alignas(16) std::array<float2,BufferLineSize+HrirLength> HrtfAccumData{};
  194. /* Mixing buffer used by the Dry mix and Real output. */
  195. al::vector<FloatBufferLine, 16> MixBuffer;
  196. /* The "dry" path corresponds to the main output. */
  197. MixParams Dry;
  198. std::array<uint,MaxAmbiOrder+1> NumChannelsPerOrder{};
  199. /* "Real" output, which will be written to the device buffer. May alias the
  200. * dry buffer.
  201. */
  202. RealMixParams RealOut;
  203. /* HRTF state and info */
  204. std::unique_ptr<DirectHrtfState> mHrtfState;
  205. al::intrusive_ptr<HrtfStore> mHrtf;
  206. uint mIrSize{0};
  207. /* Ambisonic-to-UHJ encoder */
  208. std::unique_ptr<UhjEncoderBase> mUhjEncoder;
  209. /* Ambisonic decoder for speakers */
  210. std::unique_ptr<BFormatDec> AmbiDecoder;
  211. /* Stereo-to-binaural filter */
  212. std::unique_ptr<Bs2b::bs2b> Bs2b;
  213. using PostProc = void(DeviceBase::*)(const size_t SamplesToDo);
  214. PostProc PostProcess{nullptr};
  215. std::unique_ptr<Compressor> Limiter;
  216. /* Delay buffers used to compensate for speaker distances. */
  217. std::unique_ptr<DistanceComp> ChannelDelays;
  218. /* Dithering control. */
  219. float DitherDepth{0.0f};
  220. uint DitherSeed{0u};
  221. /* Running count of the mixer invocations, in 31.1 fixed point. This
  222. * actually increments *twice* when mixing, first at the start and then at
  223. * the end, so the bottom bit indicates if the device is currently mixing
  224. * and the upper bits indicates how many mixes have been done.
  225. */
  226. std::atomic<uint> mMixCount{0u};
  227. // Contexts created on this device
  228. al::atomic_unique_ptr<al::FlexArray<ContextBase*>> mContexts;
  229. [[nodiscard]] auto bytesFromFmt() const noexcept -> uint { return BytesFromDevFmt(FmtType); }
  230. [[nodiscard]] auto channelsFromFmt() const noexcept -> uint { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
  231. [[nodiscard]] auto frameSizeFromFmt() const noexcept -> uint { return bytesFromFmt() * channelsFromFmt(); }
  232. struct MixLock {
  233. DeviceBase *const self;
  234. const uint mEndVal;
  235. MixLock(DeviceBase *device, const uint endval) noexcept : self{device}, mEndVal{endval} { }
  236. MixLock(const MixLock&) = delete;
  237. void operator=(const MixLock&) = delete;
  238. /* Update the mix count when the lock goes out of scope to "release" it
  239. * (lsb should be 0).
  240. */
  241. ~MixLock() { self->mMixCount.store(mEndVal, std::memory_order_release); }
  242. };
  243. auto getWriteMixLock() noexcept -> MixLock
  244. {
  245. /* Increment the mix count at the start of mixing and writing clock
  246. * info (lsb should be 1).
  247. */
  248. const auto oldCount = mMixCount.fetch_add(1u, std::memory_order_acq_rel);
  249. return MixLock{this, oldCount+2};
  250. }
  251. /** Waits for the mixer to not be mixing or updating the clock. */
  252. [[nodiscard]] auto waitForMix() const noexcept -> uint
  253. {
  254. uint refcount{mMixCount.load(std::memory_order_acquire)};
  255. while((refcount&1)) refcount = mMixCount.load(std::memory_order_acquire);
  256. return refcount;
  257. }
  258. /**
  259. * Helper to get the current clock time from the device's ClockBase, and
  260. * SamplesDone converted from the sample rate. Should only be called while
  261. * watching the MixCount.
  262. */
  263. [[nodiscard]] auto getClockTime() const noexcept -> std::chrono::nanoseconds
  264. {
  265. using std::chrono::seconds;
  266. using std::chrono::nanoseconds;
  267. auto ns = nanoseconds{seconds{mSamplesDone.load(std::memory_order_relaxed)}} / mSampleRate;
  268. return nanoseconds{mClockBaseNSec.load(std::memory_order_relaxed)}
  269. + mClockBaseSec.load(std::memory_order_relaxed) + ns;
  270. }
  271. void ProcessHrtf(const std::size_t SamplesToDo);
  272. void ProcessAmbiDec(const std::size_t SamplesToDo);
  273. void ProcessAmbiDecStablized(const std::size_t SamplesToDo);
  274. void ProcessUhj(const std::size_t SamplesToDo);
  275. void ProcessBs2b(const std::size_t SamplesToDo);
  276. void postProcess(const std::size_t SamplesToDo)
  277. { if(PostProcess) LIKELY (this->*PostProcess)(SamplesToDo); }
  278. void renderSamples(const al::span<void*> outBuffers, const uint numSamples);
  279. void renderSamples(void *outBuffer, const uint numSamples, const std::size_t frameStep);
  280. /* Caller must lock the device state, and the mixer must not be running. */
  281. void doDisconnect(std::string msg);
  282. template<typename ...Args>
  283. void handleDisconnect(fmt::format_string<Args...> fmt, Args&& ...args)
  284. { doDisconnect(fmt::format(std::move(fmt), std::forward<Args>(args)...)); }
  285. /**
  286. * Returns the index for the given channel name (e.g. FrontCenter), or
  287. * InvalidChannelIndex if it doesn't exist.
  288. */
  289. [[nodiscard]] auto channelIdxByName(Channel chan) const noexcept -> std::uint8_t
  290. { return RealOut.ChannelIndex[chan]; }
  291. private:
  292. uint renderSamples(const uint numSamples);
  293. protected:
  294. explicit DeviceBase(DeviceType type);
  295. ~DeviceBase();
  296. public:
  297. DeviceBase(const DeviceBase&) = delete;
  298. DeviceBase& operator=(const DeviceBase&) = delete;
  299. };
  300. /* Must be less than 15 characters (16 including terminating null) for
  301. * compatibility with pthread_setname_np limitations. */
  302. [[nodiscard]] constexpr
  303. auto GetMixerThreadName() noexcept -> const char* { return "alsoft-mixer"; }
  304. [[nodiscard]] constexpr
  305. auto GetRecordThreadName() noexcept -> const char* { return "alsoft-record"; }
  306. #endif /* CORE_DEVICE_H */