device.h 11 KB

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