OpenShot Audio Library | OpenShotAudio  0.6.0
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 
23 namespace 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 
35 using int8 = signed char;
37 using uint8 = unsigned char;
39 using int16 = signed short;
41 using uint16 = unsigned short;
43 using int32 = signed int;
45 using 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 //==============================================================================
91 template <typename... Types>
92 void ignoreUnused (Types&&...) noexcept {}
93 
102 template <typename Type, size_t N>
103 constexpr 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 
110 template <typename Type>
111 Type 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
121 template <>
122 inline 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 //==============================================================================
137 template <typename FloatType>
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.")]]
159 const constexpr double double_Pi = MathConstants<double>::pi;
160 
162 [[deprecated ("This is deprecated in favour of MathConstants<float>::pi.")]]
163 const constexpr float float_Pi = MathConstants<float>::pi;
164 #endif
165 
167 template <typename FloatType>
168 constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants<FloatType>::pi / FloatType (180)); }
169 
171 template <typename FloatType>
172 constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants<FloatType>::pi); }
173 
174 //==============================================================================
178 template <typename NumericType>
179 bool 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 //==============================================================================
200 template <typename Type>
201 constexpr 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 
214 template <typename Type>
216 {
217 public:
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 
247 private:
248  Type absolute{};
249  Type relative{};
250 };
251 
256 template <typename Type>
257 static Tolerance<Type> absoluteTolerance (Type tolerance)
258 {
259  return Tolerance<Type>{}.withAbsolute (tolerance);
260 }
261 
266 template <typename Type>
267 static Tolerance<Type> relativeTolerance (Type tolerance)
268 {
269  return Tolerance<Type>{}.withRelative (tolerance);
270 }
271 
272 
298 template <typename Type, std::enable_if_t<std::is_floating_point_v<Type>, int> = 0>
299 constexpr 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 
314 template <typename Type, std::enable_if_t<! std::is_floating_point_v<Type>, int> = 0>
315 constexpr bool approximatelyEqual (Type a, Type b)
316 {
317  return a == b;
318 }
319 
320 //==============================================================================
322 template <typename FloatType>
323 FloatType nextFloatUp (FloatType value) noexcept
324 {
325  return std::nextafter (value, std::numeric_limits<FloatType>::max());
326 }
327 
329 template <typename FloatType>
330 FloatType 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 
339 template <typename Type>
340 constexpr Type jmax (Type a, Type b) { return a < b ? b : a; }
341 
343 template <typename Type>
344 constexpr Type jmax (Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); }
345 
347 template <typename Type>
348 constexpr Type jmax (Type a, Type b, Type c, Type d) { return jmax (a, jmax (b, c, d)); }
349 
351 template <typename Type>
352 constexpr Type jmin (Type a, Type b) { return b < a ? b : a; }
353 
355 template <typename Type>
356 constexpr Type jmin (Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); }
357 
359 template <typename Type>
360 constexpr Type jmin (Type a, Type b, Type c, Type d) { return jmin (a, jmin (b, c, d)); }
361 
365 template <typename Type>
366 constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax)
367 {
368  return targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin);
369 }
370 
372 template <typename Type>
373 Type 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 
389 template <typename Type>
390 Type 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 
411 template <typename Type>
412 Type 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 
424 template <typename Type, typename Size>
425 Type 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 
444 template <typename Type, typename Size>
445 Type 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 
464 template <typename Type>
465 void 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 //==============================================================================
507 template <typename Type>
508 Type 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 
524 template <typename Type1, typename Type2>
525 bool 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 
531 template <typename Type>
532 bool 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 
543 template <typename Type1, typename Type2>
544 bool 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 
550 template <typename Type>
551 bool 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 
560 template <typename Type>
561 bool 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 
584 template <typename FloatType>
585 int 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 
601 inline 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 
618 inline 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 //==============================================================================
634 template <typename FloatType>
635 unsigned 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 //==============================================================================
646 template <typename IntegerType>
647 constexpr bool isPowerOfTwo (IntegerType value)
648 {
649  return (value & (value - 1)) == 0;
650 }
651 
653 inline 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 
668 int findHighestSetBit (uint32 n) noexcept;
669 
671 constexpr 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 
682 constexpr int countNumberOfBits (uint64 n) noexcept
683 {
684  return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
685 }
686 
690 template <typename IntegerType>
691 IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
692 {
693  jassert (divisor > 0);
694  dividend %= divisor;
695  return (dividend < 0) ? (dividend + divisor) : dividend;
696 }
697 
699 template <typename NumericType>
700 inline constexpr NumericType square (NumericType n) noexcept
701 {
702  return n * n;
703 }
704 
705 //==============================================================================
713 void writeLittleEndianBitsInBuffer (void* targetBuffer, uint32 startBit, uint32 numBits, uint32 value) noexcept;
714 
722 uint32 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 
805 template <typename T>
806 constexpr 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
Tolerance withRelative(Type newRelative)
Tolerance withAbsolute(Type newAbsolute)
std::conditional_t< std::is_same_v< Type, double >, double, float > SmallestFloatType
static constexpr FloatType halfPi
static constexpr FloatType twoPi
static constexpr FloatType sqrt2
static constexpr FloatType pi
static constexpr FloatType euler