OpenShot Audio Library | OpenShotAudio  0.6.0
juce_LookupTable.cpp
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  By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11  Agreement and JUCE Privacy Policy.
12 
13  End User License Agreement: www.juce.com/juce-7-licence
14  Privacy Policy: www.juce.com/juce-privacy-policy
15 
16  Or: You may also use this code under the terms of the GPL v3 (see
17  www.gnu.org/licenses).
18 
19  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21  DISCLAIMED.
22 
23  ==============================================================================
24 */
25 
26 namespace juce::dsp
27 {
28 
29 template <typename FloatType>
31 {
32  data.resize (1);
33 }
34 
35 template <typename FloatType>
36 LookupTable<FloatType>::LookupTable (const std::function<FloatType (size_t)>& functionToApproximate,
37  size_t numPointsToUse)
38 {
39  initialise (functionToApproximate, numPointsToUse);
40 }
41 
42 //==============================================================================
43 template <typename FloatType>
44 void LookupTable<FloatType>::initialise (const std::function<FloatType (size_t)>& functionToApproximate,
45  size_t numPointsToUse)
46 {
47  data.resize (static_cast<int> (getRequiredBufferSize (numPointsToUse)));
48 
49  for (size_t i = 0; i < numPointsToUse; ++i)
50  {
51  auto value = functionToApproximate (i);
52 
53  jassert (! std::isnan (value));
54  jassert (! std::isinf (value));
55  // Make sure functionToApproximate returns a sensible value for the entire specified range.
56  // E.g., this won't work for zero: [] (size_t i) { return 1.0f / i; }
57 
58  data.getReference (static_cast<int> (i)) = value;
59  }
60 
61  prepare();
62 }
63 
64 template <typename FloatType>
65 void LookupTable<FloatType>::prepare() noexcept
66 {
67  auto guardIndex = static_cast<int> (getGuardIndex());
68  data.getReference (guardIndex) = data.getUnchecked (guardIndex - 1);
69 }
70 
71 template <typename FloatType>
72 void LookupTableTransform<FloatType>::initialise (const std::function<FloatType (FloatType)>& functionToApproximate,
73  FloatType minInputValueToUse,
74  FloatType maxInputValueToUse,
75  size_t numPoints)
76 {
77  jassert (maxInputValueToUse > minInputValueToUse);
78 
79  minInputValue = minInputValueToUse;
80  maxInputValue = maxInputValueToUse;
81  scaler = FloatType (numPoints - 1) / (maxInputValueToUse - minInputValueToUse);
82  offset = -minInputValueToUse * scaler;
83 
84  const auto initFn = [functionToApproximate, minInputValueToUse, maxInputValueToUse, numPoints] (size_t i)
85  {
86  return functionToApproximate (
87  jlimit (
88  minInputValueToUse, maxInputValueToUse,
89  jmap (FloatType (i), FloatType (0), FloatType (numPoints - 1), minInputValueToUse, maxInputValueToUse))
90  );
91  };
92 
93  lookupTable.initialise (initFn, numPoints);
94 }
95 
96 //==============================================================================
97 template <typename FloatType>
98 double LookupTableTransform<FloatType>::calculateMaxRelativeError (const std::function<FloatType (FloatType)>& functionToApproximate,
99  FloatType minInputValue,
100  FloatType maxInputValue,
101  size_t numPoints,
102  size_t numTestPoints)
103 {
104  jassert (maxInputValue > minInputValue);
105 
106  if (numTestPoints == 0)
107  numTestPoints = 100 * numPoints; // use default
108 
109  LookupTableTransform transform (functionToApproximate, minInputValue, maxInputValue, numPoints);
110 
111  double maxError = 0;
112 
113  for (size_t i = 0; i < numTestPoints; ++i)
114  {
115  auto inputValue = jmap (FloatType (i), FloatType (0), FloatType (numTestPoints - 1), minInputValue, maxInputValue);
116  auto approximatedOutputValue = transform.processSample (inputValue);
117  auto referenceOutputValue = functionToApproximate (inputValue);
118 
119  maxError = jmax (maxError, calculateRelativeDifference ((double) referenceOutputValue, (double) approximatedOutputValue));
120  }
121 
122  return maxError;
123 }
124 
125 //==============================================================================
126 template <typename FloatType>
127 double LookupTableTransform<FloatType>::calculateRelativeDifference (double x, double y) noexcept
128 {
129  static const auto eps = std::numeric_limits<double>::min();
130 
131  auto absX = std::abs (x);
132  auto absY = std::abs (y);
133  auto absDiff = std::abs (x - y);
134 
135  if (absX < eps)
136  {
137  if (absY >= eps)
138  return absDiff / absY;
139 
140  return absDiff; // return the absolute error if both numbers are too close to zero
141  }
142 
143  return absDiff / std::min (absX, absY);
144 }
145 
146 //==============================================================================
147 template class LookupTable<float>;
148 template class LookupTable<double>;
149 
150 template class LookupTableTransform<float>;
151 template class LookupTableTransform<double>;
152 
153 } // namespace juce::dsp
void initialise(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValueToUse, FloatType maxInputValueToUse, size_t numPoints)
FloatType processSample(FloatType value) const noexcept
static double calculateMaxRelativeError(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValue, FloatType maxInputValue, size_t numPoints, size_t numTestPoints=0)
FloatType getUnchecked(FloatType index) const noexcept
void initialise(const std::function< FloatType(size_t)> &functionToApproximate, size_t numPointsToUse)