OpenShot Audio Library | OpenShotAudio  0.6.0
juce_DelayLine.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  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 //==============================================================================
34 namespace DelayLineInterpolationTypes
35 {
43  struct None {};
44 
53  struct Linear {};
54 
63  struct Lagrange3rd {};
64 
74  struct Thiran {};
75 }
76 
77 //==============================================================================
91 template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear>
92 class DelayLine
93 {
94 public:
95  //==============================================================================
97  DelayLine();
98 
100  explicit DelayLine (int maximumDelayInSamples);
101 
102  //==============================================================================
104  void setDelay (SampleType newDelayInSamples);
105 
107  SampleType getDelay() const;
108 
109  //==============================================================================
111  void prepare (const ProcessSpec& spec);
112 
119  void setMaximumDelayInSamples (int maxDelayInSamples);
120 
126  int getMaximumDelayInSamples() const noexcept { return totalSize - 2; }
127 
129  void reset();
130 
131  //==============================================================================
140  void pushSample (int channel, SampleType sample);
141 
159  SampleType popSample (int channel, SampleType delayInSamples = -1, bool updateReadPointer = true);
160 
161  //==============================================================================
169  template <typename ProcessContext>
170  void process (const ProcessContext& context) noexcept
171  {
172  const auto& inputBlock = context.getInputBlock();
173  auto& outputBlock = context.getOutputBlock();
174  const auto numChannels = outputBlock.getNumChannels();
175  const auto numSamples = outputBlock.getNumSamples();
176 
177  jassert (inputBlock.getNumChannels() == numChannels);
178  jassert (inputBlock.getNumChannels() == writePos.size());
179  jassert (inputBlock.getNumSamples() == numSamples);
180 
181  if (context.isBypassed)
182  {
183  outputBlock.copyFrom (inputBlock);
184  return;
185  }
186 
187  for (size_t channel = 0; channel < numChannels; ++channel)
188  {
189  auto* inputSamples = inputBlock.getChannelPointer (channel);
190  auto* outputSamples = outputBlock.getChannelPointer (channel);
191 
192  for (size_t i = 0; i < numSamples; ++i)
193  {
194  pushSample ((int) channel, inputSamples[i]);
195  outputSamples[i] = popSample ((int) channel);
196  }
197  }
198  }
199 
200 private:
201  //==============================================================================
202  SampleType interpolateSample (int channel)
203  {
204  if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::None>)
205  {
206  auto index = (readPos[(size_t) channel] + delayInt) % totalSize;
207  return bufferData.getSample (channel, index);
208  }
209  else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Linear>)
210  {
211  auto index1 = readPos[(size_t) channel] + delayInt;
212  auto index2 = index1 + 1;
213 
214  if (index2 >= totalSize)
215  {
216  index1 %= totalSize;
217  index2 %= totalSize;
218  }
219 
220  auto value1 = bufferData.getSample (channel, index1);
221  auto value2 = bufferData.getSample (channel, index2);
222 
223  return value1 + delayFrac * (value2 - value1);
224  }
225  else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Lagrange3rd>)
226  {
227  auto index1 = readPos[(size_t) channel] + delayInt;
228  auto index2 = index1 + 1;
229  auto index3 = index2 + 1;
230  auto index4 = index3 + 1;
231 
232  if (index4 >= totalSize)
233  {
234  index1 %= totalSize;
235  index2 %= totalSize;
236  index3 %= totalSize;
237  index4 %= totalSize;
238  }
239 
240  auto* samples = bufferData.getReadPointer (channel);
241 
242  auto value1 = samples[index1];
243  auto value2 = samples[index2];
244  auto value3 = samples[index3];
245  auto value4 = samples[index4];
246 
247  auto d1 = delayFrac - 1.f;
248  auto d2 = delayFrac - 2.f;
249  auto d3 = delayFrac - 3.f;
250 
251  auto c1 = -d1 * d2 * d3 / 6.f;
252  auto c2 = d2 * d3 * 0.5f;
253  auto c3 = -d1 * d3 * 0.5f;
254  auto c4 = d1 * d2 / 6.f;
255 
256  return value1 * c1 + delayFrac * (value2 * c2 + value3 * c3 + value4 * c4);
257  }
258  else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Thiran>)
259  {
260  auto index1 = readPos[(size_t) channel] + delayInt;
261  auto index2 = index1 + 1;
262 
263  if (index2 >= totalSize)
264  {
265  index1 %= totalSize;
266  index2 %= totalSize;
267  }
268 
269  auto value1 = bufferData.getSample (channel, index1);
270  auto value2 = bufferData.getSample (channel, index2);
271 
272  auto output = approximatelyEqual (delayFrac, (SampleType) 0) ? value1 : value2 + alpha * (value1 - v[(size_t) channel]);
273  v[(size_t) channel] = output;
274 
275  return output;
276  }
277  }
278 
279  //==============================================================================
280  void updateInternalVariables()
281  {
282  if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Lagrange3rd>)
283  {
284  if (delayFrac < (SampleType) 2.0 && delayInt >= 1)
285  {
286  delayFrac++;
287  delayInt--;
288  }
289  }
290  else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Thiran>)
291  {
292  if (delayFrac < (SampleType) 0.618 && delayInt >= 1)
293  {
294  delayFrac++;
295  delayInt--;
296  }
297 
298  alpha = (1 - delayFrac) / (1 + delayFrac);
299  }
300  }
301 
302  //==============================================================================
303  double sampleRate;
304 
305  //==============================================================================
306  AudioBuffer<SampleType> bufferData;
307  std::vector<SampleType> v;
308  std::vector<int> writePos, readPos;
309  SampleType delay = 0.0, delayFrac = 0.0;
310  int delayInt = 0, totalSize = 4;
311  SampleType alpha = 0.0;
312 };
313 
314 } // namespace juce::dsp
Type getSample(int channel, int sampleIndex) const noexcept
const Type * getReadPointer(int channelNumber) const noexcept
void prepare(const ProcessSpec &spec)
int getMaximumDelayInSamples() const noexcept
void setDelay(SampleType newDelayInSamples)
SampleType popSample(int channel, SampleType delayInSamples=-1, bool updateReadPointer=true)
void setMaximumDelayInSamples(int maxDelayInSamples)
SampleType getDelay() const
void process(const ProcessContext &context) noexcept
void pushSample(int channel, SampleType sample)