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.

279 lines
7.4KB

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