DISTRHO Plugin Framework
DistrhoUtils.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 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(DISTRHO_OS_MAC) && ! defined(CARLA_OS_MAC) && ! 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 #define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO
59 #define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO)
60 
61 // -----------------------------------------------------------------------
62 // misc functions
63 
64 /*
65  * Return a 64-bit number from 4 8-bit numbers.
66  */
67 static inline constexpr
68 int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d) noexcept
69 {
70  return (a << 24) | (b << 16) | (c << 8) | (d << 0);
71 }
72 
73 /*
74  * Return an hexadecimal representation of a MAJ.MIN.MICRO version number.
75  */
76 static inline constexpr
77 uint32_t d_version(const uint8_t major, const uint8_t minor, const uint8_t micro) noexcept
78 {
79  return uint32_t(major << 16) | uint32_t(minor << 8) | (micro << 0);
80 }
81 
82 /*
83  * Dummy function.
84  */
85 static inline
86 void d_pass() noexcept {}
87 
88 // -----------------------------------------------------------------------
89 // string print functions
90 
91 /*
92  * Print a string to stdout with newline (gray color).
93  * Does nothing if DEBUG is not defined.
94  */
95 #ifndef DEBUG
96 # define d_debug(...)
97 #else
98 static inline
99 void d_debug(const char* const fmt, ...) noexcept
100 {
101  try {
102  va_list args;
103  va_start(args, fmt);
104  std::fprintf(stdout, "\x1b[30;1m");
105  std::vfprintf(stdout, fmt, args);
106  std::fprintf(stdout, "\x1b[0m\n");
107  va_end(args);
108  } catch (...) {}
109 }
110 #endif
111 
112 /*
113  * Print a string to stdout with newline.
114  */
115 static inline
116 void d_stdout(const char* const fmt, ...) noexcept
117 {
118  try {
119  va_list args;
120  va_start(args, fmt);
121  std::vfprintf(stdout, fmt, args);
122  std::fprintf(stdout, "\n");
123  va_end(args);
124  } catch (...) {}
125 }
126 
127 /*
128  * Print a string to stderr with newline.
129  */
130 static inline
131 void d_stderr(const char* const fmt, ...) noexcept
132 {
133  try {
134  va_list args;
135  va_start(args, fmt);
136  std::vfprintf(stderr, fmt, args);
137  std::fprintf(stderr, "\n");
138  va_end(args);
139  } catch (...) {}
140 }
141 
142 /*
143  * Print a string to stderr with newline (red color).
144  */
145 static inline
146 void d_stderr2(const char* const fmt, ...) noexcept
147 {
148  try {
149  va_list args;
150  va_start(args, fmt);
151  std::fprintf(stderr, "\x1b[31m");
152  std::vfprintf(stderr, fmt, args);
153  std::fprintf(stderr, "\x1b[0m\n");
154  va_end(args);
155  } catch (...) {}
156 }
157 
158 /*
159  * Print a safe assertion error message.
160  */
161 static inline
162 void d_safe_assert(const char* const assertion, const char* const file, const int line) noexcept
163 {
164  d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line);
165 }
166 
167 /*
168  * Print a safe assertion error message, with 1 extra signed integer value.
169  */
170 static inline
171 void d_safe_assert_int(const char* const assertion, const char* const file,
172  const int line, const int value) noexcept
173 {
174  d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value);
175 }
176 
177 /*
178  * Print a safe assertion error message, with 1 extra unsigned integer value.
179  */
180 static inline
181 void d_safe_assert_uint(const char* const assertion, const char* const file,
182  const int line, const uint value) noexcept
183 {
184  d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value);
185 }
186 
187 /*
188  * Print a safe assertion error message, with 2 extra signed integer values.
189  */
190 static inline
191 void d_safe_assert_int2(const char* const assertion, const char* const file,
192  const int line, const int v1, const int v2) noexcept
193 {
194  d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2);
195 }
196 
197 /*
198  * Print a safe assertion error message, with 2 extra unsigned integer values.
199  */
200 static inline
201 void d_safe_assert_uint2(const char* const assertion, const char* const file,
202  const int line, const uint v1, const uint v2) noexcept
203 {
204  d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2);
205 }
206 
207 /*
208  * Print a safe assertion error message, with a custom error message.
209  */
210 static inline
211 void d_custom_safe_assert(const char* const message, const char* const assertion, const char* const file,
212  const int line) noexcept
213 {
214  d_stderr2("assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line);
215 }
216 
217 /*
218  * Print a safe exception error message.
219  */
220 static inline
221 void d_safe_exception(const char* const exception, const char* const file, const int line) noexcept
222 {
223  d_stderr2("exception caught: \"%s\" in file %s, line %i", exception, file, line);
224 }
225 
226 // -----------------------------------------------------------------------
227 // math functions
228 
229 /*
230  * Safely compare two floating point numbers.
231  * Returns true if they match.
232  */
233 template<typename T>
234 static inline
235 bool d_isEqual(const T& v1, const T& v2)
236 {
237  return std::abs(v1-v2) < std::numeric_limits<T>::epsilon();
238 }
239 
240 /*
241  * Safely compare two floating point numbers.
242  * Returns true if they don't match.
243  */
244 template<typename T>
245 static inline
246 bool d_isNotEqual(const T& v1, const T& v2)
247 {
248  return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon();
249 }
250 
251 /*
252  * Safely check if a floating point number is zero.
253  */
254 template<typename T>
255 static inline
256 bool d_isZero(const T& value)
257 {
258  return std::abs(value) < std::numeric_limits<T>::epsilon();
259 }
260 
261 /*
262  * Safely check if a floating point number is not zero.
263  */
264 template<typename T>
265 static inline
266 bool d_isNotZero(const T& value)
267 {
268  return std::abs(value) >= std::numeric_limits<T>::epsilon();
269 }
270 
271 /*
272  * Get next power of 2.
273  */
274 static inline
275 uint32_t d_nextPowerOf2(uint32_t size) noexcept
276 {
277  DISTRHO_SAFE_ASSERT_RETURN(size > 0, 0);
278 
279  // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
280  --size;
281  size |= size >> 1;
282  size |= size >> 2;
283  size |= size >> 4;
284  size |= size >> 8;
285  size |= size >> 16;
286  return ++size;
287 }
288 
289 // -----------------------------------------------------------------------
290 
291 #ifndef DONT_SET_USING_DISTRHO_NAMESPACE
292  // If your code uses a lot of DISTRHO classes, then this will obviously save you
293  // a lot of typing, but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE.
294  namespace DISTRHO_NAMESPACE {}
295  using namespace DISTRHO_NAMESPACE;
296 #endif
297 
298 // -----------------------------------------------------------------------
299 
300 #endif // DISTRHO_UTILS_HPP_INCLUDED