OpenShot Audio Library | OpenShotAudio 0.4.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
26namespace juce::dsp
27{
28
29//==============================================================================
34namespace DelayLineInterpolationTypes
35{
43 struct None {};
44
53 struct Linear {};
54
63 struct Lagrange3rd {};
64
74 struct Thiran {};
75}
76
77//==============================================================================
91template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear>
93{
94public:
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
200private:
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)