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.

479 lines
12KB

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