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.

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