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