OpenShot Library | OpenShotAudio  0.2.1
juce_LookupTable.h
1 
2 /** @weakgroup juce_dsp-maths
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
15  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
16  27th April 2017).
17 
18  End User License Agreement: www.juce.com/juce-5-licence
19  Privacy Policy: www.juce.com/juce-5-privacy-policy
20 
21  Or: You may also use this code under the terms of the GPL v3 (see
22  www.gnu.org/licenses).
23 
24  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
25  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
26  DISCLAIMED.
27 
28  ==============================================================================
29 */
30 
31 namespace juce
32 {
33 namespace dsp
34 {
35 
36 /**
37  Class for efficiently approximating expensive arithmetic operations.
38 
39  The approximation is based on linear interpolation between pre-calculated values.
40  The approximated function should be passed as a callable object to the constructor
41  along with the number of data points to be pre-calculated. The accuracy of the
42  approximation can be increased by using more points at the cost of a larger memory
43  footprint.
44 
45  Consider using LookupTableTransform as an easy-to-use alternative.
46 
47  Example:
48 
49  LookupTable<float> lut ([] (size_t i) { return std::sqrt ((float) i); }, 64);
50  auto outValue = lut[17];
51 
52  @see LookupTableTransform
53 
54  @tags{DSP}
55 */
56 template <typename FloatType>
58 {
59 public:
60  /** Creates an uninitialised LookupTable object.
61 
62  You need to call initialise() before using the object. Prefer using the
63  non-default constructor instead.
64 
65  @see initialise
66  */
67  LookupTable();
68 
69  /** Creates and initialises a LookupTable object.
70 
71  @param functionToApproximate The function to be approximated. This should be a
72  mapping from the integer range [0, numPointsToUse - 1].
73  @param numPointsToUse The number of pre-calculated values stored.
74  */
75  LookupTable (const std::function<FloatType(size_t)>& functionToApproximate, size_t numPointsToUse);
76 
77  /** Initialises or changes the parameters of a LookupTable object.
78 
79  This function can be used to change what function is approximated by an already
80  constructed LookupTable along with the number of data points used. If the function
81  to be approximated won't ever change, prefer using the non-default constructor.
82 
83  @param functionToApproximate The function to be approximated. This should be a
84  mapping from the integer range [0, numPointsToUse - 1].
85  @param numPointsToUse The number of pre-calculated values stored.
86  */
87  void initialise (const std::function<FloatType(size_t)>& functionToApproximate, size_t numPointsToUse);
88 
89  //==============================================================================
90  /** Calculates the approximated value for the given index without range checking.
91 
92  Use this if you can guarantee that the index is non-negative and less than numPoints.
93  Otherwise use get().
94 
95  @param index The approximation is calculated for this non-integer index.
96  @return The approximated value at the given index.
97 
98  @see get, operator[]
99  */
100  FloatType getUnchecked (FloatType index) const noexcept
101  {
102  jassert (isInitialised()); // Use the non-default constructor or call initialise() before first use
103  jassert (isPositiveAndBelow (index, FloatType (getNumPoints())));
104 
105  auto i = truncatePositiveToUnsignedInt (index);
106  auto f = index - FloatType (i);
107  jassert (isPositiveAndBelow (f, FloatType (1)));
108 
109  auto x0 = data.getUnchecked (static_cast<int> (i));
110  auto x1 = data.getUnchecked (static_cast<int> (i + 1));
111 
112  return jmap (f, x0, x1);
113  }
114 
115  //==============================================================================
116  /** Calculates the approximated value for the given index with range checking.
117 
118  This can be called with any input indices. If the provided index is out-of-range
119  either the bottom or the top element of the LookupTable is returned.
120 
121  If the index is guaranteed to be in range use the faster getUnchecked() instead.
122 
123  @param index The approximation is calculated for this non-integer index.
124  @return The approximated value at the given index.
125 
126  @see getUnchecked, operator[]
127  */
128  FloatType get (FloatType index) const noexcept
129  {
130  if (index >= getNumPoints())
131  index = static_cast<FloatType> (getGuardIndex());
132  else if (index < 0)
133  index = {};
134 
135  return getUnchecked (index);
136  }
137 
138  //==============================================================================
139  /** @see getUnchecked */
140  FloatType operator[] (FloatType index) const noexcept { return getUnchecked (index); }
141 
142  /** Returns the size of the LookupTable, i.e., the number of pre-calculated data points. */
143  size_t getNumPoints() const noexcept { return static_cast<size_t> (data.size()) - 1; }
144 
145  /** Returns true if the LookupTable is initialised and ready to be used. */
146  bool isInitialised() const noexcept { return data.size() > 1; }
147 
148 private:
149  //==============================================================================
150  Array<FloatType> data;
151 
152  void prepare() noexcept;
153  static size_t getRequiredBufferSize (size_t numPointsToUse) noexcept { return numPointsToUse + 1; }
154  size_t getGuardIndex() const noexcept { return getRequiredBufferSize (getNumPoints()) - 1; }
155 
156  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookupTable)
157 };
158 
159 
160 //==============================================================================
161 /** Class for approximating expensive arithmetic operations.
162 
163  Once initialised, this class can be used just like the function it approximates
164  via operator().
165 
166  Example:
167 
168  LookupTableTransform<float> tanhApprox ([] (float x) { return std::tanh (x); }, -5.0f, 5.0f, 64);
169  auto outValue = tanhApprox (4.2f);
170 
171  Note: If you try to call the function with an input outside the provided
172  range, it will return either the first or the last recorded LookupTable value.
173 
174  @see LookupTable
175 
176  @tags{DSP}
177 */
178 template <typename FloatType>
180 {
181 public:
182  //==============================================================================
183  /** Creates an uninitialised LookupTableTransform object.
184 
185  You need to call initialise() before using the object. Prefer using the
186  non-default constructor instead.
187 
188  @see initialise
189  */
190  LookupTableTransform() = default;
191 
192  //==============================================================================
193  /** Creates and initialises a LookupTableTransform object.
194 
195  @param functionToApproximate The function to be approximated. This should be a
196  mapping from a FloatType to FloatType.
197  @param minInputValueToUse The lowest input value used. The approximation will
198  fail for values lower than this.
199  @param maxInputValueToUse The highest input value used. The approximation will
200  fail for values higher than this.
201  @param numPoints The number of pre-calculated values stored.
202  */
203  LookupTableTransform (const std::function<FloatType(FloatType)>& functionToApproximate,
204  FloatType minInputValueToUse,
205  FloatType maxInputValueToUse,
206  size_t numPoints)
207  {
208  initialise (functionToApproximate, minInputValueToUse, maxInputValueToUse, numPoints);
209  }
210 
211  //==============================================================================
212  /** Initialises or changes the parameters of a LookupTableTransform object.
213 
214  @param functionToApproximate The function to be approximated. This should be a
215  mapping from a FloatType to FloatType.
216  @param minInputValueToUse The lowest input value used. The approximation will
217  fail for values lower than this.
218  @param maxInputValueToUse The highest input value used. The approximation will
219  fail for values higher than this.
220  @param numPoints The number of pre-calculated values stored.
221  */
222  void initialise (const std::function<FloatType(FloatType)>& functionToApproximate,
223  FloatType minInputValueToUse,
224  FloatType maxInputValueToUse,
225  size_t numPoints);
226 
227  //==============================================================================
228  /** Calculates the approximated value for the given input value without range checking.
229 
230  Use this if you can guarantee that the input value is within the range specified
231  in the constructor or initialise(), otherwise use processSample().
232 
233  @param value The approximation is calculated for this input value.
234  @return The approximated value for the provided input value.
235 
236  @see processSample, operator(), operator[]
237  */
238  FloatType processSampleUnchecked (FloatType value) const noexcept
239  {
240  jassert (value >= minInputValue && value <= maxInputValue);
241  return lookupTable[scaler * value + offset];
242  }
243 
244  //==============================================================================
245  /** Calculates the approximated value for the given input value with range checking.
246 
247  This can be called with any input values. Out-of-range input values will be
248  clipped to the specified input range.
249 
250  If the index is guaranteed to be in range use the faster processSampleUnchecked()
251  instead.
252 
253  @param value The approximation is calculated for this input value.
254  @return The approximated value for the provided input value.
255 
256  @see processSampleUnchecked, operator(), operator[]
257  */
258  FloatType processSample (FloatType value) const noexcept
259  {
260  auto index = scaler * jlimit (minInputValue, maxInputValue, value) + offset;
261  jassert (isPositiveAndBelow (index, FloatType (lookupTable.getNumPoints())));
262 
263  return lookupTable[index];
264  }
265 
266  //==============================================================================
267  /** @see processSampleUnchecked */
268  FloatType operator[] (FloatType index) const noexcept { return processSampleUnchecked (index); }
269 
270  /** @see processSample */
271  FloatType operator() (FloatType index) const noexcept { return processSample (index); }
272 
273  //==============================================================================
274  /** Processes an array of input values without range checking
275  @see process
276  */
277  void processUnchecked (const FloatType* input, FloatType* output, size_t numSamples) const noexcept
278  {
279  for (size_t i = 0; i < numSamples; ++i)
280  output[i] = processSampleUnchecked (input[i]);
281  }
282 
283  //==============================================================================
284  /** Processes an array of input values with range checking
285  @see processUnchecked
286  */
287  void process (const FloatType* input, FloatType* output, size_t numSamples) const noexcept
288  {
289  for (size_t i = 0; i < numSamples; ++i)
290  output[i] = processSample (input[i]);
291  }
292 
293  //==============================================================================
294  /** Calculates the maximum relative error of the approximation for the specified
295  parameter set.
296 
297  The closer the returned value is to zero the more accurate the approximation
298  is.
299 
300  This function compares the approximated output of this class to the function
301  it approximates at a range of points and returns the maximum relative error.
302  This can be used to determine if the approximation is suitable for the given
303  problem. The accuracy of the approximation can generally be improved by
304  increasing numPoints.
305 
306  @param functionToApproximate The approximated function. This should be a
307  mapping from a FloatType to FloatType.
308  @param minInputValue The lowest input value used.
309  @param maxInputValue The highest input value used.
310  @param numPoints The number of pre-calculated values stored.
311  @param numTestPoints The number of input values used for error
312  calculation. Higher numbers can increase the
313  accuracy of the error calculation. If it's zero
314  then 100 * numPoints will be used.
315  */
316  static double calculateMaxRelativeError (const std::function<FloatType(FloatType)>& functionToApproximate,
317  FloatType minInputValue,
318  FloatType maxInputValue,
319  size_t numPoints,
320  size_t numTestPoints = 0);
321 private:
322  //==============================================================================
323  static double calculateRelativeDifference (double, double) noexcept;
324 
325  //==============================================================================
326  LookupTable<FloatType> lookupTable;
327 
328  FloatType minInputValue, maxInputValue;
329  FloatType scaler, offset;
330 
331  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookupTableTransform)
332 };
333 
334 } // namespace dsp
335 } // namespace juce
336 
337 /** @}*/
void initialise(const std::function< FloatType(size_t)> &functionToApproximate, size_t numPointsToUse)
Initialises or changes the parameters of a LookupTable object.
FloatType processSample(FloatType value) const noexcept
Calculates the approximated value for the given input value with range checking.
size_t getNumPoints() const noexcept
Returns the size of the LookupTable, i.e., the number of pre-calculated data points.
FloatType getUnchecked(FloatType index) const noexcept
Calculates the approximated value for the given index without range checking.
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
Definition: juce_Array.h:256
FloatType operator[](FloatType index) const noexcept
LookupTable()
Creates an uninitialised LookupTable object.
Class for approximating expensive arithmetic operations.
Class for efficiently approximating expensive arithmetic operations.
bool isInitialised() const noexcept
Returns true if the LookupTable is initialised and ready to be used.
void processUnchecked(const FloatType *input, FloatType *output, size_t numSamples) const noexcept
Processes an array of input values without range checking.
int size() const noexcept
Returns the current number of elements in the array.
Definition: juce_Array.h:219
void process(const FloatType *input, FloatType *output, size_t numSamples) const noexcept
Processes an array of input values with range checking.
LookupTableTransform(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValueToUse, FloatType maxInputValueToUse, size_t numPoints)
Creates and initialises a LookupTableTransform object.
FloatType processSampleUnchecked(FloatType value) const noexcept
Calculates the approximated value for the given input value without range checking.