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.

277 lines
7.5KB

  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() noexcept
  27. : RingBufferControl<HeapRingBuffer>(nullptr),
  28. fIsDummy(false)
  29. {
  30. fBuffer.size = 0;
  31. fBuffer.buf = nullptr;
  32. }
  33. ~Lv2AtomRingBufferControl() noexcept
  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) noexcept
  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[]) noexcept
  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() noexcept {}
  123. // -------------------------------------------------------------------
  124. void createBuffer(const uint32_t size) noexcept
  125. {
  126. fRingBufferCtrl.createBuffer(size);
  127. }
  128. // -------------------------------------------------------------------
  129. uint32_t getSize() const noexcept
  130. {
  131. return fRingBufferCtrl.fBuffer.size;
  132. }
  133. bool isEmpty() const noexcept
  134. {
  135. return (fRingBufferCtrl.fBuffer.buf == nullptr || !fRingBufferCtrl.isDataAvailable());
  136. }
  137. // must have been locked before
  138. bool get(const LV2_Atom** const atom, uint32_t* const portIndex) noexcept
  139. {
  140. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false);
  141. if (! fRingBufferCtrl.isDataAvailable())
  142. return false;
  143. if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex))
  144. {
  145. *atom = retAtom;
  146. return true;
  147. }
  148. return false;
  149. }
  150. // must NOT been locked, we do that here
  151. bool put(const LV2_Atom* const atom, const uint32_t portIndex) noexcept
  152. {
  153. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  154. const CarlaMutexLocker cml(fMutex);
  155. return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex));
  156. }
  157. // must NOT been locked, we do that here
  158. bool putChunk(const LV2_Atom* const atom, const void* const data, const uint32_t portIndex) noexcept
  159. {
  160. CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
  161. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  162. const CarlaMutexLocker cml(fMutex);
  163. return fRingBufferCtrl.writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
  164. }
  165. // -------------------------------------------------------------------
  166. void lock() const noexcept
  167. {
  168. fMutex.lock();
  169. }
  170. bool tryLock() const noexcept
  171. {
  172. return fMutex.tryLock();
  173. }
  174. void unlock() const noexcept
  175. {
  176. fMutex.unlock();
  177. }
  178. // -------------------------------------------------------------------
  179. void copyDataFromQueue(Lv2AtomQueue& queue) noexcept
  180. {
  181. // lock source
  182. const CarlaMutexLocker cml1(queue.fMutex);
  183. {
  184. // copy data from source
  185. const CarlaMutexLocker cml2(fMutex);
  186. fRingBufferCtrl.fBuffer = queue.fRingBufferCtrl.fBuffer;
  187. }
  188. // clear source
  189. queue.fRingBufferCtrl.clear();
  190. }
  191. void copyAndDumpDataFromQueue(Lv2AtomQueue& queue, char dumpBuf[]) noexcept
  192. {
  193. // lock source
  194. const CarlaMutexLocker cml1(queue.fMutex);
  195. {
  196. // copy data from source
  197. const CarlaMutexLocker cml2(fMutex);
  198. fRingBufferCtrl.copyDump(queue.fRingBufferCtrl.fBuffer, dumpBuf);
  199. }
  200. // clear source
  201. queue.fRingBufferCtrl.clear();
  202. }
  203. // -------------------------------------------------------------------
  204. private:
  205. CarlaMutex fMutex;
  206. Lv2AtomRingBufferControl fRingBufferCtrl;
  207. CARLA_PREVENT_HEAP_ALLOCATION
  208. CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomQueue)
  209. };
  210. // -----------------------------------------------------------------------
  211. #endif // LV2_ATOM_QUEUE_HPP_INCLUDED