OpenShot Library | OpenShotAudio 0.2.2
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
31namespace juce
32{
33namespace 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*/
56template <typename FloatType>
58{
59public:
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 */
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
148private:
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*/
178template <typename FloatType>
180{
181public:
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 */
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);
321private:
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/** @}*/
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
Definition: juce_Array.h:256
int size() const noexcept
Returns the current number of elements in the array.
Definition: juce_Array.h:219
Class for approximating expensive arithmetic operations.
LookupTableTransform(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValueToUse, FloatType maxInputValueToUse, size_t numPoints)
Creates and initialises a LookupTableTransform object.
FloatType operator[](FloatType index) const noexcept
FloatType processSampleUnchecked(FloatType value) const noexcept
Calculates the approximated value for the given input value without range checking.
void initialise(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValueToUse, FloatType maxInputValueToUse, size_t numPoints)
Initialises or changes the parameters of a LookupTableTransform object.
void process(const FloatType *input, FloatType *output, size_t numSamples) const noexcept
Processes an array of input values with range checking.
void processUnchecked(const FloatType *input, FloatType *output, size_t numSamples) const noexcept
Processes an array of input values without range checking.
FloatType processSample(FloatType value) const noexcept
Calculates the approximated value for the given input value with range checking.
FloatType operator()(FloatType index) const noexcept
LookupTableTransform()=default
Creates an uninitialised LookupTableTransform object.
static double calculateMaxRelativeError(const std::function< FloatType(FloatType)> &functionToApproximate, FloatType minInputValue, FloatType maxInputValue, size_t numPoints, size_t numTestPoints=0)
Calculates the maximum relative error of the approximation for the specified parameter set.
Class for efficiently approximating expensive arithmetic operations.
FloatType get(FloatType index) const noexcept
Calculates the approximated value for the given index with range checking.
FloatType operator[](FloatType index) const noexcept
FloatType getUnchecked(FloatType index) const noexcept
Calculates the approximated value for the given index without range checking.
bool isInitialised() const noexcept
Returns true if the LookupTable is initialised and ready to be used.
size_t getNumPoints() const noexcept
Returns the size of the LookupTable, i.e., the number of pre-calculated data points.
void initialise(const std::function< FloatType(size_t)> &functionToApproximate, size_t numPointsToUse)
Initialises or changes the parameters of a LookupTable object.
LookupTable()
Creates an uninitialised LookupTable object.