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.

455 lines
11KB

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