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.

287 lines
7.8KB

  1. /*
  2. * Simple Queue, specially developed for Atom types
  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_QUEUE_HPP_INCLUDED
  18. #define LV2_ATOM_QUEUE_HPP_INCLUDED
  19. #include "CarlaMathUtils.hpp"
  20. #include "CarlaMutex.hpp"
  21. #include "CarlaRingBuffer.hpp"
  22. #include "lv2/atom.h"
  23. // -----------------------------------------------------------------------
  24. class Lv2AtomRingBufferControl : public RingBufferControl<HeapBuffer>
  25. {
  26. public:
  27. Lv2AtomRingBufferControl() noexcept
  28. : RingBufferControl<HeapBuffer>(nullptr),
  29. fIsDummy(false)
  30. {
  31. fLv2Buffer.size = 0;
  32. fLv2Buffer.buf = nullptr;
  33. }
  34. ~Lv2AtomRingBufferControl() noexcept
  35. {
  36. if (fLv2Buffer.buf != nullptr && ! fIsDummy)
  37. {
  38. delete[] fLv2Buffer.buf;
  39. fLv2Buffer.buf = nullptr;
  40. }
  41. }
  42. // -------------------------------------------------------------------
  43. void createBuffer(const uint32_t size) noexcept
  44. {
  45. if (fLv2Buffer.size == size && ! fIsDummy)
  46. return;
  47. if (fLv2Buffer.buf != nullptr)
  48. {
  49. if (! fIsDummy)
  50. delete[] fLv2Buffer.buf;
  51. fLv2Buffer.buf = nullptr;
  52. }
  53. // shouldn't really happen please...
  54. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  55. const uint32_t p2size(carla_nextPowerOf2(size));
  56. try {
  57. fLv2Buffer.buf = new char[p2size];
  58. } CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBufferControl::createBuffer",);
  59. fLv2Buffer.size = p2size;
  60. setRingBuffer(&fLv2Buffer, true);
  61. //lockMemory();
  62. }
  63. // used for tmp buffers only
  64. void copyDump(HeapBuffer& rb, char dumpBuf[]) noexcept
  65. {
  66. CARLA_SAFE_ASSERT_RETURN(fLv2Buffer.size == 0,);
  67. CARLA_SAFE_ASSERT_RETURN(fLv2Buffer.buf == nullptr,);
  68. fLv2Buffer.buf = dumpBuf;
  69. fLv2Buffer.size = rb.size;
  70. fLv2Buffer.head = rb.head;
  71. fLv2Buffer.tail = rb.tail;
  72. fLv2Buffer.written = rb.written;
  73. fLv2Buffer.invalidateCommit = rb.invalidateCommit;
  74. fIsDummy = true;
  75. std::memcpy(dumpBuf, rb.buf, rb.size);
  76. setRingBuffer(&fLv2Buffer, false);
  77. }
  78. // -------------------------------------------------------------------
  79. const LV2_Atom* readAtom(uint32_t* const portIndex) noexcept
  80. {
  81. fRetAtom.atom.size = 0;
  82. fRetAtom.atom.type = 0;
  83. tryRead(&fRetAtom.atom, sizeof(LV2_Atom));
  84. if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0)
  85. return nullptr;
  86. CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < kMaxDataSize, nullptr);
  87. int32_t index = -1;
  88. tryRead(&index, sizeof(int32_t));
  89. if (index < 0)
  90. return nullptr;
  91. if (portIndex != nullptr)
  92. *portIndex = static_cast<uint32_t>(index);
  93. carla_zeroChar(fRetAtom.data, fRetAtom.atom.size);
  94. tryRead(fRetAtom.data, fRetAtom.atom.size);
  95. return &fRetAtom.atom;
  96. }
  97. // -------------------------------------------------------------------
  98. bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
  99. {
  100. tryWrite(atom, sizeof(LV2_Atom));
  101. tryWrite(&portIndex, sizeof(int32_t));
  102. tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
  103. return commitWrite();
  104. }
  105. bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
  106. {
  107. tryWrite(atom, sizeof(LV2_Atom));
  108. tryWrite(&portIndex, sizeof(int32_t));
  109. tryWrite(data, atom->size);
  110. return commitWrite();
  111. }
  112. // -------------------------------------------------------------------
  113. private:
  114. HeapBuffer fLv2Buffer;
  115. bool fIsDummy;
  116. static const size_t kMaxDataSize = 8192;
  117. struct RetAtom {
  118. LV2_Atom atom;
  119. char data[kMaxDataSize];
  120. } fRetAtom;
  121. friend class Lv2AtomQueue;
  122. CARLA_PREVENT_HEAP_ALLOCATION
  123. CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomRingBufferControl)
  124. };
  125. // -----------------------------------------------------------------------
  126. class Lv2AtomQueue
  127. {
  128. public:
  129. Lv2AtomQueue() noexcept {}
  130. // -------------------------------------------------------------------
  131. void createBuffer(const uint32_t size) noexcept
  132. {
  133. fRingBufferCtrl.createBuffer(size);
  134. }
  135. // -------------------------------------------------------------------
  136. uint32_t getSize() const noexcept
  137. {
  138. return fRingBufferCtrl.fLv2Buffer.size;
  139. }
  140. bool isEmpty() const noexcept
  141. {
  142. return (fRingBufferCtrl.fLv2Buffer.buf == nullptr || !fRingBufferCtrl.isDataAvailable());
  143. }
  144. // must have been locked before
  145. bool get(const LV2_Atom** const atom, uint32_t* const portIndex) noexcept
  146. {
  147. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false);
  148. if (! fRingBufferCtrl.isDataAvailable())
  149. return false;
  150. if (const LV2_Atom* const retAtom = fRingBufferCtrl.readAtom(portIndex))
  151. {
  152. *atom = retAtom;
  153. return true;
  154. }
  155. return false;
  156. }
  157. // must NOT been locked, we do that here
  158. bool put(const LV2_Atom* const atom, const uint32_t portIndex) noexcept
  159. {
  160. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  161. const CarlaMutexLocker cml(fMutex);
  162. return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex));
  163. }
  164. // must NOT been locked, we do that here
  165. bool putChunk(const LV2_Atom* const atom, const void* const data, const uint32_t portIndex) noexcept
  166. {
  167. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  168. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  169. const CarlaMutexLocker cml(fMutex);
  170. return fRingBufferCtrl.writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
  171. }
  172. // -------------------------------------------------------------------
  173. void lock() const noexcept
  174. {
  175. fMutex.lock();
  176. }
  177. bool tryLock() const noexcept
  178. {
  179. return fMutex.tryLock();
  180. }
  181. void unlock() const noexcept
  182. {
  183. fMutex.unlock();
  184. }
  185. // -------------------------------------------------------------------
  186. void copyDataFromQueue(Lv2AtomQueue& queue) noexcept
  187. {
  188. // lock source
  189. const CarlaMutexLocker cml1(queue.fMutex);
  190. {
  191. // copy data from source
  192. const CarlaMutexLocker cml2(fMutex);
  193. fRingBufferCtrl.fLv2Buffer = queue.fRingBufferCtrl.fLv2Buffer;
  194. }
  195. // clear source
  196. queue.fRingBufferCtrl.clear();
  197. }
  198. // used for tmp buffers only
  199. void copyAndDumpDataFromQueue(Lv2AtomQueue& queue, char dumpBuf[]) noexcept
  200. {
  201. // source is locked
  202. {
  203. // copy data from source
  204. const CarlaMutexLocker cml2(fMutex);
  205. fRingBufferCtrl.copyDump(queue.fRingBufferCtrl.fLv2Buffer, dumpBuf);
  206. }
  207. // clear source
  208. queue.fRingBufferCtrl.clear();
  209. }
  210. // -------------------------------------------------------------------
  211. private:
  212. CarlaMutex fMutex;
  213. Lv2AtomRingBufferControl fRingBufferCtrl;
  214. CARLA_PREVENT_HEAP_ALLOCATION
  215. CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomQueue)
  216. };
  217. // -----------------------------------------------------------------------
  218. #endif // LV2_ATOM_QUEUE_HPP_INCLUDED