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.

441 lines
11KB

  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 "CarlaMathUtils.hpp"
  20. // -----------------------------------------------------------------------
  21. // Buffer structs
  22. /*
  23. head:
  24. current writing position, headmost position of the buffer.
  25. increments when writing.
  26. tail:
  27. current reading position, last used position of the buffer.
  28. increments when reading.
  29. head == tail means empty buffer
  30. wrtn:
  31. temporary position of head until a commitWrite() is called.
  32. if buffer writing fails, wrtn will be back to head position thus ignoring the last operation(s).
  33. if buffer writing succeeds, head will be set to this variable.
  34. invalidateCommit:
  35. boolean used to check if a write operation failed.
  36. this ensures we don't get incomplete writes.
  37. */
  38. struct HeapBuffer {
  39. uint32_t size;
  40. std::size_t head, tail, wrtn;
  41. bool invalidateCommit;
  42. uint8_t* buf;
  43. void copyDataFrom(const HeapBuffer& rb) noexcept
  44. {
  45. CARLA_SAFE_ASSERT_RETURN(size == rb.size,);
  46. head = rb.head;
  47. tail = rb.tail;
  48. wrtn = rb.wrtn;
  49. invalidateCommit = rb.invalidateCommit;
  50. std::memcpy(buf, rb.buf, size);
  51. }
  52. };
  53. struct StackBuffer {
  54. static const uint32_t size = 4096;
  55. std::size_t head, tail, wrtn;
  56. bool invalidateCommit;
  57. uint8_t buf[size];
  58. };
  59. // -----------------------------------------------------------------------
  60. // CarlaRingBuffer templated class
  61. template <class BufferStruct>
  62. class CarlaRingBuffer
  63. {
  64. public:
  65. CarlaRingBuffer() noexcept
  66. : fBuffer(nullptr) {}
  67. CarlaRingBuffer(BufferStruct* const ringBuf) noexcept
  68. : fBuffer(ringBuf)
  69. {
  70. if (ringBuf != nullptr)
  71. clear();
  72. }
  73. void clear() noexcept
  74. {
  75. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  76. fBuffer->head = 0;
  77. fBuffer->tail = 0;
  78. fBuffer->wrtn = 0;
  79. fBuffer->invalidateCommit = false;
  80. carla_zeroBytes(fBuffer->buf, fBuffer->size);
  81. }
  82. // -------------------------------------------------------------------
  83. bool commitWrite() noexcept
  84. {
  85. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  86. if (fBuffer->invalidateCommit)
  87. {
  88. fBuffer->wrtn = fBuffer->head;
  89. fBuffer->invalidateCommit = false;
  90. return false;
  91. }
  92. // nothing to commit?
  93. CARLA_SAFE_ASSERT_RETURN(fBuffer->head != fBuffer->wrtn, false);
  94. // all ok
  95. fBuffer->head = fBuffer->wrtn;
  96. return true;
  97. }
  98. bool isDataAvailableForReading() const noexcept
  99. {
  100. return (fBuffer != nullptr && fBuffer->buf != nullptr && fBuffer->head != fBuffer->tail);
  101. }
  102. bool isEmpty() const noexcept
  103. {
  104. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  105. return (fBuffer->buf == nullptr || fBuffer->head == fBuffer->tail);
  106. }
  107. // -------------------------------------------------------------------
  108. bool readBool() noexcept
  109. {
  110. bool b = false;
  111. return tryRead(&b, sizeof(bool)) ? b : false;
  112. }
  113. int8_t readByte() noexcept
  114. {
  115. int8_t b = 0;
  116. return tryRead(&b, sizeof(int8_t)) ? b : 0;
  117. }
  118. uint8_t readUByte() noexcept
  119. {
  120. int8_t ub = -1;
  121. return (tryRead(&ub, sizeof(int8_t)) && ub >= 0 && ub <= INT_LEAST8_MAX) ? static_cast<uint8_t>(ub) : 0;
  122. }
  123. int16_t readShort() noexcept
  124. {
  125. int16_t s = 0;
  126. return tryRead(&s, sizeof(int16_t)) ? s : 0;
  127. }
  128. uint16_t readUShort() noexcept
  129. {
  130. int16_t us = -1;
  131. return (tryRead(&us, sizeof(int16_t)) && us >= 0 && us <= INT_LEAST16_MAX) ? static_cast<uint16_t>(us) : 0;
  132. }
  133. int32_t readInt() noexcept
  134. {
  135. int32_t i = 0;
  136. return tryRead(&i, sizeof(int32_t)) ? i : 0;
  137. }
  138. uint32_t readUInt() noexcept
  139. {
  140. int32_t ui = -1;
  141. return (tryRead(&ui, sizeof(int32_t)) && ui >= 0 && ui <= INT_LEAST32_MAX) ? static_cast<uint32_t>(ui) : 0;
  142. }
  143. int64_t readLong() noexcept
  144. {
  145. int64_t l = 0;
  146. return tryRead(&l, sizeof(int64_t)) ? l : 0;
  147. }
  148. uint64_t readULong() noexcept
  149. {
  150. int64_t ul = -1;
  151. return (tryRead(&ul, sizeof(int64_t)) && ul >= 0 && ul <= INT_LEAST64_MAX) ? static_cast<uint64_t>(ul) : 0;
  152. }
  153. float readFloat() noexcept
  154. {
  155. float f = 0.0f;
  156. return tryRead(&f, sizeof(float)) ? f : 0.0f;
  157. }
  158. double readDouble() noexcept
  159. {
  160. double d = 0.0;
  161. return tryRead(&d, sizeof(double)) ? d : 0.0;
  162. }
  163. void readCustomData(void* const data, const std::size_t size) noexcept
  164. {
  165. if (! tryRead(data, size))
  166. carla_zeroBytes(data, size);
  167. }
  168. template <typename T>
  169. void readCustomType(T& type) noexcept
  170. {
  171. if (! tryRead(&type, sizeof(T)))
  172. carla_zeroStruct(type);
  173. }
  174. // -------------------------------------------------------------------
  175. void writeBool(const bool value) noexcept
  176. {
  177. tryWrite(&value, sizeof(bool));
  178. }
  179. void writeByte(const int8_t value) noexcept
  180. {
  181. tryWrite(&value, sizeof(int8_t));
  182. }
  183. void writeShort(const int16_t value) noexcept
  184. {
  185. tryWrite(&value, sizeof(int16_t));
  186. }
  187. void writeInt(const int32_t value) noexcept
  188. {
  189. tryWrite(&value, sizeof(int32_t));
  190. }
  191. void writeLong(const int64_t value) noexcept
  192. {
  193. tryWrite(&value, sizeof(int64_t));
  194. }
  195. void writeFloat(const float value) noexcept
  196. {
  197. tryWrite(&value, sizeof(float));
  198. }
  199. void writeDouble(const double value) noexcept
  200. {
  201. tryWrite(&value, sizeof(double));
  202. }
  203. void writeCustomData(const void* const value, const std::size_t size) noexcept
  204. {
  205. tryWrite(value, size);
  206. }
  207. template <typename T>
  208. void writeCustomType(const T& value) noexcept
  209. {
  210. tryWrite(&value, sizeof(T));
  211. }
  212. // -------------------------------------------------------------------
  213. protected:
  214. void setRingBuffer(BufferStruct* const ringBuf, const bool reset) noexcept
  215. {
  216. CARLA_SAFE_ASSERT_RETURN(ringBuf != fBuffer,);
  217. fBuffer = ringBuf;
  218. if (reset && ringBuf != nullptr)
  219. clear();
  220. }
  221. // -------------------------------------------------------------------
  222. bool tryRead(void* const buf, const std::size_t size) noexcept
  223. {
  224. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  225. CARLA_SAFE_ASSERT_RETURN(buf != nullptr, false);
  226. CARLA_SAFE_ASSERT_RETURN(size > 0, false);
  227. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size, false);
  228. // empty
  229. if (fBuffer->head == fBuffer->tail)
  230. return false;
  231. uint8_t* const bytebuf(static_cast<uint8_t*>(buf));
  232. const std::size_t head(fBuffer->head);
  233. const std::size_t tail(fBuffer->tail);
  234. const std::size_t wrap((head > tail) ? 0 : fBuffer->size);
  235. if (size > wrap + head - tail)
  236. {
  237. carla_stderr2("CarlaRingBuffer::tryRead(%p, " P_SIZE "): failed, not enough space", buf, size);
  238. return false;
  239. }
  240. std::size_t readto(tail + size);
  241. if (readto > fBuffer->size)
  242. {
  243. readto -= fBuffer->size;
  244. const std::size_t firstpart(fBuffer->size - tail);
  245. std::memcpy(bytebuf, fBuffer->buf + tail, firstpart);
  246. std::memcpy(bytebuf + firstpart, fBuffer->buf, readto);
  247. }
  248. else
  249. {
  250. std::memcpy(bytebuf, fBuffer->buf + tail, size);
  251. if (readto == fBuffer->size)
  252. readto = 0;
  253. }
  254. fBuffer->tail = readto;
  255. return true;
  256. }
  257. void tryWrite(const void* const buf, const std::size_t size) noexcept
  258. {
  259. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  260. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  261. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  262. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  263. const uint8_t* const bytebuf(static_cast<const uint8_t*>(buf));
  264. const std::size_t tail(fBuffer->tail);
  265. const std::size_t wrtn(fBuffer->wrtn);
  266. const std::size_t wrap((tail > wrtn) ? 0 : fBuffer->size);
  267. if (size >= wrap + tail - wrtn)
  268. {
  269. carla_stderr2("CarlaRingBuffer::tryWrite(%p, " P_SIZE "): failed, not enough space", buf, size);
  270. fBuffer->invalidateCommit = true;
  271. return;
  272. }
  273. std::size_t writeto(wrtn + size);
  274. if (writeto > fBuffer->size)
  275. {
  276. writeto -= fBuffer->size;
  277. const std::size_t firstpart(fBuffer->size - wrtn);
  278. std::memcpy(fBuffer->buf + wrtn, bytebuf, firstpart);
  279. std::memcpy(fBuffer->buf, bytebuf + firstpart, writeto);
  280. }
  281. else
  282. {
  283. std::memcpy(fBuffer->buf + wrtn, bytebuf, size);
  284. if (writeto == fBuffer->size)
  285. writeto = 0;
  286. }
  287. fBuffer->wrtn = writeto;
  288. }
  289. private:
  290. BufferStruct* fBuffer;
  291. CARLA_PREVENT_HEAP_ALLOCATION
  292. CARLA_DECLARE_NON_COPY_CLASS(CarlaRingBuffer)
  293. };
  294. // -----------------------------------------------------------------------
  295. // CarlaRingBuffer using heap space
  296. class CarlaHeapRingBuffer : public CarlaRingBuffer<HeapBuffer>
  297. {
  298. public:
  299. CarlaHeapRingBuffer() noexcept
  300. : CarlaRingBuffer<HeapBuffer>()
  301. {
  302. carla_zeroStruct(fHeapBuffer);
  303. }
  304. ~CarlaHeapRingBuffer() noexcept
  305. {
  306. if (fHeapBuffer.buf == nullptr)
  307. return;
  308. delete[] fHeapBuffer.buf;
  309. fHeapBuffer.buf = nullptr;
  310. }
  311. void createBuffer(const uint32_t size) noexcept
  312. {
  313. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
  314. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  315. const uint32_t p2size(carla_nextPowerOf2(size));
  316. try {
  317. fHeapBuffer.buf = new uint8_t[p2size];
  318. } CARLA_SAFE_EXCEPTION_RETURN("CarlaHeapRingBuffer::createBuffer",);
  319. fHeapBuffer.size = p2size;
  320. setRingBuffer(&fHeapBuffer, true);
  321. }
  322. void deleteBuffer() noexcept
  323. {
  324. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
  325. setRingBuffer(nullptr, false);
  326. delete[] fHeapBuffer.buf;
  327. fHeapBuffer.buf = nullptr;
  328. fHeapBuffer.size = 0;
  329. }
  330. private:
  331. HeapBuffer fHeapBuffer;
  332. CARLA_PREVENT_HEAP_ALLOCATION
  333. CARLA_DECLARE_NON_COPY_CLASS(CarlaHeapRingBuffer)
  334. };
  335. // -----------------------------------------------------------------------
  336. // CarlaRingBuffer using stack space
  337. class CarlaStackRingBuffer : public CarlaRingBuffer<StackBuffer>
  338. {
  339. public:
  340. CarlaStackRingBuffer() noexcept
  341. : CarlaRingBuffer<StackBuffer>(&fStackBuffer) {}
  342. private:
  343. StackBuffer fStackBuffer;
  344. CARLA_PREVENT_HEAP_ALLOCATION
  345. CARLA_DECLARE_NON_COPY_CLASS(CarlaStackRingBuffer)
  346. };
  347. // -----------------------------------------------------------------------
  348. #endif // CARLA_RING_BUFFER_HPP_INCLUDED