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.

315 lines
8.1KB

  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. #ifndef 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. void lockMemory() const noexcept
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  106. #ifdef CARLA_OS_WIN
  107. try {
  108. ::VirtualLock(fBuffer, sizeof(BufferStruct));
  109. ::VirtualLock(fBuffer->buf, fBuffer->size);
  110. } CARLA_SAFE_EXCEPTION("RingBufferControl::lockMemory");
  111. #else
  112. ::mlock(fBuffer, sizeof(BufferStruct));
  113. ::mlock(fBuffer->buf, fBuffer->size);
  114. #endif
  115. }
  116. // -------------------------------------------------------------------
  117. char readChar() noexcept
  118. {
  119. char c = '\0';
  120. tryRead(&c, sizeof(char));
  121. return c;
  122. }
  123. int32_t readInt() noexcept
  124. {
  125. int32_t i = 0;
  126. tryRead(&i, sizeof(int32_t));
  127. return i;
  128. }
  129. uint32_t readUInt() noexcept
  130. {
  131. int32_t i = -1;
  132. tryRead(&i, sizeof(int32_t));
  133. return (i >= 0) ? static_cast<uint32_t>(i) : 0;
  134. }
  135. int64_t readLong() noexcept
  136. {
  137. int64_t l = 0;
  138. tryRead(&l, sizeof(int64_t));
  139. return l;
  140. }
  141. float readFloat() noexcept
  142. {
  143. float f = 0.0f;
  144. tryRead(&f, sizeof(float));
  145. return f;
  146. }
  147. // -------------------------------------------------------------------
  148. void writeChar(const char value) noexcept
  149. {
  150. tryWrite(&value, sizeof(char));
  151. }
  152. void writeInt(const int32_t value) noexcept
  153. {
  154. tryWrite(&value, sizeof(int32_t));
  155. }
  156. void writeLong(const int64_t value) noexcept
  157. {
  158. tryWrite(&value, sizeof(int64_t));
  159. }
  160. void writeFloat(const float value) noexcept
  161. {
  162. tryWrite(&value, sizeof(float));
  163. }
  164. // -------------------------------------------------------------------
  165. protected:
  166. void tryRead(void* const buf, const size_t size) noexcept
  167. {
  168. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  169. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  170. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  171. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  172. // this should not happen
  173. CARLA_ASSERT(fBuffer->head >= 0);
  174. CARLA_ASSERT(fBuffer->tail >= 0);
  175. CARLA_ASSERT(fBuffer->written >= 0);
  176. // empty
  177. if (fBuffer->head == fBuffer->tail)
  178. return;
  179. char* const charbuf(static_cast<char*>(buf));
  180. const size_t head(static_cast<size_t>(fBuffer->head));
  181. const size_t tail(static_cast<size_t>(fBuffer->tail));
  182. const size_t wrap((head < tail) ? fBuffer->size : 0);
  183. if (head - tail + wrap < size)
  184. {
  185. carla_stderr2("RingBufferControl::tryRead() - failed");
  186. return;
  187. }
  188. size_t readto = tail + size;
  189. if (readto >= fBuffer->size)
  190. {
  191. readto -= fBuffer->size;
  192. const size_t firstpart(fBuffer->size - tail);
  193. std::memcpy(charbuf, fBuffer->buf + tail, firstpart);
  194. std::memcpy(charbuf + firstpart, fBuffer->buf, readto);
  195. }
  196. else
  197. {
  198. std::memcpy(charbuf, fBuffer->buf + tail, size);
  199. }
  200. memoryBarrier();
  201. fBuffer->tail = static_cast<int32_t>(readto);
  202. }
  203. void tryWrite(const void* const buf, const size_t size) noexcept
  204. {
  205. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  206. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  207. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  208. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  209. // this should not happen
  210. CARLA_ASSERT(fBuffer->head >= 0);
  211. CARLA_ASSERT(fBuffer->tail >= 0);
  212. CARLA_ASSERT(fBuffer->written >= 0);
  213. const char* const charbuf(static_cast<const char*>(buf));
  214. const size_t tail(static_cast<size_t>(fBuffer->tail));
  215. const size_t wrtn(static_cast<size_t>(fBuffer->written));
  216. const size_t wrap((tail <= wrtn) ? fBuffer->size : 0);
  217. if (tail - wrtn + wrap <= size)
  218. {
  219. carla_stderr2("RingBufferControl::tryWrite() - buffer full!");
  220. fBuffer->invalidateCommit = true;
  221. return;
  222. }
  223. size_t writeto = wrtn + size;
  224. if (writeto >= fBuffer->size)
  225. {
  226. writeto -= fBuffer->size;
  227. const size_t firstpart(fBuffer->size - wrtn);
  228. std::memcpy(fBuffer->buf + wrtn, charbuf, firstpart);
  229. std::memcpy(fBuffer->buf, charbuf + firstpart, writeto);
  230. }
  231. else
  232. {
  233. std::memcpy(fBuffer->buf + wrtn, charbuf, size);
  234. }
  235. memoryBarrier();
  236. fBuffer->written = static_cast<int32_t>(writeto);
  237. }
  238. private:
  239. BufferStruct* fBuffer;
  240. static void memoryBarrier() noexcept
  241. {
  242. try {
  243. #if defined(CARLA_OS_MAC)
  244. ::OSMemoryBarrier();
  245. #elif defined(CARLA_OS_WIN)
  246. ::MemoryBarrier();
  247. #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 401
  248. ::__sync_synchronize();
  249. #endif
  250. } CARLA_SAFE_EXCEPTION("RingBufferControl::memoryBarrier");
  251. }
  252. CARLA_PREVENT_HEAP_ALLOCATION
  253. CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl)
  254. };
  255. // -----------------------------------------------------------------------
  256. #endif // CARLA_RING_BUFFER_HPP_INCLUDED