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.

215 lines
6.0KB

  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. fRetAtom{{0,0}, {0}} {}
  31. Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
  32. : fMutex(),
  33. fHeapBuffer(HeapBuffer_INIT),
  34. fNeedsDataDelete(false),
  35. fRetAtom{{0,0}, {0}}
  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.clear();
  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) 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. }
  66. void deleteBuffer() noexcept
  67. {
  68. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
  69. CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
  70. setRingBuffer(nullptr, false);
  71. delete[] fHeapBuffer.buf;
  72. fHeapBuffer.buf = nullptr;
  73. fHeapBuffer.size = 0;
  74. }
  75. uint32_t getSize() const noexcept
  76. {
  77. return fHeapBuffer.size;
  78. }
  79. // -------------------------------------------------------------------
  80. bool tryLock() const noexcept
  81. {
  82. return fMutex.tryLock();
  83. }
  84. void unlock() const noexcept
  85. {
  86. fMutex.unlock();
  87. }
  88. // -------------------------------------------------------------------
  89. // NOTE: must have been locked before
  90. bool get(const LV2_Atom*& atom, uint32_t& portIndex) noexcept
  91. {
  92. if (const LV2_Atom* const retAtom = readAtom(portIndex))
  93. {
  94. atom = retAtom;
  95. return true;
  96. }
  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. const LV2_Atom* readAtom(uint32_t& portIndex) noexcept
  117. {
  118. fRetAtom.atom.size = 0;
  119. fRetAtom.atom.type = 0;
  120. if (! tryRead(&fRetAtom.atom, sizeof(LV2_Atom)))
  121. return nullptr;
  122. if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0)
  123. return nullptr;
  124. CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < kMaxAtomDataSize, nullptr);
  125. int32_t index = -1;
  126. if (! tryRead(&index, sizeof(int32_t)))
  127. return nullptr;
  128. if (index < 0)
  129. return nullptr;
  130. if (! tryRead(fRetAtom.data, fRetAtom.atom.size))
  131. return nullptr;
  132. portIndex = static_cast<uint32_t>(index);
  133. return &fRetAtom.atom;
  134. }
  135. // -------------------------------------------------------------------
  136. bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
  137. {
  138. tryWrite(atom, sizeof(LV2_Atom));
  139. tryWrite(&portIndex, sizeof(int32_t));
  140. tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
  141. return commitWrite();
  142. }
  143. bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
  144. {
  145. tryWrite(atom, sizeof(LV2_Atom));
  146. 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. static const size_t kMaxAtomDataSize = 8192;
  156. struct RetAtom {
  157. LV2_Atom atom;
  158. char data[kMaxAtomDataSize];
  159. } fRetAtom;
  160. friend class Lv2AtomQueue;
  161. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  162. CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomRingBuffer)
  163. };
  164. // -----------------------------------------------------------------------
  165. #endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED