🛠️🐜 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.

138 lines
4.3 KiB

  1. #include "config.h"
  2. #include <memory>
  3. #include "async_event.h"
  4. #include "context.h"
  5. #include "device.h"
  6. #include "effectslot.h"
  7. #include "logging.h"
  8. #include "ringbuffer.h"
  9. #include "voice.h"
  10. #include "voice_change.h"
  11. ContextBase::ContextBase(DeviceBase *device) : mDevice{device}
  12. { }
  13. ContextBase::~ContextBase()
  14. {
  15. size_t count{0};
  16. ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)};
  17. if(cprops)
  18. {
  19. ++count;
  20. delete cprops;
  21. }
  22. cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire);
  23. while(cprops)
  24. {
  25. std::unique_ptr<ContextProps> old{cprops};
  26. cprops = old->next.load(std::memory_order_relaxed);
  27. ++count;
  28. }
  29. TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s");
  30. count = 0;
  31. EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)};
  32. while(eprops)
  33. {
  34. std::unique_ptr<EffectSlotProps> old{eprops};
  35. eprops = old->next.load(std::memory_order_relaxed);
  36. ++count;
  37. }
  38. TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
  39. if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
  40. {
  41. al::destroy_n(curarray->end(), curarray->size());
  42. delete curarray;
  43. }
  44. delete mVoices.exchange(nullptr, std::memory_order_relaxed);
  45. if(mAsyncEvents)
  46. {
  47. count = 0;
  48. auto evt_vec = mAsyncEvents->getReadVector();
  49. if(evt_vec.first.len > 0)
  50. {
  51. al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf), evt_vec.first.len);
  52. count += evt_vec.first.len;
  53. }
  54. if(evt_vec.second.len > 0)
  55. {
  56. al::destroy_n(reinterpret_cast<AsyncEvent*>(evt_vec.second.buf), evt_vec.second.len);
  57. count += evt_vec.second.len;
  58. }
  59. if(count > 0)
  60. TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s");
  61. mAsyncEvents->readAdvance(count);
  62. }
  63. }
  64. void ContextBase::allocVoiceChanges()
  65. {
  66. constexpr size_t clustersize{128};
  67. VoiceChangeCluster cluster{std::make_unique<VoiceChange[]>(clustersize)};
  68. for(size_t i{1};i < clustersize;++i)
  69. cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  70. cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed);
  71. mVoiceChangeClusters.emplace_back(std::move(cluster));
  72. mVoiceChangeTail = mVoiceChangeClusters.back().get();
  73. }
  74. void ContextBase::allocVoiceProps()
  75. {
  76. constexpr size_t clustersize{32};
  77. TRACE("Increasing allocated voice properties to %zu\n",
  78. (mVoicePropClusters.size()+1) * clustersize);
  79. VoicePropsCluster cluster{std::make_unique<VoicePropsItem[]>(clustersize)};
  80. for(size_t i{1};i < clustersize;++i)
  81. cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
  82. mVoicePropClusters.emplace_back(std::move(cluster));
  83. VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
  84. do {
  85. mVoicePropClusters.back()[clustersize-1].next.store(oldhead, std::memory_order_relaxed);
  86. } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back().get(),
  87. std::memory_order_acq_rel, std::memory_order_acquire) == false);
  88. }
  89. void ContextBase::allocVoices(size_t addcount)
  90. {
  91. constexpr size_t clustersize{32};
  92. /* Convert element count to cluster count. */
  93. addcount = (addcount+(clustersize-1)) / clustersize;
  94. if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size())
  95. throw std::runtime_error{"Allocating too many voices"};
  96. const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize};
  97. TRACE("Increasing allocated voices to %zu\n", totalcount);
  98. auto newarray = VoiceArray::Create(totalcount);
  99. while(addcount)
  100. {
  101. mVoiceClusters.emplace_back(std::make_unique<Voice[]>(clustersize));
  102. --addcount;
  103. }
  104. auto voice_iter = newarray->begin();
  105. for(VoiceCluster &cluster : mVoiceClusters)
  106. {
  107. for(size_t i{0};i < clustersize;++i)
  108. *(voice_iter++) = &cluster[i];
  109. }
  110. if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel))
  111. {
  112. mDevice->waitForMix();
  113. delete oldvoices;
  114. }
  115. }