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