You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
9.0KB

  1. #pragma once
  2. #include <JuceHeader.h>
  3. // Borrowed from JUCE, but made cloneable
  4. //==============================================================================
  5. /**
  6. A delay line processor featuring several algorithms for the fractional delay
  7. calculation, block processing, and sample-by-sample processing useful when
  8. modulating the delay in real time or creating a standard delay effect with
  9. feedback.
  10. Note: If you intend to change the delay in real time, you may want to smooth
  11. changes to the delay systematically using either a ramp or a low-pass filter.
  12. @see SmoothedValue, FirstOrderTPTFilter
  13. @tags{DSP}
  14. */
  15. template <typename SampleType, typename InterpolationType = juce::dsp::DelayLineInterpolationTypes::Linear>
  16. class CloneableDelayLine
  17. {
  18. public:
  19. //==============================================================================
  20. /** Default constructor. */
  21. CloneableDelayLine();
  22. /** Constructor. */
  23. explicit CloneableDelayLine (int maximumDelayInSamples);
  24. //==============================================================================
  25. /** Sets the delay in samples. */
  26. void setDelay (SampleType newDelayInSamples);
  27. /** Returns the current delay in samples. */
  28. SampleType getDelay() const;
  29. //==============================================================================
  30. /** Initialises the processor. */
  31. void prepare (const juce::dsp::ProcessSpec& spec);
  32. /** Sets a new maximum delay in samples.
  33. Also clears the delay line.
  34. This may allocate internally, so you should never call it from the audio thread.
  35. */
  36. void setMaximumDelayInSamples (int maxDelayInSamples);
  37. /** Gets the maximum possible delay in samples.
  38. For very short delay times, the result of getMaximumDelayInSamples() may
  39. differ from the last value passed to setMaximumDelayInSamples().
  40. */
  41. int getMaximumDelayInSamples() const noexcept { return totalSize - 2; }
  42. /** Resets the internal state variables of the processor. */
  43. void reset();
  44. //==============================================================================
  45. /** Pushes a single sample into one channel of the delay line.
  46. Use this function and popSample instead of process if you need to modulate
  47. the delay in real time instead of using a fixed delay value, or if you want
  48. to code a delay effect with a feedback loop.
  49. @see setDelay, popSample, process
  50. */
  51. void pushSample (int channel, SampleType sample);
  52. /** Pops a single sample from one channel of the delay line.
  53. Use this function to modulate the delay in real time or implement standard
  54. delay effects with feedback.
  55. @param channel the target channel for the delay line.
  56. @param delayInSamples sets the wanted fractional delay in samples, or -1
  57. to use the value being used before or set with
  58. setDelay function.
  59. @param updateReadPointer should be set to true if you use the function
  60. once for each sample, or false if you need
  61. multi-tap delay capabilities.
  62. @see setDelay, pushSample, process
  63. */
  64. SampleType popSample (int channel, SampleType delayInSamples = -1, bool updateReadPointer = true);
  65. //==============================================================================
  66. /** Processes the input and output samples supplied in the processing context.
  67. Can be used for block processing when the delay is not going to change
  68. during processing. The delay must first be set by calling setDelay.
  69. @see setDelay
  70. */
  71. template <typename ProcessContext>
  72. void process (const ProcessContext& context) noexcept
  73. {
  74. const auto& inputBlock = context.getInputBlock();
  75. auto& outputBlock = context.getOutputBlock();
  76. const auto numChannels = outputBlock.getNumChannels();
  77. const auto numSamples = outputBlock.getNumSamples();
  78. jassert (inputBlock.getNumChannels() == numChannels);
  79. jassert (inputBlock.getNumChannels() == writePos.size());
  80. jassert (inputBlock.getNumSamples() == numSamples);
  81. if (context.isBypassed)
  82. {
  83. outputBlock.copyFrom (inputBlock);
  84. return;
  85. }
  86. for (size_t channel = 0; channel < numChannels; ++channel)
  87. {
  88. auto* inputSamples = inputBlock.getChannelPointer (channel);
  89. auto* outputSamples = outputBlock.getChannelPointer (channel);
  90. for (size_t i = 0; i < numSamples; ++i)
  91. {
  92. pushSample ((int) channel, inputSamples[i]);
  93. outputSamples[i] = popSample ((int) channel);
  94. }
  95. }
  96. }
  97. CloneableDelayLine* clone() const {
  98. return new CloneableDelayLine(*this);
  99. }
  100. // Public for tests
  101. double sampleRate;
  102. juce::AudioBuffer<SampleType> bufferData;
  103. std::vector<SampleType> v;
  104. std::vector<int> writePos, readPos;
  105. SampleType delay = 0.0, delayFrac = 0.0;
  106. int delayInt = 0, totalSize = 4;
  107. SampleType alpha = 0.0;
  108. private:
  109. CloneableDelayLine(const CloneableDelayLine& other) :
  110. sampleRate(other.sampleRate),
  111. bufferData(other.bufferData),
  112. v(other.v),
  113. writePos(other.writePos),
  114. readPos(other.readPos),
  115. delay(other.delay),
  116. delayFrac(other.delayFrac),
  117. delayInt(other.delayInt),
  118. totalSize(other.totalSize),
  119. alpha(other.alpha) {
  120. }
  121. //==============================================================================
  122. SampleType interpolateSample (int channel)
  123. {
  124. if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::None>)
  125. {
  126. auto index = (readPos[(size_t) channel] + delayInt) % totalSize;
  127. return bufferData.getSample (channel, index);
  128. }
  129. else if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::Linear>)
  130. {
  131. auto index1 = readPos[(size_t) channel] + delayInt;
  132. auto index2 = index1 + 1;
  133. if (index2 >= totalSize)
  134. {
  135. index1 %= totalSize;
  136. index2 %= totalSize;
  137. }
  138. auto value1 = bufferData.getSample (channel, index1);
  139. auto value2 = bufferData.getSample (channel, index2);
  140. return value1 + delayFrac * (value2 - value1);
  141. }
  142. else if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::Lagrange3rd>)
  143. {
  144. auto index1 = readPos[(size_t) channel] + delayInt;
  145. auto index2 = index1 + 1;
  146. auto index3 = index2 + 1;
  147. auto index4 = index3 + 1;
  148. if (index4 >= totalSize)
  149. {
  150. index1 %= totalSize;
  151. index2 %= totalSize;
  152. index3 %= totalSize;
  153. index4 %= totalSize;
  154. }
  155. auto* samples = bufferData.getReadPointer (channel);
  156. auto value1 = samples[index1];
  157. auto value2 = samples[index2];
  158. auto value3 = samples[index3];
  159. auto value4 = samples[index4];
  160. auto d1 = delayFrac - 1.f;
  161. auto d2 = delayFrac - 2.f;
  162. auto d3 = delayFrac - 3.f;
  163. auto c1 = -d1 * d2 * d3 / 6.f;
  164. auto c2 = d2 * d3 * 0.5f;
  165. auto c3 = -d1 * d3 * 0.5f;
  166. auto c4 = d1 * d2 / 6.f;
  167. return value1 * c1 + delayFrac * (value2 * c2 + value3 * c3 + value4 * c4);
  168. }
  169. else if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::Thiran>)
  170. {
  171. auto index1 = readPos[(size_t) channel] + delayInt;
  172. auto index2 = index1 + 1;
  173. if (index2 >= totalSize)
  174. {
  175. index1 %= totalSize;
  176. index2 %= totalSize;
  177. }
  178. auto value1 = bufferData.getSample (channel, index1);
  179. auto value2 = bufferData.getSample (channel, index2);
  180. auto output = juce::approximatelyEqual (delayFrac, (SampleType) 0) ? value1 : value2 + alpha * (value1 - v[(size_t) channel]);
  181. v[(size_t) channel] = output;
  182. return output;
  183. }
  184. }
  185. //==============================================================================
  186. void updateInternalVariables()
  187. {
  188. if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::Lagrange3rd>)
  189. {
  190. if (delayFrac < (SampleType) 2.0 && delayInt >= 1)
  191. {
  192. delayFrac++;
  193. delayInt--;
  194. }
  195. }
  196. else if constexpr (std::is_same_v<InterpolationType, juce::dsp::DelayLineInterpolationTypes::Thiran>)
  197. {
  198. if (delayFrac < (SampleType) 0.618 && delayInt >= 1)
  199. {
  200. delayFrac++;
  201. delayInt--;
  202. }
  203. alpha = (1 - delayFrac) / (1 + delayFrac);
  204. }
  205. }
  206. };