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