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.

210 lines
5.9KB

  1. /*
  2. * LV2 Atom Ring Buffer
  3. * Copyright (C) 2012-2022 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(HeapBuffer_INIT),
  29. fNeedsDataDelete(true)
  30. {
  31. carla_zeroStruct(fHeapBuffer);
  32. }
  33. Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
  34. : fMutex(),
  35. fHeapBuffer(HeapBuffer_INIT),
  36. fNeedsDataDelete(false)
  37. {
  38. carla_zeroStruct(fHeapBuffer);
  39. fHeapBuffer.buf = buf;
  40. fHeapBuffer.size = ringBuf.fHeapBuffer.size;
  41. {
  42. const CarlaMutexLocker cml(ringBuf.fMutex);
  43. fHeapBuffer.copyDataFrom(ringBuf.fHeapBuffer);
  44. ringBuf.clearData();
  45. }
  46. setRingBuffer(&fHeapBuffer, false);
  47. }
  48. ~Lv2AtomRingBuffer() noexcept
  49. {
  50. if (fHeapBuffer.buf == nullptr || ! fNeedsDataDelete)
  51. return;
  52. delete[] fHeapBuffer.buf;
  53. fHeapBuffer.buf = nullptr;
  54. }
  55. // -------------------------------------------------------------------
  56. void createBuffer(const uint32_t size) noexcept
  57. {
  58. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
  59. CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
  60. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  61. const uint32_t p2size(carla_nextPowerOf2(size));
  62. try {
  63. fHeapBuffer.buf = new uint8_t[p2size];
  64. } CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBuffer::createBuffer",);
  65. fHeapBuffer.size = p2size;
  66. setRingBuffer(&fHeapBuffer, true);
  67. }
  68. void deleteBuffer() noexcept
  69. {
  70. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
  71. CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
  72. setRingBuffer(nullptr, false);
  73. delete[] fHeapBuffer.buf;
  74. fHeapBuffer.buf = nullptr;
  75. fHeapBuffer.size = 0;
  76. }
  77. uint32_t getSize() const noexcept
  78. {
  79. return fHeapBuffer.size;
  80. }
  81. // -------------------------------------------------------------------
  82. bool tryLock() const noexcept
  83. {
  84. return fMutex.tryLock();
  85. }
  86. void unlock() const noexcept
  87. {
  88. fMutex.unlock();
  89. }
  90. // -------------------------------------------------------------------
  91. // NOTE: must have been locked before
  92. bool get(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
  93. {
  94. if (readAtom(portIndex, retAtom))
  95. return true;
  96. retAtom->size = retAtom->type = 0;
  97. return false;
  98. }
  99. // NOTE: must NOT been locked, we do that here
  100. bool put(const LV2_Atom* const atom, const uint32_t portIndex) noexcept
  101. {
  102. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  103. const CarlaMutexLocker cml(fMutex);
  104. return writeAtom(atom, static_cast<int32_t>(portIndex));
  105. }
  106. // NOTE: must NOT been locked, we do that here
  107. bool putChunk(const LV2_Atom* const atom, const void* const data, const uint32_t portIndex) noexcept
  108. {
  109. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  110. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  111. const CarlaMutexLocker cml(fMutex);
  112. return writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
  113. }
  114. protected:
  115. // -------------------------------------------------------------------
  116. bool readAtom(uint32_t& portIndex, LV2_Atom* const retAtom) noexcept
  117. {
  118. const uint32_t maxAtomSize = retAtom->size - sizeof(LV2_Atom);
  119. LV2_Atom atom = {};
  120. if (! tryRead(&atom, sizeof(LV2_Atom)))
  121. return false;
  122. if (atom.size == 0 || atom.type == 0)
  123. return false;
  124. CARLA_SAFE_ASSERT_UINT2_RETURN(atom.size < maxAtomSize, atom.size, maxAtomSize, false);
  125. int32_t index = -1;
  126. if (! tryRead(&index, sizeof(int32_t)))
  127. return false;
  128. if (index < 0)
  129. return false;
  130. if (! tryRead(retAtom + 1, atom.size))
  131. return false;
  132. portIndex = static_cast<uint32_t>(index);
  133. retAtom->size = atom.size;
  134. retAtom->type = atom.type;
  135. return true;
  136. }
  137. // -------------------------------------------------------------------
  138. bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
  139. {
  140. if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
  141. tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
  142. return commitWrite();
  143. }
  144. bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
  145. {
  146. if (tryWrite(atom, sizeof(LV2_Atom)) && tryWrite(&portIndex, sizeof(int32_t)))
  147. tryWrite(data, atom->size);
  148. return commitWrite();
  149. }
  150. // -------------------------------------------------------------------
  151. private:
  152. CarlaMutex fMutex;
  153. HeapBuffer fHeapBuffer;
  154. const bool fNeedsDataDelete;
  155. friend class Lv2AtomQueue;
  156. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  157. CARLA_DECLARE_NON_COPYABLE(Lv2AtomRingBuffer)
  158. };
  159. // -----------------------------------------------------------------------
  160. #endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED