DISTRHO Plugin Framework
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.

448 lines
11KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2024 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. #ifndef __STDC_LIMIT_MACROS
  20. # define __STDC_LIMIT_MACROS
  21. #endif
  22. #include <cstdarg>
  23. #include <cstdio>
  24. #include <cstdlib>
  25. #include <cstring>
  26. #include <cmath>
  27. #include <limits>
  28. #ifdef DISTRHO_PROPER_CPP11_SUPPORT
  29. # include <cstdint>
  30. #else
  31. # include <stdint.h>
  32. #endif
  33. #if defined(DISTRHO_OS_WINDOWS) && defined(_MSC_VER)
  34. #include <basetsd.h>
  35. typedef SSIZE_T ssize_t;
  36. #endif
  37. #if ! defined(CARLA_MATH_UTILS_HPP_INCLUDED) && ! defined(DISTRHO_PROPER_CPP11_SUPPORT) && ! defined(DISTRHO_OS_MAC)
  38. namespace std {
  39. inline float fmin(float __x, float __y)
  40. { return __builtin_fminf(__x, __y); }
  41. inline float fmax(float __x, float __y)
  42. { return __builtin_fmaxf(__x, __y); }
  43. inline float rint(float __x)
  44. { return __builtin_rintf(__x); }
  45. inline float round(float __x)
  46. { return __builtin_roundf(__x); }
  47. }
  48. #endif
  49. #ifndef M_PI
  50. # define M_PI 3.14159265358979323846
  51. #endif
  52. /* --------------------------------------------------------------------------------------------------------------------
  53. * misc functions */
  54. /**
  55. @defgroup MiscellaneousFunctions Miscellaneous functions
  56. @{
  57. */
  58. /**
  59. Return a 32-bit number from 4 8-bit numbers.@n
  60. The return type is a int64_t for better compatibility with plugin formats that use such numbers.
  61. */
  62. static inline constexpr
  63. int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d) noexcept
  64. {
  65. return (a << 24) | (b << 16) | (c << 8) | (d << 0);
  66. }
  67. /**
  68. Return a 32-bit number from 4 ASCII characters.
  69. */
  70. static inline constexpr
  71. uint32_t d_cconst(const char str[4])
  72. {
  73. return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3];
  74. }
  75. /**
  76. Return an hexadecimal representation of a MAJ.MIN.MICRO version number.
  77. */
  78. static inline constexpr
  79. uint32_t d_version(const uint8_t major, const uint8_t minor, const uint8_t micro) noexcept
  80. {
  81. return uint32_t(major << 16) | uint32_t(minor << 8) | (micro << 0);
  82. }
  83. /**
  84. Dummy, no-op function.
  85. */
  86. static inline
  87. void d_pass() noexcept {}
  88. /** @} */
  89. /* --------------------------------------------------------------------------------------------------------------------
  90. * string print functions */
  91. /**
  92. @defgroup StringPrintFunctions String print functions
  93. @{
  94. */
  95. /*
  96. * Internal noexcept-safe fopen function.
  97. */
  98. static inline
  99. FILE* __d_fopen(const char* const filename, FILE* const fallback) noexcept
  100. {
  101. if (std::getenv("DPF_CAPTURE_CONSOLE_OUTPUT") == nullptr)
  102. return fallback;
  103. FILE* ret = nullptr;
  104. try {
  105. ret = std::fopen(filename, "a+");
  106. } catch (...) {}
  107. if (ret == nullptr)
  108. ret = fallback;
  109. return ret;
  110. }
  111. /**
  112. Print a string to stdout with newline (gray color).
  113. Does nothing if DEBUG is not defined.
  114. */
  115. #ifndef DEBUG
  116. # define d_debug(...)
  117. #else
  118. static inline
  119. void d_debug(const char* const fmt, ...) noexcept
  120. {
  121. static FILE* const output = __d_fopen("/tmp/dpf.debug.log", stdout);
  122. try {
  123. va_list args;
  124. va_start(args, fmt);
  125. if (output == stdout)
  126. {
  127. #ifdef DISTRHO_OS_MAC
  128. std::fprintf(output, "\x1b[37;1m[dpf] ");
  129. #else
  130. std::fprintf(output, "\x1b[30;1m[dpf] ");
  131. #endif
  132. std::vfprintf(output, fmt, args);
  133. std::fprintf(output, "\x1b[0m\n");
  134. }
  135. else
  136. {
  137. std::fprintf(output, "[dpf] ");
  138. std::vfprintf(output, fmt, args);
  139. std::fprintf(output, "\n");
  140. }
  141. std::fflush(output);
  142. va_end(args);
  143. } catch (...) {}
  144. }
  145. #endif
  146. /**
  147. Print a string to stdout with newline.
  148. */
  149. static inline
  150. void d_stdout(const char* const fmt, ...) noexcept
  151. {
  152. static FILE* const output = __d_fopen("/tmp/dpf.stdout.log", stdout);
  153. try {
  154. va_list args;
  155. va_start(args, fmt);
  156. std::fprintf(output, "[dpf] ");
  157. std::vfprintf(output, fmt, args);
  158. std::fprintf(output, "\n");
  159. #ifndef DEBUG
  160. if (output != stdout)
  161. #endif
  162. std::fflush(output);
  163. va_end(args);
  164. } catch (...) {}
  165. }
  166. /**
  167. Print a string to stderr with newline.
  168. */
  169. static inline
  170. void d_stderr(const char* const fmt, ...) noexcept
  171. {
  172. static FILE* const output = __d_fopen("/tmp/dpf.stderr.log", stderr);
  173. try {
  174. va_list args;
  175. va_start(args, fmt);
  176. std::fprintf(output, "[dpf] ");
  177. std::vfprintf(output, fmt, args);
  178. std::fprintf(output, "\n");
  179. #ifndef DEBUG
  180. if (output != stderr)
  181. #endif
  182. std::fflush(output);
  183. va_end(args);
  184. } catch (...) {}
  185. }
  186. /**
  187. Print a string to stderr with newline (red color).
  188. */
  189. static inline
  190. void d_stderr2(const char* const fmt, ...) noexcept
  191. {
  192. static FILE* const output = __d_fopen("/tmp/dpf.stderr2.log", stderr);
  193. try {
  194. va_list args;
  195. va_start(args, fmt);
  196. if (output == stdout)
  197. {
  198. std::fprintf(output, "\x1b[31m[dpf] ");
  199. std::vfprintf(output, fmt, args);
  200. std::fprintf(output, "\x1b[0m\n");
  201. }
  202. else
  203. {
  204. std::fprintf(output, "[dpf] ");
  205. std::vfprintf(output, fmt, args);
  206. std::fprintf(output, "\n");
  207. }
  208. std::fflush(output);
  209. va_end(args);
  210. } catch (...) {}
  211. }
  212. /**
  213. Print a safe assertion error message.
  214. */
  215. static inline
  216. void d_safe_assert(const char* const assertion, const char* const file, const int line) noexcept
  217. {
  218. d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line);
  219. }
  220. /**
  221. Print a safe assertion error message, with 1 extra signed integer value.
  222. */
  223. static inline
  224. void d_safe_assert_int(const char* const assertion, const char* const file,
  225. const int line, const int value) noexcept
  226. {
  227. d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value);
  228. }
  229. /**
  230. Print a safe assertion error message, with 1 extra unsigned integer value.
  231. */
  232. static inline
  233. void d_safe_assert_uint(const char* const assertion, const char* const file,
  234. const int line, const uint value) noexcept
  235. {
  236. d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value);
  237. }
  238. /**
  239. Print a safe assertion error message, with 2 extra signed integer values.
  240. */
  241. static inline
  242. void d_safe_assert_int2(const char* const assertion, const char* const file,
  243. const int line, const int v1, const int v2) noexcept
  244. {
  245. d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2);
  246. }
  247. /**
  248. Print a safe assertion error message, with 2 extra unsigned integer values.
  249. */
  250. static inline
  251. void d_safe_assert_uint2(const char* const assertion, const char* const file,
  252. const int line, const uint v1, const uint v2) noexcept
  253. {
  254. d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2);
  255. }
  256. /**
  257. Print a safe assertion error message, with a custom error message.
  258. */
  259. static inline
  260. void d_custom_safe_assert(const char* const message, const char* const assertion, const char* const file,
  261. const int line) noexcept
  262. {
  263. d_stderr2("assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line);
  264. }
  265. /**
  266. Print a safe exception error message.
  267. */
  268. static inline
  269. void d_safe_exception(const char* const exception, const char* const file, const int line) noexcept
  270. {
  271. d_stderr2("exception caught: \"%s\" in file %s, line %i", exception, file, line);
  272. }
  273. /** @} */
  274. /* --------------------------------------------------------------------------------------------------------------------
  275. * math functions */
  276. /**
  277. @defgroup MathFunctions Math related functions
  278. @{
  279. */
  280. /**
  281. Safely compare two floating point numbers.
  282. Returns true if they match.
  283. */
  284. template<typename T>
  285. static inline constexpr
  286. bool d_isEqual(const T& v1, const T& v2)
  287. {
  288. return std::abs(v1-v2) < std::numeric_limits<T>::epsilon();
  289. }
  290. /**
  291. Safely compare two floating point numbers.
  292. Returns true if they don't match.
  293. */
  294. template<typename T>
  295. static inline constexpr
  296. bool d_isNotEqual(const T& v1, const T& v2)
  297. {
  298. return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon();
  299. }
  300. /**
  301. Safely check if a floating point number is zero.
  302. */
  303. template<typename T>
  304. static inline constexpr
  305. bool d_isZero(const T& value)
  306. {
  307. return std::abs(value) < std::numeric_limits<T>::epsilon();
  308. }
  309. /**
  310. Safely check if a floating point number is not zero.
  311. */
  312. template<typename T>
  313. static inline constexpr
  314. bool d_isNotZero(const T& value)
  315. {
  316. return std::abs(value) >= std::numeric_limits<T>::epsilon();
  317. }
  318. /**
  319. Get next power of 2.
  320. */
  321. static inline
  322. uint32_t d_nextPowerOf2(uint32_t size) noexcept
  323. {
  324. DISTRHO_SAFE_ASSERT_RETURN(size > 0, 0);
  325. // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  326. --size;
  327. size |= size >> 1;
  328. size |= size >> 2;
  329. size |= size >> 4;
  330. size |= size >> 8;
  331. size |= size >> 16;
  332. return ++size;
  333. }
  334. /**
  335. Round a floating point number to an integer.
  336. Fast operation for values known to be 0 or positive.
  337. */
  338. template<typename T>
  339. static inline constexpr
  340. int32_t d_roundToIntPositive(const T& value)
  341. {
  342. return static_cast<int32_t>(value + static_cast<T>(0.5));
  343. }
  344. /**
  345. Round a floating point number to an unsigned integer.
  346. Fast operation for values known to be 0 or positive.
  347. */
  348. template<typename T>
  349. static inline constexpr
  350. uint32_t d_roundToUnsignedInt(const T& value)
  351. {
  352. return static_cast<uint32_t>(value + static_cast<T>(0.5));
  353. }
  354. /**
  355. Round a floating point number to an integer.
  356. Fast operation for values known to be 0 or negative.
  357. */
  358. template<typename T>
  359. static inline constexpr
  360. int32_t d_roundToIntNegative(const T& value)
  361. {
  362. return static_cast<int32_t>(value - static_cast<T>(0.5));
  363. }
  364. /**
  365. Round a floating point number to integer.
  366. */
  367. template<typename T>
  368. static inline constexpr
  369. int32_t d_roundToInt(const T& value)
  370. {
  371. return value >= 0 ? static_cast<int32_t>(value + static_cast<T>(0.5))
  372. : static_cast<int32_t>(value - static_cast<T>(0.5));
  373. }
  374. /** @} */
  375. /* --------------------------------------------------------------------------------------------------------------------
  376. * other stuff */
  377. #ifndef DONT_SET_USING_DISTRHO_NAMESPACE
  378. /**
  379. If your code uses a lot of DISTRHO classes, then this will obviously save you a lot of typing,
  380. but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE.
  381. */
  382. namespace DISTRHO_NAMESPACE {}
  383. using namespace DISTRHO_NAMESPACE;
  384. #endif
  385. #endif // DISTRHO_UTILS_HPP_INCLUDED