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.

CarlaRingBuffer.hpp 12KB

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