OpenShot Audio Library | OpenShotAudio  0.6.0
juce_GenericInterpolator.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 
39 template <class InterpolatorTraits, int memorySize>
40 class JUCE_API GenericInterpolator
41 {
42  static auto processReplacingCallback()
43  {
44  return [] (auto, auto newValue) { return newValue; };
45  }
46 
47  static auto processAddingCallback (float gain)
48  {
49  return [gain] (auto oldValue, auto newValue) { return oldValue + gain * newValue; };
50  }
51 
52 public:
53  GenericInterpolator() noexcept { reset(); }
54 
55  GenericInterpolator (GenericInterpolator&&) noexcept = default;
56  GenericInterpolator& operator= (GenericInterpolator&&) noexcept = default;
57 
63  static constexpr float getBaseLatency() noexcept
64  {
65  return InterpolatorTraits::algorithmicLatency;
66  }
67 
72  void reset() noexcept
73  {
74  indexBuffer = 0;
75  subSamplePos = 1.0;
76  std::fill (std::begin (lastInputSamples), std::end (lastInputSamples), 0.0f);
77  }
78 
89  int process (double speedRatio,
90  const float* inputSamples,
91  float* outputSamples,
92  int numOutputSamplesToProduce) noexcept
93  {
94  return interpolateImpl (speedRatio,
95  inputSamples,
96  outputSamples,
97  numOutputSamplesToProduce,
98  processReplacingCallback());
99  }
100 
116  int process (double speedRatio,
117  const float* inputSamples,
118  float* outputSamples,
119  int numOutputSamplesToProduce,
120  int numInputSamplesAvailable,
121  int wrapAround) noexcept
122  {
123  return interpolateImpl (speedRatio,
124  inputSamples,
125  outputSamples,
126  numOutputSamplesToProduce,
127  numInputSamplesAvailable,
128  wrapAround,
129  processReplacingCallback());
130  }
131 
147  int processAdding (double speedRatio,
148  const float* inputSamples,
149  float* outputSamples,
150  int numOutputSamplesToProduce,
151  float gain) noexcept
152  {
153  return interpolateImpl (speedRatio,
154  inputSamples,
155  outputSamples,
156  numOutputSamplesToProduce,
157  processAddingCallback (gain));
158  }
159 
180  int processAdding (double speedRatio,
181  const float* inputSamples,
182  float* outputSamples,
183  int numOutputSamplesToProduce,
184  int numInputSamplesAvailable,
185  int wrapAround,
186  float gain) noexcept
187  {
188  return interpolateImpl (speedRatio,
189  inputSamples,
190  outputSamples,
191  numOutputSamplesToProduce,
192  numInputSamplesAvailable,
193  wrapAround,
194  processAddingCallback (gain));
195  }
196 
197 private:
198  //==============================================================================
199  forcedinline void pushInterpolationSample (float newValue) noexcept
200  {
201  lastInputSamples[indexBuffer] = newValue;
202 
203  if (++indexBuffer == memorySize)
204  indexBuffer = 0;
205  }
206 
207  forcedinline void pushInterpolationSamples (const float* input,
208  int numOutputSamplesToProduce) noexcept
209  {
210  if (numOutputSamplesToProduce >= memorySize)
211  {
212  const auto* const offsetInput = input + (numOutputSamplesToProduce - memorySize);
213 
214  for (int i = 0; i < memorySize; ++i)
215  pushInterpolationSample (offsetInput[i]);
216  }
217  else
218  {
219  for (int i = 0; i < numOutputSamplesToProduce; ++i)
220  pushInterpolationSample (input[i]);
221  }
222  }
223 
224  forcedinline void pushInterpolationSamples (const float* input,
225  int numOutputSamplesToProduce,
226  int numInputSamplesAvailable,
227  int wrapAround) noexcept
228  {
229  if (numOutputSamplesToProduce >= memorySize)
230  {
231  if (numInputSamplesAvailable >= memorySize)
232  {
233  pushInterpolationSamples (input,
234  numOutputSamplesToProduce);
235  }
236  else
237  {
238  pushInterpolationSamples (input + ((numOutputSamplesToProduce - numInputSamplesAvailable) - 1),
239  numInputSamplesAvailable);
240 
241  if (wrapAround > 0)
242  {
243  numOutputSamplesToProduce -= wrapAround;
244 
245  pushInterpolationSamples (input + ((numOutputSamplesToProduce - (memorySize - numInputSamplesAvailable)) - 1),
246  memorySize - numInputSamplesAvailable);
247  }
248  else
249  {
250  for (int i = numInputSamplesAvailable; i < memorySize; ++i)
251  pushInterpolationSample (0.0f);
252  }
253  }
254  }
255  else
256  {
257  if (numOutputSamplesToProduce > numInputSamplesAvailable)
258  {
259  for (int i = 0; i < numInputSamplesAvailable; ++i)
260  pushInterpolationSample (input[i]);
261 
262  const auto extraSamples = numOutputSamplesToProduce - numInputSamplesAvailable;
263 
264  if (wrapAround > 0)
265  {
266  const auto* const offsetInput = input + (numInputSamplesAvailable - wrapAround);
267 
268  for (int i = 0; i < extraSamples; ++i)
269  pushInterpolationSample (offsetInput[i]);
270  }
271  else
272  {
273  for (int i = 0; i < extraSamples; ++i)
274  pushInterpolationSample (0.0f);
275  }
276  }
277  else
278  {
279  for (int i = 0; i < numOutputSamplesToProduce; ++i)
280  pushInterpolationSample (input[i]);
281  }
282  }
283  }
284 
285  //==============================================================================
286  template <typename Process>
287  int interpolateImpl (double speedRatio,
288  const float* input,
289  float* output,
290  int numOutputSamplesToProduce,
291  int numInputSamplesAvailable,
292  int wrap,
293  Process process)
294  {
295  auto originalIn = input;
296  bool exceeded = false;
297 
298  const auto pushSample = [&]
299  {
300  if (exceeded)
301  {
302  pushInterpolationSample (0.0);
303  }
304  else
305  {
306  pushInterpolationSample (*input++);
307 
308  if (--numInputSamplesAvailable <= 0)
309  {
310  if (wrap > 0)
311  {
312  input -= wrap;
313  numInputSamplesAvailable += wrap;
314  }
315  else
316  {
317  exceeded = true;
318  }
319  }
320  }
321  };
322 
323  interpolateImpl (speedRatio,
324  output,
325  numOutputSamplesToProduce,
326  process,
327  pushSample);
328 
329  if (wrap == 0)
330  return (int) (input - originalIn);
331 
332  return ((int) (input - originalIn) + wrap) % wrap;
333  }
334 
335  template <typename Process>
336  int interpolateImpl (double speedRatio,
337  const float* input,
338  float* output,
339  int numOutputSamplesToProduce,
340  Process process)
341  {
342  int numUsed = 0;
343 
344  interpolateImpl (speedRatio,
345  output,
346  numOutputSamplesToProduce,
347  process,
348  [this, input, &numUsed] { pushInterpolationSample (input[numUsed++]); });
349 
350  return numUsed;
351  }
352 
353  template <typename Process, typename PushSample>
354  void interpolateImpl (double speedRatio,
355  float* output,
356  int numOutputSamplesToProduce,
357  Process process,
358  PushSample pushSample)
359  {
360  auto pos = subSamplePos;
361 
362  for (auto i = 0; i < numOutputSamplesToProduce; ++i)
363  {
364  while (pos >= 1.0)
365  {
366  pushSample();
367  pos -= 1.0;
368  }
369 
370  *output = process (*output, InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer));
371  ++output;
372  pos += speedRatio;
373  }
374 
375  subSamplePos = pos;
376  }
377 
378  //==============================================================================
379  float lastInputSamples[(size_t) memorySize];
380  double subSamplePos = 1.0;
381  int indexBuffer = 0;
382 
383  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericInterpolator)
384 };
385 
386 } // namespace juce
int process(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, int numInputSamplesAvailable, int wrapAround) noexcept
int process(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce) noexcept
int processAdding(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, int numInputSamplesAvailable, int wrapAround, float gain) noexcept
int processAdding(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, float gain) noexcept
static constexpr float getBaseLatency() noexcept