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.

320 lines
8.2KB

  1. /*
  2. * Carla Ring Buffer
  3. * Copyright (C) 2013-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 CARLA_RING_BUFFER_HPP_INCLUDED
  18. #define CARLA_RING_BUFFER_HPP_INCLUDED
  19. #include "CarlaUtils.hpp"
  20. #if 0 //ndef CARLA_OS_WIN
  21. # include <sys/mman.h>
  22. # ifdef CARLA_OS_MAC
  23. # include <libkern/OSAtomic.h>
  24. # endif
  25. #endif
  26. // -----------------------------------------------------------------------
  27. // RingBuffer structs
  28. struct HeapBuffer {
  29. uint32_t size;
  30. int32_t head, tail, written;
  31. bool invalidateCommit;
  32. char* buf;
  33. HeapBuffer& operator=(const HeapBuffer& rb) noexcept
  34. {
  35. CARLA_SAFE_ASSERT_RETURN(size == rb.size, *this);
  36. size = rb.size;
  37. head = rb.head;
  38. tail = rb.tail;
  39. written = rb.written;
  40. invalidateCommit = rb.invalidateCommit;
  41. std::memcpy(buf, rb.buf, size);
  42. return *this;
  43. }
  44. };
  45. struct StackBuffer {
  46. static const uint32_t size = 4096;
  47. int32_t head, tail, written;
  48. bool invalidateCommit;
  49. char buf[size];
  50. };
  51. // -----------------------------------------------------------------------
  52. // RingBufferControl templated class
  53. template <class BufferStruct>
  54. class RingBufferControl
  55. {
  56. public:
  57. RingBufferControl(BufferStruct* const ringBuf) noexcept
  58. : fBuffer(ringBuf)
  59. {
  60. if (ringBuf != nullptr)
  61. clear();
  62. }
  63. void clear() noexcept
  64. {
  65. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  66. fBuffer->head = 0;
  67. fBuffer->tail = 0;
  68. fBuffer->written = 0;
  69. fBuffer->invalidateCommit = false;
  70. if (fBuffer->size > 0)
  71. carla_zeroChar(fBuffer->buf, fBuffer->size);
  72. }
  73. void setRingBuffer(BufferStruct* const ringBuf, const bool reset) noexcept
  74. {
  75. CARLA_SAFE_ASSERT_RETURN(ringBuf != nullptr,);
  76. CARLA_SAFE_ASSERT_RETURN(ringBuf != fBuffer,);
  77. fBuffer = ringBuf;
  78. if (reset)
  79. clear();
  80. }
  81. // -------------------------------------------------------------------
  82. bool commitWrite() noexcept
  83. {
  84. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  85. if (fBuffer->invalidateCommit)
  86. {
  87. memoryBarrier();
  88. fBuffer->written = fBuffer->head;
  89. fBuffer->invalidateCommit = false;
  90. return false;
  91. }
  92. else
  93. {
  94. fBuffer->head = fBuffer->written;
  95. return true;
  96. }
  97. }
  98. bool isDataAvailable() const noexcept
  99. {
  100. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  101. return (fBuffer->head != fBuffer->tail);
  102. }
  103. #if 0
  104. void lockMemory() const noexcept
  105. {
  106. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  107. #ifdef CARLA_OS_WIN
  108. try {
  109. ::VirtualLock(fBuffer, sizeof(BufferStruct));
  110. ::VirtualLock(fBuffer->buf, fBuffer->size);
  111. } CARLA_SAFE_EXCEPTION("RingBufferControl::lockMemory");
  112. #else
  113. ::mlock(fBuffer, sizeof(BufferStruct));
  114. ::mlock(fBuffer->buf, fBuffer->size);
  115. #endif
  116. }
  117. #endif
  118. // -------------------------------------------------------------------
  119. char readChar() noexcept
  120. {
  121. char c = '\0';
  122. tryRead(&c, sizeof(char));
  123. return c;
  124. }
  125. int32_t readInt() noexcept
  126. {
  127. int32_t i = 0;
  128. tryRead(&i, sizeof(int32_t));
  129. return i;
  130. }
  131. uint32_t readUInt() noexcept
  132. {
  133. int32_t i = -1;
  134. tryRead(&i, sizeof(int32_t));
  135. return (i >= 0) ? static_cast<uint32_t>(i) : 0;
  136. }
  137. int64_t readLong() noexcept
  138. {
  139. int64_t l = 0;
  140. tryRead(&l, sizeof(int64_t));
  141. return l;
  142. }
  143. float readFloat() noexcept
  144. {
  145. float f = 0.0f;
  146. tryRead(&f, sizeof(float));
  147. return f;
  148. }
  149. // -------------------------------------------------------------------
  150. void writeChar(const char value) noexcept
  151. {
  152. tryWrite(&value, sizeof(char));
  153. }
  154. void writeInt(const int32_t value) noexcept
  155. {
  156. tryWrite(&value, sizeof(int32_t));
  157. }
  158. void writeLong(const int64_t value) noexcept
  159. {
  160. tryWrite(&value, sizeof(int64_t));
  161. }
  162. void writeFloat(const float value) noexcept
  163. {
  164. tryWrite(&value, sizeof(float));
  165. }
  166. // -------------------------------------------------------------------
  167. protected:
  168. void tryRead(void* const buf, const size_t size) noexcept
  169. {
  170. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  171. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  172. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  173. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  174. // this should not happen
  175. CARLA_ASSERT(fBuffer->head >= 0);
  176. CARLA_ASSERT(fBuffer->tail >= 0);
  177. CARLA_ASSERT(fBuffer->written >= 0);
  178. // empty
  179. if (fBuffer->head == fBuffer->tail)
  180. return;
  181. char* const charbuf(static_cast<char*>(buf));
  182. const size_t head(static_cast<size_t>(fBuffer->head));
  183. const size_t tail(static_cast<size_t>(fBuffer->tail));
  184. const size_t wrap((head < tail) ? fBuffer->size : 0);
  185. if (head - tail + wrap < size)
  186. {
  187. carla_stderr2("RingBufferControl::tryRead() - failed");
  188. return;
  189. }
  190. size_t readto = tail + size;
  191. if (readto >= fBuffer->size)
  192. {
  193. readto -= fBuffer->size;
  194. const size_t firstpart(fBuffer->size - tail);
  195. std::memcpy(charbuf, fBuffer->buf + tail, firstpart);
  196. std::memcpy(charbuf + firstpart, fBuffer->buf, readto);
  197. }
  198. else
  199. {
  200. std::memcpy(charbuf, fBuffer->buf + tail, size);
  201. }
  202. memoryBarrier();
  203. fBuffer->tail = static_cast<int32_t>(readto);
  204. }
  205. void tryWrite(const void* const buf, const size_t size) noexcept
  206. {
  207. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  208. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  209. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  210. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  211. // this should not happen
  212. CARLA_ASSERT(fBuffer->head >= 0);
  213. CARLA_ASSERT(fBuffer->tail >= 0);
  214. CARLA_ASSERT(fBuffer->written >= 0);
  215. const char* const charbuf(static_cast<const char*>(buf));
  216. const size_t tail(static_cast<size_t>(fBuffer->tail));
  217. const size_t wrtn(static_cast<size_t>(fBuffer->written));
  218. const size_t wrap((tail <= wrtn) ? fBuffer->size : 0);
  219. if (tail - wrtn + wrap <= size)
  220. {
  221. carla_stderr2("RingBufferControl::tryWrite() - buffer full!");
  222. fBuffer->invalidateCommit = true;
  223. return;
  224. }
  225. size_t writeto = wrtn + size;
  226. if (writeto >= fBuffer->size)
  227. {
  228. writeto -= fBuffer->size;
  229. const size_t firstpart(fBuffer->size - wrtn);
  230. std::memcpy(fBuffer->buf + wrtn, charbuf, firstpart);
  231. std::memcpy(fBuffer->buf, charbuf + firstpart, writeto);
  232. }
  233. else
  234. {
  235. std::memcpy(fBuffer->buf + wrtn, charbuf, size);
  236. }
  237. memoryBarrier();
  238. fBuffer->written = static_cast<int32_t>(writeto);
  239. }
  240. private:
  241. BufferStruct* fBuffer;
  242. static void memoryBarrier() noexcept
  243. {
  244. // this breaks win32<=>linux plugin bridges
  245. #if 0
  246. try {
  247. #if defined(CARLA_OS_MAC)
  248. ::OSMemoryBarrier();
  249. #elif defined(CARLA_OS_WIN)
  250. ::MemoryBarrier();
  251. #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 401
  252. ::__sync_synchronize();
  253. #endif
  254. } CARLA_SAFE_EXCEPTION("RingBufferControl::memoryBarrier");
  255. #endif
  256. }
  257. CARLA_PREVENT_HEAP_ALLOCATION
  258. CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl)
  259. };
  260. // -----------------------------------------------------------------------
  261. #endif // CARLA_RING_BUFFER_HPP_INCLUDED