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.

DistrhoUtils.hpp 15KB

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
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
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
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
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
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_UTILS_HPP_INCLUDED
  17. #define DISTRHO_UTILS_HPP_INCLUDED
  18. #include "src/DistrhoDefines.h"
  19. #include <cassert>
  20. #include <cstdarg>
  21. #include <cstdio>
  22. #include <cstdlib>
  23. #include <cstring>
  24. #ifdef PROPER_CPP11_SUPPORT
  25. # include <cstdint>
  26. #else
  27. # include <stdint.h>
  28. #endif
  29. #ifdef DISTRHO_OS_WINDOWS
  30. # include <windows.h>
  31. #else
  32. # include <unistd.h>
  33. #endif
  34. #if defined(DISTRHO_OS_MAC) && ! defined(CARLA_OS_MAC)
  35. namespace std {
  36. inline float
  37. fmin(float __x, float __y)
  38. { return __builtin_fminf(__x, __y); }
  39. inline float
  40. fmax(float __x, float __y)
  41. { return __builtin_fmaxf(__x, __y); }
  42. inline float
  43. rint(float __x)
  44. { return __builtin_rintf(__x); }
  45. }
  46. #endif
  47. // -----------------------------------------------------------------------
  48. // misc functions
  49. static inline
  50. long d_cconst(int a, int b, int c, int d) noexcept
  51. {
  52. return (a << 24) | (b << 16) | (c << 8) | (d << 0);
  53. }
  54. // -----------------------------------------------------------------------
  55. // string print functions
  56. #ifndef DEBUG
  57. # define d_debug(...)
  58. #else
  59. static inline
  60. void d_debug(const char* const fmt, ...)
  61. {
  62. va_list args;
  63. va_start(args, fmt);
  64. std::fprintf(stdout, "\x1b[30;1m");
  65. std::vfprintf(stdout, fmt, args);
  66. std::fprintf(stdout, "\x1b[0m\n");
  67. va_end(args);
  68. }
  69. #endif
  70. static inline
  71. void d_stdout(const char* const fmt, ...)
  72. {
  73. va_list args;
  74. va_start(args, fmt);
  75. std::vfprintf(stdout, fmt, args);
  76. std::fprintf(stdout, "\n");
  77. va_end(args);
  78. }
  79. static inline
  80. void d_stderr(const char* const fmt, ...)
  81. {
  82. va_list args;
  83. va_start(args, fmt);
  84. std::vfprintf(stderr, fmt, args);
  85. std::fprintf(stderr, "\n");
  86. va_end(args);
  87. }
  88. static inline
  89. void d_stderr2(const char* const fmt, ...)
  90. {
  91. va_list args;
  92. va_start(args, fmt);
  93. std::fprintf(stderr, "\x1b[31m");
  94. std::vfprintf(stderr, fmt, args);
  95. std::fprintf(stderr, "\x1b[0m\n");
  96. va_end(args);
  97. }
  98. // -----------------------------------------------------------------------
  99. // d_*sleep
  100. static inline
  101. void d_sleep(unsigned int secs)
  102. {
  103. #ifdef DISTRHO_OS_WINDOWS
  104. Sleep(secs * 1000);
  105. #else
  106. sleep(secs);
  107. #endif
  108. }
  109. static inline
  110. void d_msleep(unsigned int msecs)
  111. {
  112. #ifdef DISTRHO_OS_WINDOWS
  113. Sleep(msecs);
  114. #else
  115. usleep(msecs * 1000);
  116. #endif
  117. }
  118. // -----------------------------------------------------------------------
  119. // d_string class
  120. class d_string
  121. {
  122. public:
  123. // -------------------------------------------------------------------
  124. // constructors (no explicit conversions allowed)
  125. /*
  126. * Empty string.
  127. */
  128. explicit d_string()
  129. {
  130. _init();
  131. _dup(nullptr);
  132. }
  133. /*
  134. * Simple character.
  135. */
  136. explicit d_string(const char c)
  137. {
  138. char ch[2];
  139. ch[0] = c;
  140. ch[1] = '\0';
  141. _init();
  142. _dup(ch);
  143. }
  144. /*
  145. * Simple char string.
  146. */
  147. explicit d_string(char* const strBuf)
  148. {
  149. _init();
  150. _dup(strBuf);
  151. }
  152. /*
  153. * Simple const char string.
  154. */
  155. explicit d_string(const char* const strBuf)
  156. {
  157. _init();
  158. _dup(strBuf);
  159. }
  160. /*
  161. * Integer.
  162. */
  163. explicit d_string(const int value)
  164. {
  165. char strBuf[0xff+1];
  166. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  167. std::snprintf(strBuf, 0xff, "%d", value);
  168. _init();
  169. _dup(strBuf);
  170. }
  171. /*
  172. * Unsigned integer, possibly in hexadecimal.
  173. */
  174. explicit d_string(const unsigned int value, const bool hexadecimal = false)
  175. {
  176. char strBuf[0xff+1];
  177. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  178. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  179. _init();
  180. _dup(strBuf);
  181. }
  182. /*
  183. * Long integer.
  184. */
  185. explicit d_string(const long int value)
  186. {
  187. char strBuf[0xff+1];
  188. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  189. std::snprintf(strBuf, 0xff, "%ld", value);
  190. _init();
  191. _dup(strBuf);
  192. }
  193. /*
  194. * Long unsigned integer, possibly hexadecimal.
  195. */
  196. explicit d_string(const unsigned long int value, const bool hexadecimal = false)
  197. {
  198. char strBuf[0xff+1];
  199. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  200. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  201. _init();
  202. _dup(strBuf);
  203. }
  204. /*
  205. * Single-precision floating point number.
  206. */
  207. explicit d_string(const float value)
  208. {
  209. char strBuf[0xff+1];
  210. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  211. std::snprintf(strBuf, 0xff, "%f", value);
  212. _init();
  213. _dup(strBuf);
  214. }
  215. /*
  216. * Double-precision floating point number.
  217. */
  218. explicit d_string(const double value)
  219. {
  220. char strBuf[0xff+1];
  221. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  222. std::snprintf(strBuf, 0xff, "%g", value);
  223. _init();
  224. _dup(strBuf);
  225. }
  226. // -------------------------------------------------------------------
  227. // non-explicit constructor
  228. /*
  229. * Create string from another string.
  230. */
  231. d_string(const d_string& str)
  232. {
  233. _init();
  234. _dup(str.fBuffer);
  235. }
  236. // -------------------------------------------------------------------
  237. // destructor
  238. /*
  239. * Destructor.
  240. */
  241. ~d_string()
  242. {
  243. assert(fBuffer != nullptr);
  244. delete[] fBuffer;
  245. fBuffer = nullptr;
  246. }
  247. // -------------------------------------------------------------------
  248. // public methods
  249. /*
  250. * Get length of the string.
  251. */
  252. size_t length() const noexcept
  253. {
  254. return fBufferLen;
  255. }
  256. /*
  257. * Check if the string is empty.
  258. */
  259. bool isEmpty() const noexcept
  260. {
  261. return (fBufferLen == 0);
  262. }
  263. /*
  264. * Check if the string is not empty.
  265. */
  266. bool isNotEmpty() const noexcept
  267. {
  268. return (fBufferLen != 0);
  269. }
  270. /*
  271. * Check if the string contains another string, optionally ignoring case.
  272. */
  273. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  274. {
  275. if (strBuf == nullptr)
  276. return false;
  277. if (ignoreCase)
  278. {
  279. #ifdef __USE_GNU
  280. return (strcasestr(fBuffer, strBuf) != nullptr);
  281. #else
  282. d_string tmp1(fBuffer), tmp2(strBuf);
  283. tmp1.toLower();
  284. tmp2.toLower();
  285. return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr);
  286. #endif
  287. }
  288. return (std::strstr(fBuffer, strBuf) != nullptr);
  289. }
  290. /*
  291. * Overloaded function.
  292. */
  293. bool contains(const d_string& str, const bool ignoreCase = false) const
  294. {
  295. return contains(str.fBuffer, ignoreCase);
  296. }
  297. /*
  298. * Check if character at 'pos' is a digit.
  299. */
  300. bool isDigit(const size_t pos) const noexcept
  301. {
  302. if (pos >= fBufferLen)
  303. return false;
  304. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  305. }
  306. /*
  307. * Check if the string starts with the character 'c'.
  308. */
  309. bool startsWith(const char c) const
  310. {
  311. if (c == '\0')
  312. return false;
  313. return (fBufferLen > 0 && fBuffer[0] == c);
  314. }
  315. /*
  316. * Check if the string starts with the string 'prefix'.
  317. */
  318. bool startsWith(const char* const prefix) const
  319. {
  320. if (prefix == nullptr)
  321. return false;
  322. const size_t prefixLen(std::strlen(prefix));
  323. if (fBufferLen < prefixLen)
  324. return false;
  325. return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
  326. }
  327. /*
  328. * Check if the string ends with the character 'c'.
  329. */
  330. bool endsWith(const char c) const
  331. {
  332. if (c == '\0')
  333. return false;
  334. return (fBufferLen > 0 && fBuffer[fBufferLen] == c);
  335. }
  336. /*
  337. * Check if the string ends with the string 'suffix'.
  338. */
  339. bool endsWith(const char* const suffix) const
  340. {
  341. if (suffix == nullptr)
  342. return false;
  343. const size_t suffixLen(std::strlen(suffix));
  344. if (fBufferLen < suffixLen)
  345. return false;
  346. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  347. }
  348. /*
  349. * Clear the string.
  350. */
  351. void clear() noexcept
  352. {
  353. truncate(0);
  354. }
  355. /*
  356. * Replace all occurrences of character 'before' with character 'after'.
  357. */
  358. void replace(const char before, const char after) noexcept
  359. {
  360. if (before == '\0' || after == '\0')
  361. return;
  362. for (size_t i=0; i < fBufferLen; ++i)
  363. {
  364. if (fBuffer[i] == before)
  365. fBuffer[i] = after;
  366. else if (fBuffer[i] == '\0')
  367. break;
  368. }
  369. }
  370. /*
  371. * Truncate the string to size 'n'.
  372. */
  373. void truncate(const size_t n) noexcept
  374. {
  375. if (n >= fBufferLen)
  376. return;
  377. for (size_t i=n; i < fBufferLen; ++i)
  378. fBuffer[i] = '\0';
  379. fBufferLen = n;
  380. }
  381. /*
  382. * Convert all non-basic characters to '_'.
  383. */
  384. void toBasic() noexcept
  385. {
  386. for (size_t i=0; i < fBufferLen; ++i)
  387. {
  388. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  389. continue;
  390. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  391. continue;
  392. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  393. continue;
  394. if (fBuffer[i] == '_')
  395. continue;
  396. fBuffer[i] = '_';
  397. }
  398. }
  399. /*
  400. * Convert to all ascii characters to lowercase.
  401. */
  402. void toLower() noexcept
  403. {
  404. static const char kCharDiff('a' - 'A');
  405. for (size_t i=0; i < fBufferLen; ++i)
  406. {
  407. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  408. fBuffer[i] += kCharDiff;
  409. }
  410. }
  411. /*
  412. * Convert to all ascii characters to uppercase.
  413. */
  414. void toUpper() noexcept
  415. {
  416. static const char kCharDiff('a' - 'A');
  417. for (size_t i=0; i < fBufferLen; ++i)
  418. {
  419. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  420. fBuffer[i] -= kCharDiff;
  421. }
  422. }
  423. // -------------------------------------------------------------------
  424. // public operators
  425. operator const char*() const noexcept
  426. {
  427. return fBuffer;
  428. }
  429. char& operator[](const size_t pos) const noexcept
  430. {
  431. return fBuffer[pos];
  432. }
  433. bool operator==(const char* const strBuf) const
  434. {
  435. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  436. }
  437. bool operator==(const d_string& str) const
  438. {
  439. return operator==(str.fBuffer);
  440. }
  441. bool operator!=(const char* const strBuf) const
  442. {
  443. return !operator==(strBuf);
  444. }
  445. bool operator!=(const d_string& str) const
  446. {
  447. return !operator==(str.fBuffer);
  448. }
  449. d_string& operator=(const char* const strBuf)
  450. {
  451. _dup(strBuf);
  452. return *this;
  453. }
  454. d_string& operator=(const d_string& str)
  455. {
  456. return operator=(str.fBuffer);
  457. }
  458. d_string& operator+=(const char* const strBuf)
  459. {
  460. if (strBuf == nullptr)
  461. return *this;
  462. const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  463. char newBuf[newBufSize];
  464. std::strcpy(newBuf, fBuffer);
  465. std::strcat(newBuf, strBuf);
  466. _dup(newBuf, newBufSize-1);
  467. return *this;
  468. }
  469. d_string& operator+=(const d_string& str)
  470. {
  471. return operator+=(str.fBuffer);
  472. }
  473. d_string operator+(const char* const strBuf)
  474. {
  475. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  476. char newBuf[newBufSize];
  477. std::strcpy(newBuf, fBuffer);
  478. if (strBuf != nullptr)
  479. std::strcat(newBuf, strBuf);
  480. return d_string(newBuf);
  481. }
  482. d_string operator+(const d_string& str)
  483. {
  484. return operator+(str.fBuffer);
  485. }
  486. // -------------------------------------------------------------------
  487. private:
  488. char* fBuffer; // the actual string buffer
  489. size_t fBufferLen; // string length
  490. bool fFirstInit; // true when first initiated
  491. /*
  492. * Shared init function.
  493. * Called on all constructors.
  494. */
  495. void _init() noexcept
  496. {
  497. fBuffer = nullptr;
  498. fBufferLen = 0;
  499. fFirstInit = true;
  500. }
  501. /*
  502. * Helper function.
  503. * Called whenever the string needs to be allocated.
  504. *
  505. * Notes:
  506. * - Allocates string only if first initiated, or if 'strBuf' is not null and new string contents are different
  507. * - If 'strBuf' is null 'size' must be 0
  508. */
  509. void _dup(const char* const strBuf, const size_t size = 0)
  510. {
  511. if (strBuf != nullptr)
  512. {
  513. // don't recreate string if contents match
  514. if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
  515. {
  516. if (! fFirstInit)
  517. {
  518. assert(fBuffer != nullptr);
  519. delete[] fBuffer;
  520. }
  521. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  522. fBuffer = new char[fBufferLen+1];
  523. std::strcpy(fBuffer, strBuf);
  524. fBuffer[fBufferLen] = '\0';
  525. fFirstInit = false;
  526. }
  527. }
  528. else
  529. {
  530. assert(size == 0);
  531. // don't recreate null string
  532. if (fFirstInit || fBufferLen != 0)
  533. {
  534. if (! fFirstInit)
  535. {
  536. assert(fBuffer != nullptr);
  537. delete[] fBuffer;
  538. }
  539. fBufferLen = 0;
  540. fBuffer = new char[1];
  541. fBuffer[0] = '\0';
  542. fFirstInit = false;
  543. }
  544. }
  545. }
  546. };
  547. // -----------------------------------------------------------------------
  548. static inline
  549. d_string operator+(const d_string& strBefore, const char* const strBufAfter)
  550. {
  551. const char* const strBufBefore = (const char*)strBefore;
  552. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  553. char newBuf[newBufSize];
  554. std::strcpy(newBuf, strBufBefore);
  555. std::strcat(newBuf, strBufAfter);
  556. return d_string(newBuf);
  557. }
  558. static inline
  559. d_string operator+(const char* const strBufBefore, const d_string& strAfter)
  560. {
  561. const char* const strBufAfter = (const char*)strAfter;
  562. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  563. char newBuf[newBufSize];
  564. std::strcpy(newBuf, strBufBefore);
  565. std::strcat(newBuf, strBufAfter);
  566. return d_string(newBuf);
  567. }
  568. // -----------------------------------------------------------------------
  569. #endif // DISTRHO_UTILS_HPP_INCLUDED