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.

285 lines
7.5KB

  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. // -----------------------------------------------------------------------
  21. // RingBuffer structs
  22. struct HeapRingBuffer {
  23. uint32_t size;
  24. int32_t head, tail, written;
  25. bool invalidateCommit;
  26. char* buf;
  27. HeapRingBuffer& operator=(const HeapRingBuffer& rb)
  28. {
  29. CARLA_SAFE_ASSERT_RETURN(size == rb.size, *this);
  30. size = rb.size;
  31. head = rb.head;
  32. tail = rb.tail;
  33. written = rb.written;
  34. invalidateCommit = rb.invalidateCommit;
  35. std::memcpy(buf, rb.buf, size);
  36. return *this;
  37. }
  38. };
  39. struct StackRingBuffer {
  40. static const uint32_t size = 4096;
  41. int32_t head, tail, written;
  42. bool invalidateCommit;
  43. char buf[size];
  44. };
  45. PRE_PACKED_STRUCTURE
  46. struct StackPackedRingBuffer {
  47. static const uint32_t size = 4096;
  48. int32_t head, tail, written;
  49. bool invalidateCommit;
  50. char buf[size];
  51. } POST_PACKED_STRUCTURE;
  52. // -----------------------------------------------------------------------
  53. // RingBufferControl templated class
  54. template <class RingBufferStruct>
  55. class RingBufferControl
  56. {
  57. public:
  58. RingBufferControl(RingBufferStruct* const ringBuf) noexcept
  59. : fRingBuf(ringBuf)
  60. {
  61. if (ringBuf != nullptr)
  62. clear();
  63. }
  64. void clear() noexcept
  65. {
  66. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  67. fRingBuf->head = 0;
  68. fRingBuf->tail = 0;
  69. fRingBuf->written = 0;
  70. fRingBuf->invalidateCommit = false;
  71. if (fRingBuf->size > 0)
  72. carla_zeroChar(fRingBuf->buf, fRingBuf->size);
  73. }
  74. void setRingBuffer(RingBufferStruct* const ringBuf, const bool reset) noexcept
  75. {
  76. CARLA_SAFE_ASSERT_RETURN(ringBuf != nullptr,);
  77. CARLA_SAFE_ASSERT_RETURN(ringBuf != fRingBuf,);
  78. fRingBuf = ringBuf;
  79. if (reset)
  80. clear();
  81. }
  82. // -------------------------------------------------------------------
  83. bool commitWrite() noexcept
  84. {
  85. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr, false);
  86. if (fRingBuf->invalidateCommit)
  87. {
  88. fRingBuf->written = fRingBuf->head;
  89. fRingBuf->invalidateCommit = false;
  90. return false;
  91. }
  92. else
  93. {
  94. fRingBuf->head = fRingBuf->written;
  95. return true;
  96. }
  97. }
  98. bool isDataAvailable() const noexcept
  99. {
  100. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr, false);
  101. return (fRingBuf->head != fRingBuf->tail);
  102. }
  103. // -------------------------------------------------------------------
  104. char readChar() noexcept
  105. {
  106. char c = '\0';
  107. tryRead(&c, sizeof(char));
  108. return c;
  109. }
  110. int32_t readInt() noexcept
  111. {
  112. int32_t i = 0;
  113. tryRead(&i, sizeof(int32_t));
  114. return i;
  115. }
  116. uint32_t readUInt() noexcept
  117. {
  118. int32_t i = -1;
  119. tryRead(&i, sizeof(int32_t));
  120. return (i >= 0) ? static_cast<uint32_t>(i) : 0;
  121. }
  122. int64_t readLong() noexcept
  123. {
  124. int64_t l = 0;
  125. tryRead(&l, sizeof(int64_t));
  126. return l;
  127. }
  128. float readFloat() noexcept
  129. {
  130. float f = 0.0f;
  131. tryRead(&f, sizeof(float));
  132. return f;
  133. }
  134. // -------------------------------------------------------------------
  135. void writeChar(const char value) noexcept
  136. {
  137. tryWrite(&value, sizeof(char));
  138. }
  139. void writeInt(const int32_t value) noexcept
  140. {
  141. tryWrite(&value, sizeof(int32_t));
  142. }
  143. void writeLong(const int64_t value) noexcept
  144. {
  145. tryWrite(&value, sizeof(int64_t));
  146. }
  147. void writeFloat(const float value) noexcept
  148. {
  149. tryWrite(&value, sizeof(float));
  150. }
  151. // -------------------------------------------------------------------
  152. protected:
  153. void tryRead(void* const buf, const size_t size) noexcept
  154. {
  155. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  156. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  157. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  158. CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,);
  159. // this should not happen
  160. CARLA_ASSERT(fRingBuf->head >= 0);
  161. CARLA_ASSERT(fRingBuf->tail >= 0);
  162. CARLA_ASSERT(fRingBuf->written >= 0);
  163. // empty
  164. if (fRingBuf->head == fRingBuf->tail)
  165. return;
  166. char* const charbuf(static_cast<char*>(buf));
  167. const size_t head(static_cast<size_t>(fRingBuf->head));
  168. const size_t tail(static_cast<size_t>(fRingBuf->tail));
  169. const size_t wrap((head < tail) ? fRingBuf->size : 0);
  170. if (head - tail + wrap < size)
  171. {
  172. carla_stderr2("RingBufferControl::tryRead() - failed");
  173. return;
  174. }
  175. size_t readto = tail + size;
  176. if (readto >= fRingBuf->size)
  177. {
  178. readto -= fRingBuf->size;
  179. const size_t firstpart(fRingBuf->size - tail);
  180. std::memcpy(charbuf, fRingBuf->buf + tail, firstpart);
  181. std::memcpy(charbuf + firstpart, fRingBuf->buf, readto);
  182. }
  183. else
  184. {
  185. std::memcpy(charbuf, fRingBuf->buf + tail, size);
  186. }
  187. fRingBuf->tail = static_cast<int32_t>(readto);
  188. }
  189. void tryWrite(const void* const buf, const size_t size) noexcept
  190. {
  191. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  192. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  193. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  194. CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,);
  195. // this should not happen
  196. CARLA_ASSERT(fRingBuf->head >= 0);
  197. CARLA_ASSERT(fRingBuf->tail >= 0);
  198. CARLA_ASSERT(fRingBuf->written >= 0);
  199. const char* const charbuf(static_cast<const char*>(buf));
  200. const size_t tail(static_cast<size_t>(fRingBuf->tail));
  201. const size_t wrtn(static_cast<size_t>(fRingBuf->written));
  202. const size_t wrap((tail <= wrtn) ? fRingBuf->size : 0);
  203. if (tail - wrtn + wrap <= size)
  204. {
  205. carla_stderr2("RingBufferControl::tryWrite() - buffer full!");
  206. fRingBuf->invalidateCommit = true;
  207. return;
  208. }
  209. size_t writeto = wrtn + size;
  210. if (writeto >= fRingBuf->size)
  211. {
  212. writeto -= fRingBuf->size;
  213. const size_t firstpart(fRingBuf->size - wrtn);
  214. std::memcpy(fRingBuf->buf + wrtn, charbuf, firstpart);
  215. std::memcpy(fRingBuf->buf, charbuf + firstpart, writeto);
  216. }
  217. else
  218. {
  219. std::memcpy(fRingBuf->buf + wrtn, charbuf, size);
  220. }
  221. fRingBuf->written = static_cast<int32_t>(writeto);
  222. }
  223. private:
  224. RingBufferStruct* fRingBuf;
  225. CARLA_PREVENT_HEAP_ALLOCATION
  226. CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl)
  227. };
  228. // -----------------------------------------------------------------------
  229. #endif // CARLA_RING_BUFFER_HPP_INCLUDED