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.

222 lines
6.3KB

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