OpenShot Audio Library | OpenShotAudio: juce_MathsFunctions.h Source File

OpenShot Audio Library | OpenShotAudio 0.6.0

Loading...
Searching...
No Matches
juce_MathsFunctions.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26//==============================================================================
27/*
28 This file sets up some handy mathematical typdefs and functions.
29*/
30
31//==============================================================================
32// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
33
35using int8 = signed char;
37using uint8 = unsigned char;
39using int16 = signed short;
41using uint16 = unsigned short;
43using int32 = signed int;
45using uint32 = unsigned int;
46
47#if JUCE_MSVC
49 using int64 = __int64;
51 using uint64 = unsigned __int64;
52#else
54 using int64 = long long;
56 using uint64 = unsigned long long;
57#endif
58
59#ifndef DOXYGEN
65 #define literal64bit(longLiteral) (longLiteral##LL)
66#endif
67
68#if JUCE_64BIT
70 using pointer_sized_int = int64;
72 using pointer_sized_uint = uint64;
73#elif JUCE_MSVC
75 using pointer_sized_int = _W64 int;
77 using pointer_sized_uint = _W64 unsigned int;
78#else
80 using pointer_sized_int = int;
82 using pointer_sized_uint = unsigned int;
83#endif
84
85#if JUCE_WINDOWS && ! JUCE_MINGW
86 using ssize_t = pointer_sized_int;
87#endif
88
89//==============================================================================
91template <typename... Types>
92void ignoreUnused (Types&&...) noexcept {}
93
102template <typename Type, size_t N>
103constexpr int numElementsInArray (Type (&)[N]) noexcept { return N; }
104
105//==============================================================================
106// Some useful maths functions that aren't always present with all compilers and build settings.
107
110template <typename Type>
111Type juce_hypot (Type a, Type b) noexcept
112{
113 #if JUCE_MSVC
114 return static_cast<Type> (_hypot (a, b));
115 #else
116 return static_cast<Type> (hypot (a, b));
117 #endif
118}
119
120#ifndef DOXYGEN
121template <>
122inline float juce_hypot (float a, float b) noexcept
123{
124 #if JUCE_MSVC
125 return _hypotf (a, b);
126 #else
127 return hypotf (a, b);
128 #endif
129}
130#endif
131
132//==============================================================================
137template <typename FloatType>
138 struct MathConstants
139{
141 static constexpr FloatType pi = static_cast<FloatType> (3.141592653589793238L);
142
144 static constexpr FloatType twoPi = static_cast<FloatType> (2 * 3.141592653589793238L);
145
147 static constexpr FloatType halfPi = static_cast<FloatType> (3.141592653589793238L / 2);
148
150 static constexpr FloatType euler = static_cast<FloatType> (2.71828182845904523536L);
151
153 static constexpr FloatType sqrt2 = static_cast<FloatType> (1.4142135623730950488L);
154};
155
156#ifndef DOXYGEN
158[[deprecated ("This is deprecated in favour of MathConstants<double>::pi.")]]
159const constexpr double double_Pi = MathConstants<double>::pi;
160
162[[deprecated ("This is deprecated in favour of MathConstants<float>::pi.")]]
163const constexpr float float_Pi = MathConstants<float>::pi;
164#endif
165
167template <typename FloatType>
168constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants<FloatType>::pi / FloatType (180)); }
169
171template <typename FloatType>
172constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants<FloatType>::pi); }
173
174//==============================================================================
178template <typename NumericType>
179bool juce_isfinite (NumericType value) noexcept
180{
181 if constexpr (std::numeric_limits<NumericType>::has_infinity
182 || std::numeric_limits<NumericType>::has_quiet_NaN
183 || std::numeric_limits<NumericType>::has_signaling_NaN)
184 {
185 return std::isfinite (value);
186 }
187 else
188 {
189 ignoreUnused (value);
190 return true;
191 }
192}
193
194//==============================================================================
200template <typename Type>
201constexpr bool exactlyEqual (Type a, Type b)
202{
203 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfloat-equal")
204 return a == b;
205 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
206}
207
214template <typename Type>
215class Tolerance
216{
217public:
218 Tolerance() = default;
219
227 [[nodiscard]] Tolerance withAbsolute (Type newAbsolute)
228 {
229 return withMember (*this, &Tolerance::absolute, std::abs (newAbsolute));
230 }
231
239 [[nodiscard]] Tolerance withRelative (Type newRelative)
240 {
241 return withMember (*this, &Tolerance::relative, std::abs (newRelative));
242 }
243
244 [[nodiscard]] Type getAbsolute() const { return absolute; }
245 [[nodiscard]] Type getRelative() const { return relative; }
246
247private:
248 Type absolute{};
249 Type relative{};
250};
251
256template <typename Type>
257static Tolerance<Type> absoluteTolerance (Type tolerance)
258{
259 return Tolerance<Type>{}.withAbsolute (tolerance);
260}
261
266template <typename Type>
267static Tolerance<Type> relativeTolerance (Type tolerance)
268{
269 return Tolerance<Type>{}.withRelative (tolerance);
270}
271
272
298template <typename Type, std::enable_if_t<std::is_floating_point_v<Type>, int> = 0>
299constexpr bool approximatelyEqual (Type a, Type b,
300 Tolerance<Type> tolerance = Tolerance<Type>{}
301 .withAbsolute (std::numeric_limits<Type>::min())
302 .withRelative (std::numeric_limits<Type>::epsilon()))
303{
304 if (! (juce_isfinite (a) && juce_isfinite (b)))
305 return exactlyEqual (a, b);
306
307 const auto diff = std::abs (a - b);
308
309 return diff <= tolerance.getAbsolute()
310 || diff <= tolerance.getRelative() * std::max (std::abs (a), std::abs (b));
311}
312
314template <typename Type, std::enable_if_t<! std::is_floating_point_v<Type>, int> = 0>
315constexpr bool approximatelyEqual (Type a, Type b)
316{
317 return a == b;
318}
319
320//==============================================================================
322template <typename FloatType>
323FloatType nextFloatUp (FloatType value) noexcept
324{
325 return std::nextafter (value, std::numeric_limits<FloatType>::max());
326}
327
329template <typename FloatType>
330FloatType nextFloatDown (FloatType value) noexcept
331{
332 return std::nextafter (value, std::numeric_limits<FloatType>::lowest());
333}
334
335//==============================================================================
336// Some indispensable min/max functions
337
339template <typename Type>
340constexpr Type jmax (Type a, Type b) { return a < b ? b : a; }
341
343template <typename Type>
344constexpr Type jmax (Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); }
345
347template <typename Type>
348constexpr Type jmax (Type a, Type b, Type c, Type d) { return jmax (a, jmax (b, c, d)); }
349
351template <typename Type>
352constexpr Type jmin (Type a, Type b) { return b < a ? b : a; }
353
355template <typename Type>
356constexpr Type jmin (Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); }
357
359template <typename Type>
360constexpr Type jmin (Type a, Type b, Type c, Type d) { return jmin (a, jmin (b, c, d)); }
361
365template <typename Type>
366constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax)
367{
368 return targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin);
369}
370
372template <typename Type>
373Type jmap (Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax)
374{
375 jassert (! approximatelyEqual (sourceRangeMax, sourceRangeMin)); // mapping from a range of zero will produce NaN!
376 return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin);
377}
378
389template <typename Type>
390Type mapToLog10 (Type value0To1, Type logRangeMin, Type logRangeMax)
391{
392 jassert (logRangeMin > 0);
393 jassert (logRangeMax > 0);
394
395 auto logMin = std::log10 (logRangeMin);
396 auto logMax = std::log10 (logRangeMax);
397
398 return std::pow ((Type) 10.0, value0To1 * (logMax - logMin) + logMin);
399}
400
411template <typename Type>
412Type mapFromLog10 (Type valueInLogRange, Type logRangeMin, Type logRangeMax)
413{
414 jassert (logRangeMin > 0);
415 jassert (logRangeMax > 0);
416
417 auto logMin = std::log10 (logRangeMin);
418 auto logMax = std::log10 (logRangeMax);
419
420 return (std::log10 (valueInLogRange) - logMin) / (logMax - logMin);
421}
422
424template <typename Type, typename Size>
425Type findMinimum (const Type* data, Size numValues)
426{
427 if (numValues <= 0)
428 return Type (0);
429
430 auto result = *data++;
431
432 while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
433 {
434 auto v = *data++;
435
436 if (v < result)
437 result = v;
438 }
439
440 return result;
441}
442
444template <typename Type, typename Size>
445Type findMaximum (const Type* values, Size numValues)
446{
447 if (numValues <= 0)
448 return Type (0);
449
450 auto result = *values++;
451
452 while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
453 {
454 auto v = *values++;
455
456 if (result < v)
457 result = v;
458 }
459
460 return result;
461}
462
464template <typename Type>
465void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
466{
467 if (numValues <= 0)
468 {
469 lowest = Type (0);
470 highest = Type (0);
471 }
472 else
473 {
474 auto mn = *values++;
475 auto mx = mn;
476
477 while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
478 {
479 auto v = *values++;
480
481 if (mx < v) mx = v;
482 if (v < mn) mn = v;
483 }
484
485 lowest = mn;
486 highest = mx;
487 }
488}
489
490//==============================================================================
507template <typename Type>
508Type jlimit (Type lowerLimit,
509 Type upperLimit,
510 Type valueToConstrain) noexcept
511{
512 jassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
513
514 return valueToConstrain < lowerLimit ? lowerLimit
515 : (upperLimit < valueToConstrain ? upperLimit
516 : valueToConstrain);
517}
518
524template <typename Type1, typename Type2>
525bool isPositiveAndBelow (Type1 valueToTest, Type2 upperLimit) noexcept
526{
527 jassert (Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
528 return Type1() <= valueToTest && valueToTest < static_cast<Type1> (upperLimit);
529}
530
531template <typename Type>
532bool isPositiveAndBelow (int valueToTest, Type upperLimit) noexcept
533{
534 jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
535 return static_cast<unsigned int> (valueToTest) < static_cast<unsigned int> (upperLimit);
536}
537
543template <typename Type1, typename Type2>
544bool isPositiveAndNotGreaterThan (Type1 valueToTest, Type2 upperLimit) noexcept
545{
546 jassert (Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
547 return Type1() <= valueToTest && valueToTest <= static_cast<Type1> (upperLimit);
548}
549
550template <typename Type>
551bool isPositiveAndNotGreaterThan (int valueToTest, Type upperLimit) noexcept
552{
553 jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
554 return static_cast<unsigned int> (valueToTest) <= static_cast<unsigned int> (upperLimit);
555}
556
560template <typename Type>
561bool isWithin (Type a, Type b, Type tolerance) noexcept
562{
563 return std::abs (a - b) <= tolerance;
564}
565
566//==============================================================================
567#if JUCE_MSVC
568 #pragma optimize ("t", off)
569 #ifndef __INTEL_COMPILER
570 #pragma float_control (precise, on, push)
571 #endif
572#endif
573
584template <typename FloatType>
585int roundToInt (const FloatType value) noexcept
586{
587 #ifdef __INTEL_COMPILER
588 #pragma float_control (precise, on, push)
589 #endif
590
591 union { int asInt[2]; double asDouble; } n;
592 n.asDouble = ((double) value) + 6755399441055744.0;
593
594 #if JUCE_BIG_ENDIAN
595 return n.asInt [1];
596 #else
597 return n.asInt [0];
598 #endif
599}
600
601inline int roundToInt (int value) noexcept
602{
603 return value;
604}
605
606#if JUCE_MSVC
607 #ifndef __INTEL_COMPILER
608 #pragma float_control (pop)
609 #endif
610 #pragma optimize ("", on) // resets optimisations to the project defaults
611#endif
612
618inline int roundToIntAccurate (double value) noexcept
619{
620 #ifdef __INTEL_COMPILER
621 #pragma float_control (pop)
622 #endif
623
624 return roundToInt (value + 1.5e-8);
625}
626
627//==============================================================================
634template <typename FloatType>
635unsigned int truncatePositiveToUnsignedInt (FloatType value) noexcept
636{
637 jassert (value >= static_cast<FloatType> (0));
638 jassert (static_cast<FloatType> (value)
639 <= static_cast<FloatType> (std::numeric_limits<unsigned int>::max()));
640
641 return static_cast<unsigned int> (value);
642}
643
644//==============================================================================
646template <typename IntegerType>
647constexpr bool isPowerOfTwo (IntegerType value)
648{
649 return (value & (value - 1)) == 0;
650}
651
653inline int nextPowerOfTwo (int n) noexcept
654{
655 --n;
656 n |= (n >> 1);
657 n |= (n >> 2);
658 n |= (n >> 4);
659 n |= (n >> 8);
660 n |= (n >> 16);
661 return n + 1;
662}
663
668int findHighestSetBit (uint32 n) noexcept;
669
671constexpr int countNumberOfBits (uint32 n) noexcept
672{
673 n -= ((n >> 1) & 0x55555555);
674 n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
675 n = (((n >> 4) + n) & 0x0f0f0f0f);
676 n += (n >> 8);
677 n += (n >> 16);
678 return (int) (n & 0x3f);
679}
680
682constexpr int countNumberOfBits (uint64 n) noexcept
683{
684 return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
685}
686
690template <typename IntegerType>
691IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
692{
693 jassert (divisor > 0);
694 dividend %= divisor;
695 return (dividend < 0) ? (dividend + divisor) : dividend;
696}
697
699template <typename NumericType>
700inline constexpr NumericType square (NumericType n) noexcept
701{
702 return n * n;
703}
704
705//==============================================================================
713void writeLittleEndianBitsInBuffer (void* targetBuffer, uint32 startBit, uint32 numBits, uint32 value) noexcept;
714
722uint32 readLittleEndianBitsInBuffer (const void* sourceBuffer, uint32 startBit, uint32 numBits) noexcept;
723
724
725//==============================================================================
726#if JUCE_INTEL || DOXYGEN
731 #define JUCE_UNDENORMALISE(x) { (x) += 0.1f; (x) -= 0.1f; }
732#else
733 #define JUCE_UNDENORMALISE(x)
734#endif
735
736//==============================================================================
739 namespace TypeHelpers
740{
752 template <typename Type> struct ParameterType { using type = const Type&; };
753
754 #ifndef DOXYGEN
755 template <typename Type> struct ParameterType <Type&> { using type = Type&; };
756 template <typename Type> struct ParameterType <Type*> { using type = Type*; };
757 template <> struct ParameterType <char> { using type = char; };
758 template <> struct ParameterType <unsigned char> { using type = unsigned char; };
759 template <> struct ParameterType <short> { using type = short; };
760 template <> struct ParameterType <unsigned short> { using type = unsigned short; };
761 template <> struct ParameterType <int> { using type = int; };
762 template <> struct ParameterType <unsigned int> { using type = unsigned int; };
763 template <> struct ParameterType <long> { using type = long; };
764 template <> struct ParameterType <unsigned long> { using type = unsigned long; };
765 template <> struct ParameterType <int64> { using type = int64; };
766 template <> struct ParameterType <uint64> { using type = uint64; };
767 template <> struct ParameterType <bool> { using type = bool; };
768 template <> struct ParameterType <float> { using type = float; };
769 template <> struct ParameterType <double> { using type = double; };
770 #endif
771
777 template <typename Type>
778 using SmallestFloatType = std::conditional_t<std::is_same_v<Type, double>, double, float>;
779
785 template <int bytes> struct UnsignedTypeWithSize {};
786
787 #ifndef DOXYGEN
788 template <> struct UnsignedTypeWithSize<1> { using type = uint8; };
789 template <> struct UnsignedTypeWithSize<2> { using type = uint16; };
790 template <> struct UnsignedTypeWithSize<4> { using type = uint32; };
791 template <> struct UnsignedTypeWithSize<8> { using type = uint64; };
792 #endif
793}
794
795//==============================================================================
796#ifndef DOXYGEN
797 [[deprecated ("Use roundToInt instead.")]] inline int roundDoubleToInt (double value) noexcept { return roundToInt (value); }
798 [[deprecated ("Use roundToInt instead.")]] inline int roundFloatToInt (float value) noexcept { return roundToInt (value); }
799 [[deprecated ("Use std::abs() instead.")]] inline int64 abs64 (int64 n) noexcept { return std::abs (n); }
800#endif
801
805template <typename T>
806constexpr auto toUnderlyingType (T t) -> std::enable_if_t<std::is_enum_v<T>, std::underlying_type_t<T>>
807{
808 return static_cast<std::underlying_type_t<T>> (t);
809}
810
811} // namespace juce
juce::Tolerance
Definition juce_MathsFunctions.h:216
juce::Tolerance::withRelative
Tolerance withRelative(Type newRelative)
Definition juce_MathsFunctions.h:239
juce::Tolerance::withAbsolute
Tolerance withAbsolute(Type newAbsolute)
Definition juce_MathsFunctions.h:227
juce::TypeHelpers
Definition juce_MathsFunctions.h:740
juce::TypeHelpers::SmallestFloatType
std::conditional_t< std::is_same_v< Type, double >, double, float > SmallestFloatType
Definition juce_MathsFunctions.h:778
juce::TypeHelpers::ParameterType
Definition juce_MathsFunctions.h:752
juce::TypeHelpers::UnsignedTypeWithSize
Definition juce_MathsFunctions.h:785
juce::MathConstants
Definition juce_MathsFunctions.h:139
juce::MathConstants::halfPi
static constexpr FloatType halfPi
Definition juce_MathsFunctions.h:147
juce::MathConstants::twoPi
static constexpr FloatType twoPi
Definition juce_MathsFunctions.h:144
juce::MathConstants::sqrt2
static constexpr FloatType sqrt2
Definition juce_MathsFunctions.h:153
juce::MathConstants::pi
static constexpr FloatType pi
Definition juce_MathsFunctions.h:141
juce::MathConstants::euler
static constexpr FloatType euler
Definition juce_MathsFunctions.h:150