🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.6 KiB

  1. #ifndef CORE_CONTEXT_H
  2. #define CORE_CONTEXT_H
  3. #include <array>
  4. #include <atomic>
  5. #include <cstddef>
  6. #include <memory>
  7. #include <thread>
  8. #include "almalloc.h"
  9. #include "alspan.h"
  10. #include "atomic.h"
  11. #include "bufferline.h"
  12. #include "threads.h"
  13. #include "vecmat.h"
  14. #include "vector.h"
  15. struct DeviceBase;
  16. struct EffectSlot;
  17. struct EffectSlotProps;
  18. struct RingBuffer;
  19. struct Voice;
  20. struct VoiceChange;
  21. struct VoicePropsItem;
  22. using uint = unsigned int;
  23. constexpr float SpeedOfSoundMetersPerSec{343.3f};
  24. constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
  25. enum class DistanceModel : unsigned char {
  26. Disable,
  27. Inverse, InverseClamped,
  28. Linear, LinearClamped,
  29. Exponent, ExponentClamped,
  30. Default = InverseClamped
  31. };
  32. struct WetBuffer {
  33. bool mInUse;
  34. al::FlexArray<FloatBufferLine, 16> mBuffer;
  35. WetBuffer(size_t count) : mBuffer{count} { }
  36. DEF_FAM_NEWDEL(WetBuffer, mBuffer)
  37. };
  38. using WetBufferPtr = std::unique_ptr<WetBuffer>;
  39. struct ContextProps {
  40. std::array<float,3> Position;
  41. std::array<float,3> Velocity;
  42. std::array<float,3> OrientAt;
  43. std::array<float,3> OrientUp;
  44. float Gain;
  45. float MetersPerUnit;
  46. float AirAbsorptionGainHF;
  47. float DopplerFactor;
  48. float DopplerVelocity;
  49. float SpeedOfSound;
  50. bool SourceDistanceModel;
  51. DistanceModel mDistanceModel;
  52. std::atomic<ContextProps*> next;
  53. DEF_NEWDEL(ContextProps)
  54. };
  55. struct ContextParams {
  56. /* Pointer to the most recent property values that are awaiting an update. */
  57. std::atomic<ContextProps*> ContextUpdate{nullptr};
  58. alu::Vector Position{};
  59. alu::Matrix Matrix{alu::Matrix::Identity()};
  60. alu::Vector Velocity{};
  61. float Gain{1.0f};
  62. float MetersPerUnit{1.0f};
  63. float AirAbsorptionGainHF{AirAbsorbGainHF};
  64. float DopplerFactor{1.0f};
  65. float SpeedOfSound{SpeedOfSoundMetersPerSec}; /* in units per sec! */
  66. bool SourceDistanceModel{false};
  67. DistanceModel mDistanceModel{};
  68. };
  69. struct ContextBase {
  70. DeviceBase *const mDevice;
  71. /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
  72. * indicates if updates are currently happening).
  73. */
  74. RefCount mUpdateCount{0u};
  75. std::atomic<bool> mHoldUpdates{false};
  76. std::atomic<bool> mStopVoicesOnDisconnect{true};
  77. float mGainBoost{1.0f};
  78. /* Linked lists of unused property containers, free to use for future
  79. * updates.
  80. */
  81. std::atomic<ContextProps*> mFreeContextProps{nullptr};
  82. std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
  83. std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr};
  84. /* The voice change tail is the beginning of the "free" elements, up to and
  85. * *excluding* the current. If tail==current, there's no free elements and
  86. * new ones need to be allocated. The current voice change is the element
  87. * last processed, and any after are pending.
  88. */
  89. VoiceChange *mVoiceChangeTail{};
  90. std::atomic<VoiceChange*> mCurrentVoiceChange{};
  91. void allocVoiceChanges();
  92. void allocVoiceProps();
  93. ContextParams mParams;
  94. using VoiceArray = al::FlexArray<Voice*>;
  95. std::atomic<VoiceArray*> mVoices{};
  96. std::atomic<size_t> mActiveVoiceCount{};
  97. void allocVoices(size_t addcount);
  98. al::span<Voice*> getVoicesSpan() const noexcept
  99. {
  100. return {mVoices.load(std::memory_order_relaxed)->data(),
  101. mActiveVoiceCount.load(std::memory_order_relaxed)};
  102. }
  103. al::span<Voice*> getVoicesSpanAcquired() const noexcept
  104. {
  105. return {mVoices.load(std::memory_order_acquire)->data(),
  106. mActiveVoiceCount.load(std::memory_order_acquire)};
  107. }
  108. using EffectSlotArray = al::FlexArray<EffectSlot*>;
  109. std::atomic<EffectSlotArray*> mActiveAuxSlots{nullptr};
  110. std::thread mEventThread;
  111. al::semaphore mEventSem;
  112. std::unique_ptr<RingBuffer> mAsyncEvents;
  113. std::atomic<uint> mEnabledEvts{0u};
  114. /* Asynchronous voice change actions are processed as a linked list of
  115. * VoiceChange objects by the mixer, which is atomically appended to.
  116. * However, to avoid allocating each object individually, they're allocated
  117. * in clusters that are stored in a vector for easy automatic cleanup.
  118. */
  119. using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
  120. al::vector<VoiceChangeCluster> mVoiceChangeClusters;
  121. using VoiceCluster = std::unique_ptr<Voice[]>;
  122. al::vector<VoiceCluster> mVoiceClusters;
  123. using VoicePropsCluster = std::unique_ptr<VoicePropsItem[]>;
  124. al::vector<VoicePropsCluster> mVoicePropClusters;
  125. ContextBase(DeviceBase *device);
  126. ContextBase(const ContextBase&) = delete;
  127. ContextBase& operator=(const ContextBase&) = delete;
  128. ~ContextBase();
  129. };
  130. #endif /* CORE_CONTEXT_H */