1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - 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 6 End-User License 11 Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). 12 13 End User License Agreement: www.juce.com/juce-6-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 27 { 28 namespace dsp 29 { 30 31 /** 32 A 6 stage phaser that modulates first order all-pass filters to create sweeping 33 notches in the magnitude frequency response. 34 35 This audio effect can be controlled with standard phaser parameters: the speed 36 and depth of the LFO controlling the frequency response, a mix control, a 37 feedback control, and the centre frequency of the modulation. 38 39 @tags{DSP} 40 */ 41 template <typename SampleType> 42 class Phaser 43 { 44 public: 45 //============================================================================== 46 /** Constructor. */ 47 Phaser(); 48 49 //============================================================================== 50 /** Sets the rate (in Hz) of the LFO modulating the phaser all-pass filters. This 51 rate must be lower than 100 Hz. 52 */ 53 void setRate (SampleType newRateHz); 54 55 /** Sets the volume (between 0 and 1) of the LFO modulating the phaser all-pass 56 filters. 57 */ 58 void setDepth (SampleType newDepth); 59 60 /** Sets the centre frequency (in Hz) of the phaser all-pass filters modulation. 61 */ 62 void setCentreFrequency (SampleType newCentreHz); 63 64 /** Sets the feedback volume (between -1 and 1) of the phaser. Negative can be 65 used to get specific phaser sounds. 66 */ 67 void setFeedback (SampleType newFeedback); 68 69 /** Sets the amount of dry and wet signal in the output of the phaser (between 0 70 for full dry and 1 for full wet). 71 */ 72 void setMix (SampleType newMix); 73 74 //============================================================================== 75 /** Initialises the processor. */ 76 void prepare (const ProcessSpec& spec); 77 78 /** Resets the internal state variables of the processor. */ 79 void reset(); 80 81 //============================================================================== 82 /** Processes the input and output samples supplied in the processing context. */ 83 template <typename ProcessContext> process(const ProcessContext & context)84 void process (const ProcessContext& context) noexcept 85 { 86 const auto& inputBlock = context.getInputBlock(); 87 auto& outputBlock = context.getOutputBlock(); 88 const auto numChannels = outputBlock.getNumChannels(); 89 const auto numSamples = outputBlock.getNumSamples(); 90 91 jassert (inputBlock.getNumChannels() == numChannels); 92 jassert (inputBlock.getNumChannels() == lastOutput.size()); 93 jassert (inputBlock.getNumSamples() == numSamples); 94 95 if (context.isBypassed) 96 { 97 outputBlock.copyFrom (inputBlock); 98 return; 99 } 100 101 int numSamplesDown = 0; 102 auto counter = updateCounter; 103 104 for (size_t i = 0; i < numSamples; ++i) 105 { 106 if (counter == 0) 107 numSamplesDown++; 108 109 counter++; 110 111 if (counter == maxUpdateCounter) 112 counter = 0; 113 } 114 115 if (numSamplesDown > 0) 116 { 117 auto freqBlock = AudioBlock<SampleType>(bufferFrequency).getSubBlock (0, (size_t) numSamplesDown); 118 auto contextFreq = ProcessContextReplacing<SampleType> (freqBlock); 119 freqBlock.clear(); 120 121 osc.process (contextFreq); 122 freqBlock.multiplyBy (oscVolume); 123 } 124 125 auto* freqSamples = bufferFrequency.getWritePointer (0); 126 127 for (int i = 0; i < numSamplesDown; ++i) 128 { 129 auto lfo = jlimit (static_cast<SampleType> (0.0), 130 static_cast<SampleType> (1.0), 131 freqSamples[i] + normCentreFrequency); 132 133 freqSamples[i] = mapToLog10 (lfo, static_cast<SampleType> (20.0), 134 static_cast<SampleType> (jmin (20000.0, 0.49 * sampleRate))); 135 } 136 137 auto currentFrequency = filters[0]->getCutoffFrequency(); 138 dryWet.pushDrySamples (inputBlock); 139 140 for (size_t channel = 0; channel < numChannels; ++channel) 141 { 142 counter = updateCounter; 143 int k = 0; 144 145 auto* inputSamples = inputBlock .getChannelPointer (channel); 146 auto* outputSamples = outputBlock.getChannelPointer (channel); 147 148 for (size_t i = 0; i < numSamples; ++i) 149 { 150 auto input = inputSamples[i]; 151 auto output = input - lastOutput[channel]; 152 153 if (i == 0 && counter != 0) 154 for (int n = 0; n < numStages; ++n) 155 filters[n]->setCutoffFrequency (currentFrequency); 156 157 if (counter == 0) 158 { 159 for (int n = 0; n < numStages; ++n) 160 filters[n]->setCutoffFrequency (freqSamples[k]); 161 162 k++; 163 } 164 165 for (int n = 0; n < numStages; ++n) 166 output = filters[n]->processSample ((int) channel, output); 167 168 outputSamples[i] = output; 169 lastOutput[channel] = output * feedbackVolume[channel].getNextValue(); 170 171 counter++; 172 173 if (counter == maxUpdateCounter) 174 counter = 0; 175 } 176 } 177 178 dryWet.mixWetSamples (outputBlock); 179 updateCounter = (updateCounter + (int) numSamples) % maxUpdateCounter; 180 } 181 182 private: 183 //============================================================================== 184 void update(); 185 186 //============================================================================== 187 Oscillator<SampleType> osc; 188 OwnedArray<FirstOrderTPTFilter<SampleType>> filters; 189 SmoothedValue<SampleType, ValueSmoothingTypes::Linear> oscVolume; 190 std::vector<SmoothedValue<SampleType, ValueSmoothingTypes::Linear>> feedbackVolume { 2 }; 191 DryWetMixer<SampleType> dryWet; 192 std::vector<SampleType> lastOutput { 2 }; 193 AudioBuffer<SampleType> bufferFrequency; 194 SampleType normCentreFrequency = 0.5; 195 double sampleRate = 44100.0; 196 197 int updateCounter = 0; 198 static constexpr int maxUpdateCounter = 4; 199 200 SampleType rate = 1.0, depth = 0.5, feedback = 0.0, mix = 0.5; 201 SampleType centreFrequency = 1300.0; 202 static constexpr int numStages = 6; 203 }; 204 205 } // namespace dsp 206 } // namespace juce 207