The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

204 lines
7.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce::dsp
  19. {
  20. /**
  21. A 6 stage phaser that modulates first order all-pass filters to create sweeping
  22. notches in the magnitude frequency response.
  23. This audio effect can be controlled with standard phaser parameters: the speed
  24. and depth of the LFO controlling the frequency response, a mix control, a
  25. feedback control, and the centre frequency of the modulation.
  26. @tags{DSP}
  27. */
  28. template <typename SampleType>
  29. class Phaser
  30. {
  31. public:
  32. //==============================================================================
  33. /** Constructor. */
  34. Phaser();
  35. //==============================================================================
  36. /** Sets the rate (in Hz) of the LFO modulating the phaser all-pass filters. This
  37. rate must be lower than 100 Hz.
  38. */
  39. void setRate (SampleType newRateHz);
  40. /** Sets the volume (between 0 and 1) of the LFO modulating the phaser all-pass
  41. filters.
  42. */
  43. void setDepth (SampleType newDepth);
  44. /** Sets the centre frequency (in Hz) of the phaser all-pass filters modulation.
  45. */
  46. void setCentreFrequency (SampleType newCentreHz);
  47. /** Sets the feedback volume (between -1 and 1) of the phaser. Negative can be
  48. used to get specific phaser sounds.
  49. */
  50. void setFeedback (SampleType newFeedback);
  51. /** Sets the amount of dry and wet signal in the output of the phaser (between 0
  52. for full dry and 1 for full wet).
  53. */
  54. void setMix (SampleType newMix);
  55. //==============================================================================
  56. /** Initialises the processor. */
  57. void prepare (const ProcessSpec& spec);
  58. /** Resets the internal state variables of the processor. */
  59. void reset();
  60. //==============================================================================
  61. /** Processes the input and output samples supplied in the processing context. */
  62. template <typename ProcessContext>
  63. void process (const ProcessContext& context) noexcept
  64. {
  65. const auto& inputBlock = context.getInputBlock();
  66. auto& outputBlock = context.getOutputBlock();
  67. const auto numChannels = outputBlock.getNumChannels();
  68. const auto numSamples = outputBlock.getNumSamples();
  69. jassert (inputBlock.getNumChannels() == numChannels);
  70. jassert (inputBlock.getNumChannels() == lastOutput.size());
  71. jassert (inputBlock.getNumSamples() == numSamples);
  72. if (context.isBypassed)
  73. {
  74. outputBlock.copyFrom (inputBlock);
  75. return;
  76. }
  77. int numSamplesDown = 0;
  78. auto counter = updateCounter;
  79. for (size_t i = 0; i < numSamples; ++i)
  80. {
  81. if (counter == 0)
  82. numSamplesDown++;
  83. counter++;
  84. if (counter == maxUpdateCounter)
  85. counter = 0;
  86. }
  87. if (numSamplesDown > 0)
  88. {
  89. auto freqBlock = AudioBlock<SampleType> (bufferFrequency).getSubBlock (0, (size_t) numSamplesDown);
  90. auto contextFreq = ProcessContextReplacing<SampleType> (freqBlock);
  91. freqBlock.clear();
  92. osc.process (contextFreq);
  93. freqBlock.multiplyBy (oscVolume);
  94. }
  95. auto* freqSamples = bufferFrequency.getWritePointer (0);
  96. for (int i = 0; i < numSamplesDown; ++i)
  97. {
  98. auto lfo = jlimit (static_cast<SampleType> (0.0),
  99. static_cast<SampleType> (1.0),
  100. freqSamples[i] + normCentreFrequency);
  101. freqSamples[i] = mapToLog10 (lfo, static_cast<SampleType> (20.0),
  102. static_cast<SampleType> (jmin (20000.0, 0.49 * sampleRate)));
  103. }
  104. auto currentFrequency = filters[0]->getCutoffFrequency();
  105. dryWet.pushDrySamples (inputBlock);
  106. for (size_t channel = 0; channel < numChannels; ++channel)
  107. {
  108. counter = updateCounter;
  109. int k = 0;
  110. auto* inputSamples = inputBlock .getChannelPointer (channel);
  111. auto* outputSamples = outputBlock.getChannelPointer (channel);
  112. for (size_t i = 0; i < numSamples; ++i)
  113. {
  114. auto input = inputSamples[i];
  115. auto output = input - lastOutput[channel];
  116. if (i == 0 && counter != 0)
  117. for (int n = 0; n < numStages; ++n)
  118. filters[n]->setCutoffFrequency (currentFrequency);
  119. if (counter == 0)
  120. {
  121. for (int n = 0; n < numStages; ++n)
  122. filters[n]->setCutoffFrequency (freqSamples[k]);
  123. k++;
  124. }
  125. for (int n = 0; n < numStages; ++n)
  126. output = filters[n]->processSample ((int) channel, output);
  127. outputSamples[i] = output;
  128. lastOutput[channel] = output * feedbackVolume[channel].getNextValue();
  129. counter++;
  130. if (counter == maxUpdateCounter)
  131. counter = 0;
  132. }
  133. }
  134. dryWet.mixWetSamples (outputBlock);
  135. updateCounter = (updateCounter + (int) numSamples) % maxUpdateCounter;
  136. }
  137. private:
  138. //==============================================================================
  139. void update();
  140. //==============================================================================
  141. Oscillator<SampleType> osc;
  142. OwnedArray<FirstOrderTPTFilter<SampleType>> filters;
  143. SmoothedValue<SampleType, ValueSmoothingTypes::Linear> oscVolume;
  144. std::vector<SmoothedValue<SampleType, ValueSmoothingTypes::Linear>> feedbackVolume { 2 };
  145. DryWetMixer<SampleType> dryWet;
  146. std::vector<SampleType> lastOutput { 2 };
  147. AudioBuffer<SampleType> bufferFrequency;
  148. SampleType normCentreFrequency = 0.5;
  149. double sampleRate = 44100.0;
  150. int updateCounter = 0;
  151. static constexpr int maxUpdateCounter = 4;
  152. SampleType rate = 1.0, depth = 0.5, feedback = 0.0, mix = 0.5;
  153. SampleType centreFrequency = 1300.0;
  154. static constexpr int numStages = 6;
  155. };
  156. } // namespace juce::dsp