HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_utils.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // min(), max()
4#include <cctype> // isalpha()
5#include <cmath> // pow()
6#include <exception>
7#include <fstream>
8#include <limits> // infinity(), nan()
9#include <memory>
10#include <ostream>
11#include <string>
12#include <unordered_map>
13
15
16namespace hart
17{
18
19/// @defgroup Utilities Utilities
20/// @brief Handy functions and constants
21/// @{
22
23/// @brief Infinity
24constexpr double inf = std::numeric_limits<double>::infinity();
25
26/// @brief Infinity
27constexpr double oo = inf;
28
29/// @brief pi
30constexpr double pi = 3.14159265358979323846;
31
32/// @brief 2 * pi
33constexpr double twoPi = 2.0 * pi;
34
35/// @brief pi / 2
36constexpr double halfPi = pi / 2.0;
37
38/// @brief Helper values for channel indices
40{
41 left = 0,
42 right = 1
43};
44
45/// @brief Helper values for mid-side channel indices
47{
48 mid = 0,
49 side = 1
50};
51
52/// @brief Helper values for something that could loop, like a Signal
53enum class Loop
54{
55 no,
56 yes
57};
58
59/// @brief Helper values for something that could normalise something
60enum class Normalise
61{
62 no,
63 yes
64};
65
66/// @brief Oversampling ratio
68{
69 x4 = 4,
70 x8 = 8,
71 x16 = 16
72};
73
74/// @brief @brief Interpolation method
75enum class Interpolation
76{
77 nearest,
78 linear
79};
80
81inline std::ostream& operator<< (std::ostream& os, Oversampling oversampling)
82{
83 return os << "Oversampling::x" << static_cast<int> (oversampling);
84}
85
86/// @brief Returns a quiet NaN value for the given floating-point type.
87template<typename FloatType>
88inline FloatType nan()
89{
90 return std::numeric_limits<FloatType>::quiet_NaN();
91}
92
93/// @brief `std::clamp()` replacement for C++11
94template <typename NumericType>
95NumericType clamp (const NumericType& value, const NumericType& low, const NumericType& high)
96{
97 return std::min<NumericType> (std::max<NumericType> (value, low), high);
98}
99
100/// @brief Converts dB to linear value (ratio)
101/// @param valueDb Value in decibels
102/// @return Value in linear domain
103template <typename SampleType>
104inline static SampleType decibelsToRatio (SampleType valueDb)
105{
106 if (valueDb < -120)
107 return 0;
108
109 return std::pow (static_cast<SampleType> (10), valueDb / static_cast<SampleType> (20));
110}
111
112/// @brief Converts linear value (ratio) to dB
113/// @param valueLinear Value in linear domain
114/// @return Value in decibels
115template <typename SampleType>
116inline static SampleType ratioToDecibels (SampleType valueLinear)
117{
118 if (valueLinear < 1e-6)
119 return -120;
120
121 return static_cast<SampleType> (20 * std::log10 (valueLinear));
122}
123
124/// @brief Converts dB to linear value (power)
125/// @param valueDb Value in decibels
126/// @return Value in linear domain
127template <typename SampleType>
128inline static SampleType decibelsToPower (SampleType valueDb)
129{
130 if (valueDb < -120)
131 return 0;
132
133 return std::pow (static_cast<SampleType> (10), valueDb / static_cast<SampleType> (10));
134}
135
136/// @brief Converts linear value (power) to dB
137/// @param valueLinear Value in linear domain
138/// @return Value in decibels
139template <typename SampleType>
140inline static SampleType powerToDecibels (SampleType valueLinear)
141{
142 if (valueLinear < 1e-12)
143 return -120;
144
145 return static_cast<SampleType> (10 * std::log10 (valueLinear));
146}
147
148/// @brief Compares two floating point numbers within a given tolerance
149template <typename SampleType>
150inline static SampleType floatsEqual (SampleType a, SampleType b, SampleType epsilon = (SampleType) 1e-8)
151{
152 return std::abs (a - b) < epsilon;
153}
154
155/// @brief Compares two floating point numbers within a given tolerance
156template <typename SampleType>
157inline static SampleType floatsNotEqual (SampleType a, SampleType b, SampleType epsilon = (SampleType) 1e-8)
158{
159 return std::abs (a - b) >= epsilon;
160}
161
162/// @brief Rounds a floating point value to a `size_t` value
163template <typename SampleType>
164inline static size_t roundToSizeT (SampleType x)
165{
166 return static_cast<size_t> (x + (SampleType) 0.5);
167}
168
169/// @brief Converts frequency difference in cents to frequence ratio
170inline double centsToRatio (double cents)
171{
172 return std::pow (2.0, cents / 1200.0);
173}
174
175/// @brief Adds an offset in cents to a frequency in Hz
176inline double addCents (double baseFrequencyHz, double cents)
177{
178 return baseFrequencyHz * centsToRatio (cents);
179}
180
181/// @brief Keeps phase in 0..twoPi range
182template <typename SampleType>
183SampleType wrapPhase (const SampleType phaseRadians)
184{
185 SampleType wrappedPhaseRadians = std::remainder (phaseRadians, (SampleType) hart::twoPi);
186
187 if (wrappedPhaseRadians < 0.0)
188 wrappedPhaseRadians += hart::twoPi;
189
190 return wrappedPhaseRadians;
191}
192
193/// @brief Finds next power of 2 after a non-negative number x
194static size_t nextPowerOfTwo (size_t x)
195{
196 size_t power = 1;
197
198 while (power < x)
199 power <<= 1;
200
201 return power;
202}
203
204/// @brief Finds previous power of 2 after a non-negative number x
205/// @note If x is a power of 2 itself, it will return x
206static size_t previousPowerOfTwo (size_t x)
207{
208 if (x == 0)
209 return 0;
210
211 size_t power = 1;
212
213 while ((power << 1) < x)
214 power <<= 1;
215
216 return power;
217}
218
219// @brief Checks if number is a power of 2
220static bool isPowerOfTwo (size_t x)
221{
222 return (x != 0) && ((x & (x - 1)) == 0);
223}
224
225// @brief Check if file exists and whether it's possible to read it
226// @note There are better ways to do it post-C++17, but HART is C++11.
227inline static bool fileExistsAndReadable (const std::string& path)
228{
229 std::ifstream file (path.c_str());
230 return file.good();
231}
232
233/// @brief Checks if the provided file path is absolute
234inline static bool isAbsolutePath (const std::string& path)
235{
236 if (path.empty())
237 return false;
238
239 if (path[0] == '/' || path[0] == '\\')
240 return true;
241
242 #ifdef _WIN32
243 if (path.size() > 1 && std::isalpha (path[0]) && path[1] == ':')
244 return true;
245 #endif
246
247 return false;
248}
249
250/// @brief Converts path to absolute, if it's relative
251/// @details Relative paths are resolved based on a provided `--data-root-path` CLI argument
252inline static std::string toAbsolutePath (const std::string& path)
253{
254 if (isAbsolutePath(path))
255 return path;
256
258}
259
260/// @brief `std::unordered_map::contains()` replacement for C++11
261template <typename KeyType, typename ValueType>
262inline static bool contains (const std::unordered_map<KeyType, ValueType>& map, const KeyType& key)
263{
264 return map.find (key) != map.end();
265}
266
267/// @brief `std::make_unique()` replacement for C++11
268/// @details For C++11 compatibility only. If you're one C++14 or later, just use STL version.
269template<typename ObjectType, typename... Args>
270std::unique_ptr<ObjectType> make_unique (Args&&... args)
271{
272 return std::unique_ptr<ObjectType> (new ObjectType (std::forward<Args> (args)...));
273}
274
275/// @brief Returns `true` if an exception is currently being unwound
276inline static bool isExceptionUnwinding()
277{
278#if defined(__cpp_lib_uncaught_exceptions)
279 return std::uncaught_exceptions() > 0;
280#else
281 return std::uncaught_exception();
282#endif
283}
284
285/// @brief Defines a basic string representation of your class
286/// @details If your class takes ctor arguments, it's strongly encouraged to make a proper
287/// implementation of `represent()`, so that you get more detailed test failure reports.
288/// See @ref hart::DSP::represent(), @ref hart::Matcher::represent(),
289/// @ref hart::Signal::represent() for the description.
290#define HART_DEFINE_GENERIC_REPRESENT(ClassName)
291 virtual void represent(std::ostream& stream) const override
292 {
293 stream << #ClassName "()";
294 }
295
296/// @private
297#if defined(__GNUC__) || defined(__clang__)
298 #define HART_DEPRECATED(msg) __attribute__((deprecated(msg)))
299#elif defined(_MSC_VER)
300 #define HART_DEPRECATED(msg) __declspec(deprecated(msg))
301#else
302 #define HART_DEPRECATED(msg)
303#endif
304
305} // namespace hart
constexpr double twoPi
2 * pi
static bool isAbsolutePath(const std::string &path)
Checks if the provided file path is absolute.
FloatType nan()
Returns a quiet NaN value for the given floating-point type.
Channel
Helper values for channel indices.
static bool isPowerOfTwo(size_t x)
SampleType wrapPhase(const SampleType phaseRadians)
Keeps phase in 0..twoPi range.
static bool contains(const std::unordered_map< KeyType, ValueType > &map, const KeyType &key)
std::unordered_map::contains() replacement for C++11
Normalise
Helper values for something that could normalise something.
constexpr double halfPi
pi / 2
static size_t roundToSizeT(SampleType x)
Rounds a floating point value to a size_t value.
constexpr double inf
Infinity.
static SampleType ratioToDecibels(SampleType valueLinear)
Converts linear value (ratio) to dB.
static SampleType floatsNotEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.
MidSideChannel
Helper values for mid-side channel indices.
Interpolation
Interpolation method.
std::unique_ptr< ObjectType > make_unique(Args &&... args)
std::make_unique() replacement for C++11
static SampleType powerToDecibels(SampleType valueLinear)
Converts linear value (power) to dB.
double addCents(double baseFrequencyHz, double cents)
Adds an offset in cents to a frequency in Hz.
static size_t nextPowerOfTwo(size_t x)
Finds next power of 2 after a non-negative number x.
NumericType clamp(const NumericType &value, const NumericType &low, const NumericType &high)
std::clamp() replacement for C++11
constexpr double oo
Infinity.
static bool fileExistsAndReadable(const std::string &path)
static std::string toAbsolutePath(const std::string &path)
Converts path to absolute, if it's relative.
static SampleType decibelsToRatio(SampleType valueDb)
Converts dB to linear value (ratio)
static size_t previousPowerOfTwo(size_t x)
Finds previous power of 2 after a non-negative number x.
static bool isExceptionUnwinding()
Returns true if an exception is currently being unwound.
constexpr double pi
pi
static SampleType floatsEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.
static SampleType decibelsToPower(SampleType valueDb)
Converts dB to linear value (power)
Oversampling
Oversampling ratio.
double centsToRatio(double cents)
Converts frequency difference in cents to frequence ratio.
Loop
Helper values for something that could loop, like a Signal.
Holds values set by the user via CLI interface.
std::string getDataRootPath() const
Get data root path set by a "`--data-root-path`,`-d`" argument.
static CLIConfig & getInstance()
Get the singleton instance.