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.

248 lines
6.6KB

  1. /*
  2. * Carla Ring Buffer based on dssi-vst code
  3. * Copyright (C) 2004-2010 Chris Cannam <cannam@all-day-breakfast.com>
  4. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  17. */
  18. #ifndef CARLA_RING_BUFFER_HPP_INCLUDED
  19. #define CARLA_RING_BUFFER_HPP_INCLUDED
  20. #include "CarlaUtils.hpp"
  21. //#ifndef RING_BUFFER_SIZE
  22. #define RING_BUFFER_SIZE 2048
  23. //#endif
  24. // -----------------------------------------------------------------------
  25. // RingBuffer struct
  26. struct RingBuffer {
  27. int32_t head, tail, written;
  28. bool invalidateCommit;
  29. char buf[RING_BUFFER_SIZE];
  30. };
  31. // -----------------------------------------------------------------------
  32. // RingBufferControl class
  33. class RingBufferControl
  34. {
  35. public:
  36. RingBufferControl(RingBuffer* const ringBuf) noexcept
  37. : fRingBuf(ringBuf)
  38. {
  39. if (ringBuf != nullptr)
  40. clear();
  41. }
  42. void clear() noexcept
  43. {
  44. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  45. fRingBuf->head = 0;
  46. fRingBuf->tail = 0;
  47. fRingBuf->written = 0;
  48. fRingBuf->invalidateCommit = false;
  49. carla_zeroChar(fRingBuf->buf, RING_BUFFER_SIZE);
  50. }
  51. void setRingBuffer(RingBuffer* const ringBuf, const bool reset) noexcept
  52. {
  53. CARLA_SAFE_ASSERT_RETURN(ringBuf != nullptr,);
  54. CARLA_SAFE_ASSERT_RETURN(ringBuf != fRingBuf,);
  55. fRingBuf = ringBuf;
  56. if (reset)
  57. clear();
  58. }
  59. // -------------------------------------------------------------------
  60. bool commitWrite() noexcept
  61. {
  62. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr, false);
  63. if (fRingBuf->invalidateCommit)
  64. {
  65. fRingBuf->written = fRingBuf->head;
  66. fRingBuf->invalidateCommit = false;
  67. return false;
  68. }
  69. else
  70. {
  71. fRingBuf->head = fRingBuf->written;
  72. return true;
  73. }
  74. }
  75. bool isDataAvailable() const noexcept
  76. {
  77. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr, false);
  78. return (fRingBuf->head != fRingBuf->tail);
  79. }
  80. // -------------------------------------------------------------------
  81. char readChar() noexcept
  82. {
  83. char c = '\0';
  84. tryRead(&c, sizeof(char));
  85. return c;
  86. }
  87. int32_t readInt() noexcept
  88. {
  89. int32_t i = 0;
  90. tryRead(&i, sizeof(int32_t));
  91. return i;
  92. }
  93. int64_t readLong() noexcept
  94. {
  95. int64_t l = 0;
  96. tryRead(&l, sizeof(int64_t));
  97. return l;
  98. }
  99. float readFloat() noexcept
  100. {
  101. float f = 0.0f;
  102. tryRead(&f, sizeof(float));
  103. return f;
  104. }
  105. // -------------------------------------------------------------------
  106. void writeChar(const char value) noexcept
  107. {
  108. tryWrite(&value, sizeof(char));
  109. }
  110. void writeInt(const int32_t value) noexcept
  111. {
  112. tryWrite(&value, sizeof(int32_t));
  113. }
  114. void writeLong(const int64_t value) noexcept
  115. {
  116. tryWrite(&value, sizeof(int64_t));
  117. }
  118. void writeFloat(const float value) noexcept
  119. {
  120. tryWrite(&value, sizeof(float));
  121. }
  122. // -------------------------------------------------------------------
  123. protected:
  124. void tryRead(void* const buf, const size_t size) noexcept
  125. {
  126. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  127. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  128. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  129. // this should not happen
  130. CARLA_ASSERT(fRingBuf->head >= 0);
  131. CARLA_ASSERT(fRingBuf->tail >= 0);
  132. CARLA_ASSERT(fRingBuf->written >= 0);
  133. // empty
  134. if (fRingBuf->head == fRingBuf->tail)
  135. return;
  136. char* const charbuf(static_cast<char*>(buf));
  137. const size_t head(static_cast<size_t>(fRingBuf->head));
  138. const size_t tail(static_cast<size_t>(fRingBuf->tail));
  139. const size_t wrap((head < tail) ? RING_BUFFER_SIZE : 0);
  140. if (head - tail + wrap < size)
  141. {
  142. carla_stderr2("RingBufferControl::tryRead() - failed");
  143. return;
  144. }
  145. size_t readto = tail + size;
  146. if (readto >= RING_BUFFER_SIZE)
  147. {
  148. readto -= RING_BUFFER_SIZE;
  149. const size_t firstpart(RING_BUFFER_SIZE - tail);
  150. std::memcpy(charbuf, fRingBuf->buf + tail, firstpart);
  151. std::memcpy(charbuf + firstpart, fRingBuf->buf, readto);
  152. }
  153. else
  154. {
  155. std::memcpy(charbuf, fRingBuf->buf + tail, size);
  156. }
  157. fRingBuf->tail = static_cast<int32_t>(readto);
  158. }
  159. void tryWrite(const void* const buf, const size_t size) noexcept
  160. {
  161. CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
  162. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  163. CARLA_SAFE_ASSERT_RETURN(size != 0,);
  164. // this should not happen
  165. CARLA_ASSERT(fRingBuf->head >= 0);
  166. CARLA_ASSERT(fRingBuf->tail >= 0);
  167. CARLA_ASSERT(fRingBuf->written >= 0);
  168. const char* const charbuf(static_cast<const char*>(buf));
  169. const size_t tail(static_cast<size_t>(fRingBuf->tail));
  170. const size_t wrtn(static_cast<size_t>(fRingBuf->written));
  171. const size_t wrap((tail <= wrtn) ? RING_BUFFER_SIZE : 0);
  172. if (tail - wrtn + wrap <= size)
  173. {
  174. carla_stderr2("RingBufferControl::tryWrite() - buffer full!");
  175. fRingBuf->invalidateCommit = true;
  176. return;
  177. }
  178. size_t writeto = wrtn + size;
  179. if (writeto >= RING_BUFFER_SIZE)
  180. {
  181. writeto -= RING_BUFFER_SIZE;
  182. const size_t firstpart(RING_BUFFER_SIZE - wrtn);
  183. std::memcpy(fRingBuf->buf + wrtn, charbuf, firstpart);
  184. std::memcpy(fRingBuf->buf, charbuf + firstpart, writeto);
  185. }
  186. else
  187. {
  188. std::memcpy(fRingBuf->buf + wrtn, charbuf, size);
  189. }
  190. fRingBuf->written = static_cast<int32_t>(writeto);
  191. }
  192. private:
  193. RingBuffer* fRingBuf;
  194. CARLA_PREVENT_HEAP_ALLOCATION
  195. CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl)
  196. };
  197. // -----------------------------------------------------------------------
  198. #endif // CARLA_RING_BUFFER_HPP_INCLUDED