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.

227 lines
6.2KB

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