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 11KB

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
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
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
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
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
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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. // -----------------------------------------------------------------------
  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. uint8_t readByte() noexcept
  114. {
  115. int8_t ub = -1;
  116. return (tryRead(&ub, sizeof(int8_t)) && ub >= 0 && ub <= INT_LEAST8_MAX) ? static_cast<uint8_t>(ub) : 0;
  117. }
  118. int16_t readShort() noexcept
  119. {
  120. int16_t s = 0;
  121. return tryRead(&s, sizeof(int16_t)) ? s : 0;
  122. }
  123. uint16_t readUShort() noexcept
  124. {
  125. int16_t us = -1;
  126. return (tryRead(&us, sizeof(int16_t)) && us >= 0 && us <= INT_LEAST16_MAX) ? static_cast<uint16_t>(us) : 0;
  127. }
  128. int32_t readInt() noexcept
  129. {
  130. int32_t i = 0;
  131. return tryRead(&i, sizeof(int32_t)) ? i : 0;
  132. }
  133. uint32_t readUInt() noexcept
  134. {
  135. int32_t ui = -1;
  136. return (tryRead(&ui, sizeof(int32_t)) && ui >= 0 && ui <= INT_LEAST32_MAX) ? static_cast<uint32_t>(ui) : 0;
  137. }
  138. int64_t readLong() noexcept
  139. {
  140. int64_t l = 0;
  141. return tryRead(&l, sizeof(int64_t)) ? l : 0;
  142. }
  143. uint64_t readULong() noexcept
  144. {
  145. int64_t ul = -1;
  146. return (tryRead(&ul, sizeof(int64_t)) && ul >= 0 && ul <= INT_LEAST64_MAX) ? static_cast<uint64_t>(ul) : 0;
  147. }
  148. float readFloat() noexcept
  149. {
  150. float f = 0.0f;
  151. return tryRead(&f, sizeof(float)) ? f : 0.0f;
  152. }
  153. double readDouble() noexcept
  154. {
  155. double d = 0.0;
  156. return tryRead(&d, sizeof(double)) ? d : 0.0;
  157. }
  158. void readCustomData(void* const data, const uint32_t size) noexcept
  159. {
  160. if (! tryRead(data, size))
  161. carla_zeroBytes(data, size);
  162. }
  163. template <typename T>
  164. void readCustomType(T& type) noexcept
  165. {
  166. if (! tryRead(&type, sizeof(T)))
  167. carla_zeroStruct(type);
  168. }
  169. // -------------------------------------------------------------------
  170. void writeBool(const bool value) noexcept
  171. {
  172. tryWrite(&value, sizeof(bool));
  173. }
  174. void writeByte(const uint8_t value) noexcept
  175. {
  176. tryWrite(&value, sizeof(uint8_t));
  177. }
  178. void writeShort(const int16_t value) noexcept
  179. {
  180. tryWrite(&value, sizeof(int16_t));
  181. }
  182. void writeInt(const int32_t value) noexcept
  183. {
  184. tryWrite(&value, sizeof(int32_t));
  185. }
  186. void writeLong(const int64_t value) noexcept
  187. {
  188. tryWrite(&value, sizeof(int64_t));
  189. }
  190. void writeFloat(const float value) noexcept
  191. {
  192. tryWrite(&value, sizeof(float));
  193. }
  194. void writeDouble(const double value) noexcept
  195. {
  196. tryWrite(&value, sizeof(double));
  197. }
  198. void writeCustomData(const void* const value, const uint32_t size) noexcept
  199. {
  200. tryWrite(value, size);
  201. }
  202. template <typename T>
  203. void writeCustomType(const T& value) noexcept
  204. {
  205. tryWrite(&value, sizeof(T));
  206. }
  207. // -------------------------------------------------------------------
  208. protected:
  209. void setRingBuffer(BufferStruct* const ringBuf, const bool reset) noexcept
  210. {
  211. CARLA_SAFE_ASSERT_RETURN(ringBuf != fBuffer,);
  212. fBuffer = ringBuf;
  213. if (reset && ringBuf != nullptr)
  214. clear();
  215. }
  216. // -------------------------------------------------------------------
  217. bool tryRead(void* const buf, const uint32_t size) noexcept
  218. {
  219. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
  220. CARLA_SAFE_ASSERT_RETURN(buf != nullptr, false);
  221. CARLA_SAFE_ASSERT_RETURN(size > 0, false);
  222. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size, false);
  223. // empty
  224. if (fBuffer->head == fBuffer->tail)
  225. return false;
  226. uint8_t* const bytebuf(static_cast<uint8_t*>(buf));
  227. const uint32_t head(fBuffer->head);
  228. const uint32_t tail(fBuffer->tail);
  229. const uint32_t wrap((head > tail) ? 0 : fBuffer->size);
  230. if (size > wrap + head - tail)
  231. {
  232. carla_stderr2("CarlaRingBuffer::tryRead(%p, " P_SIZE "): failed, not enough space", buf, size);
  233. return false;
  234. }
  235. uint32_t readto(tail + size);
  236. if (readto > fBuffer->size)
  237. {
  238. readto -= fBuffer->size;
  239. const uint32_t firstpart(fBuffer->size - tail);
  240. std::memcpy(bytebuf, fBuffer->buf + tail, firstpart);
  241. std::memcpy(bytebuf + firstpart, fBuffer->buf, readto);
  242. }
  243. else
  244. {
  245. std::memcpy(bytebuf, fBuffer->buf + tail, size);
  246. if (readto == fBuffer->size)
  247. readto = 0;
  248. }
  249. fBuffer->tail = readto;
  250. return true;
  251. }
  252. void tryWrite(const void* const buf, const uint32_t size) noexcept
  253. {
  254. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  255. CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
  256. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  257. CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);
  258. const uint8_t* const bytebuf(static_cast<const uint8_t*>(buf));
  259. const uint32_t tail(fBuffer->tail);
  260. const uint32_t wrtn(fBuffer->wrtn);
  261. const uint32_t wrap((tail > wrtn) ? 0 : fBuffer->size);
  262. if (size >= wrap + tail - wrtn)
  263. {
  264. carla_stderr2("CarlaRingBuffer::tryWrite(%p, " P_SIZE "): failed, not enough space", buf, size);
  265. fBuffer->invalidateCommit = true;
  266. return;
  267. }
  268. uint32_t writeto(wrtn + size);
  269. if (writeto > fBuffer->size)
  270. {
  271. writeto -= fBuffer->size;
  272. const uint32_t firstpart(fBuffer->size - wrtn);
  273. std::memcpy(fBuffer->buf + wrtn, bytebuf, firstpart);
  274. std::memcpy(fBuffer->buf, bytebuf + firstpart, writeto);
  275. }
  276. else
  277. {
  278. std::memcpy(fBuffer->buf + wrtn, bytebuf, size);
  279. if (writeto == fBuffer->size)
  280. writeto = 0;
  281. }
  282. fBuffer->wrtn = writeto;
  283. }
  284. private:
  285. BufferStruct* fBuffer;
  286. CARLA_PREVENT_HEAP_ALLOCATION
  287. CARLA_DECLARE_NON_COPY_CLASS(CarlaRingBuffer)
  288. };
  289. // -----------------------------------------------------------------------
  290. // CarlaRingBuffer using heap space
  291. class CarlaHeapRingBuffer : public CarlaRingBuffer<HeapBuffer>
  292. {
  293. public:
  294. CarlaHeapRingBuffer() noexcept
  295. : CarlaRingBuffer<HeapBuffer>()
  296. {
  297. carla_zeroStruct(fHeapBuffer);
  298. }
  299. ~CarlaHeapRingBuffer() noexcept
  300. {
  301. if (fHeapBuffer.buf == nullptr)
  302. return;
  303. delete[] fHeapBuffer.buf;
  304. fHeapBuffer.buf = nullptr;
  305. }
  306. void createBuffer(const uint32_t size) noexcept
  307. {
  308. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
  309. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  310. const uint32_t p2size(carla_nextPowerOf2(size));
  311. try {
  312. fHeapBuffer.buf = new uint8_t[p2size];
  313. } CARLA_SAFE_EXCEPTION_RETURN("CarlaHeapRingBuffer::createBuffer",);
  314. fHeapBuffer.size = p2size;
  315. setRingBuffer(&fHeapBuffer, true);
  316. }
  317. void deleteBuffer() noexcept
  318. {
  319. CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
  320. setRingBuffer(nullptr, false);
  321. delete[] fHeapBuffer.buf;
  322. fHeapBuffer.buf = nullptr;
  323. fHeapBuffer.size = 0;
  324. }
  325. private:
  326. HeapBuffer fHeapBuffer;
  327. CARLA_PREVENT_HEAP_ALLOCATION
  328. CARLA_DECLARE_NON_COPY_CLASS(CarlaHeapRingBuffer)
  329. };
  330. // -----------------------------------------------------------------------
  331. // CarlaRingBuffer using stack space
  332. class CarlaStackRingBuffer : public CarlaRingBuffer<StackBuffer>
  333. {
  334. public:
  335. CarlaStackRingBuffer() noexcept
  336. : CarlaRingBuffer<StackBuffer>(&fStackBuffer) {}
  337. private:
  338. StackBuffer fStackBuffer;
  339. CARLA_PREVENT_HEAP_ALLOCATION
  340. CARLA_DECLARE_NON_COPY_CLASS(CarlaStackRingBuffer)
  341. };
  342. // -----------------------------------------------------------------------
  343. #endif // CARLA_RING_BUFFER_HPP_INCLUDED