DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

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