Audio plugin host https://kx.studio/carla
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.

213 lines
6.4KB

  1. /*
  2. * LV2 Atom Ring Buffer
  3. * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef LV2_ATOM_RING_BUFFER_HPP_INCLUDED
  18. #define LV2_ATOM_RING_BUFFER_HPP_INCLUDED
  19. #include "CarlaMutex.hpp"
  20. #include "CarlaRingBuffer.hpp"
  21. #include "lv2/atom.h"
  22. // --------------------------------------------------------------------------------------------------------------------
  23. class Lv2AtomRingBuffer : public CarlaRingBufferControl<HeapBuffer>
  24. {
  25. public:
  26. Lv2AtomRingBuffer() noexcept
  27. : fMutex(),
  28. fHeapBuffer{0, 0, 0, 0, false, nullptr},
  29. fNeedsDataDelete(true)
  30. {
  31. }
  32. Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
  33. : fMutex(),
  34. fHeapBuffer{0, 0, 0, 0, false, nullptr},
  35. fNeedsDataDelete(false)
  36. {
  37. fHeapBuffer.buf = buf;
  38. fHeapBuffer.size = ringBuf.fHeapBuffer.size;
  39. {
  40. const CarlaMutexLocker cml(ringBuf.fMutex);
  41. fHeapBuffer.copyDataFrom(ringBuf.fHeapBuffer);
  42. ringBuf.clearData();
  43. }
  44. setRingBuffer(&fHeapBuffer, false);
  45. }
  46. ~Lv2AtomRingBuffer() noexcept
  47. {
  48. if (fHeapBuffer.buf == nullptr || ! fNeedsDataDelete)
  49. return;
  50. delete[] fHeapBuffer.buf;
  51. fHeapBuffer.buf = nullptr;
  52. }
  53. // ----------------------------------------------------------------------------------------------------------------
  54. void createBuffer(const uint32_t size, const bool mlock) noexcept
  55. {
  56. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
  57. CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
  58. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  59. const uint32_t p2size = carla_nextPowerOf2(size);
  60. try {
  61. fHeapBuffer.buf = new uint8_t[p2size];
  62. } CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBuffer::createBuffer",);
  63. fHeapBuffer.size = p2size;
  64. setRingBuffer(&fHeapBuffer, true);
  65. if (mlock)
  66. {
  67. carla_mlock(&fHeapBuffer, sizeof(fHeapBuffer));
  68. carla_mlock(fHeapBuffer.buf, p2size);
  69. }
  70. }
  71. void deleteBuffer() noexcept
  72. {
  73. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
  74. CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
  75. setRingBuffer(nullptr, false);
  76. delete[] fHeapBuffer.buf;
  77. fHeapBuffer.buf = nullptr;
  78. fHeapBuffer.size = 0;
  79. }
  80. uint32_t getSize() const noexcept
  81. {
  82. return fHeapBuffer.size;
  83. }
  84. // ----------------------------------------------------------------------------------------------------------------
  85. bool tryLock() const noexcept
  86. {
  87. return fMutex.tryLock();
  88. }
  89. void unlock() const noexcept
  90. {
  91. fMutex.unlock();
  92. }
  93. // ----------------------------------------------------------------------------------------------------------------
  94. // NOTE: must have been locked before
  95. bool get(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
  96. {
  97. if (readAtom(portIndex, retAtom))
  98. return true;
  99. retAtom->size = retAtom->type = 0;
  100. return false;
  101. }
  102. // NOTE: must NOT been locked, we do that here
  103. bool put(const LV2_Atom* const atom, const uint32_t portIndex) noexcept
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  106. const CarlaMutexLocker cml(fMutex);
  107. return writeAtom(atom, static_cast<int32_t>(portIndex));
  108. }
  109. // NOTE: must NOT been locked, we do that here
  110. bool putChunk(const LV2_Atom* const atom, const void* const data, const uint32_t portIndex) noexcept
  111. {
  112. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  113. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  114. const CarlaMutexLocker cml(fMutex);
  115. return writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
  116. }
  117. protected:
  118. // ----------------------------------------------------------------------------------------------------------------
  119. bool readAtom(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
  120. {
  121. const uint32_t maxAtomSize = retAtom->size - sizeof(LV2_Atom);
  122. LV2_Atom atom = {};
  123. if (! tryRead(&atom, sizeof(LV2_Atom)))
  124. return false;
  125. if (atom.size == 0 || atom.type == 0)
  126. return false;
  127. CARLA_SAFE_ASSERT_UINT2_RETURN(atom.size < maxAtomSize, atom.size, maxAtomSize, false);
  128. int32_t index = -1;
  129. if (! tryRead(&index, sizeof(int32_t)))
  130. return false;
  131. if (index < 0)
  132. return false;
  133. if (! tryRead(retAtom + 1, atom.size))
  134. return false;
  135. portIndex = static_cast<uint32_t>(index);
  136. retAtom->size = atom.size;
  137. retAtom->type = atom.type;
  138. return true;
  139. }
  140. // ----------------------------------------------------------------------------------------------------------------
  141. bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
  142. {
  143. if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
  144. tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
  145. return commitWrite();
  146. }
  147. bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
  148. {
  149. if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
  150. tryWrite(data, atom->size);
  151. return commitWrite();
  152. }
  153. // ----------------------------------------------------------------------------------------------------------------
  154. private:
  155. CarlaMutex fMutex;
  156. HeapBuffer fHeapBuffer;
  157. const bool fNeedsDataDelete;
  158. friend class Lv2AtomQueue;
  159. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  160. CARLA_DECLARE_NON_COPYABLE(Lv2AtomRingBuffer)
  161. };
  162. // --------------------------------------------------------------------------------------------------------------------
  163. #endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED