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.

504 lines
13KB

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