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.

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