annotate effects/phaser/Source/PluginProcessor.cpp @ 1:04e171d2a747 tip

JUCE 4 compatible. Standardised paths on Mac: modules '../../juce/modules'; VST folder '~/SDKs/vstsdk2.4' (JUCE default). Replaced deprecated 'getSampleData(channel)'; getToggleState(...); setToggleState(...); setSelectedId(...). Removed unused variables. Ignore JUCE code and build files.
author Brecht De Man <b.deman@qmul.ac.uk>
date Sun, 22 Nov 2015 15:23:40 +0000
parents e32fe563e124
children
rev   line source
andrewm@0 1 /*
andrewm@0 2 This code accompanies the textbook:
andrewm@0 3
andrewm@0 4 Digital Audio Effects: Theory, Implementation and Application
andrewm@0 5 Joshua D. Reiss and Andrew P. McPherson
andrewm@0 6
andrewm@0 7 ---
andrewm@0 8
andrewm@0 9 Phaser: phasing effect using time-varying allpass filters
andrewm@0 10 See textbook Chapter 4: Filter Effects
andrewm@0 11
andrewm@0 12 Code by Andrew McPherson, Brecht De Man and Joshua Reiss
andrewm@0 13
andrewm@0 14 ---
andrewm@0 15
andrewm@0 16 This program is free software: you can redistribute it and/or modify
andrewm@0 17 it under the terms of the GNU General Public License as published by
andrewm@0 18 the Free Software Foundation, either version 3 of the License, or
andrewm@0 19 (at your option) any later version.
andrewm@0 20
andrewm@0 21 This program is distributed in the hope that it will be useful,
andrewm@0 22 but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0 24 GNU General Public License for more details.
andrewm@0 25
andrewm@0 26 You should have received a copy of the GNU General Public License
andrewm@0 27 along with this program. If not, see <http://www.gnu.org/licenses/>.
andrewm@0 28 */
andrewm@0 29
andrewm@0 30 #include "PluginProcessor.h"
andrewm@0 31 #include "PluginEditor.h"
andrewm@0 32 #include <math.h>
andrewm@0 33
andrewm@0 34 //==============================================================================
andrewm@0 35 PhaserAudioProcessor::PhaserAudioProcessor()
andrewm@0 36 {
andrewm@0 37 // Set default values:
andrewm@0 38 baseFrequency_ = 200.0;
andrewm@0 39 sweepWidth_ = 2000.0;
andrewm@0 40 depth_ = 1.0;
andrewm@0 41 feedback_ = 0.0;
andrewm@0 42 lfoFrequency_ = 0.5;
andrewm@0 43 waveform_ = kWaveformSine;
andrewm@0 44 stereo_ = 0;
andrewm@0 45
andrewm@0 46 // Start with no filters (at least until we have some channels)
andrewm@0 47 allpassFilters_ = 0;
andrewm@0 48 filtersPerChannel_ = 4;
andrewm@0 49 totalNumFilters_ = 0;
andrewm@0 50 lastFilterOutputs_ = 0;
andrewm@0 51 numLastFilterOutputs_ = 0;
andrewm@0 52
andrewm@0 53 lfoPhase_ = 0.0;
andrewm@0 54 inverseSampleRate_ = 1.0/44100.0;
andrewm@0 55 sampleCount_ = 0;
andrewm@0 56 filterUpdateInterval_ = 8;
andrewm@0 57
andrewm@0 58 lastUIWidth_ = 550;
andrewm@0 59 lastUIHeight_ = 200;
andrewm@0 60 }
andrewm@0 61
andrewm@0 62 PhaserAudioProcessor::~PhaserAudioProcessor()
andrewm@0 63 {
andrewm@0 64 deallocateFilters();
andrewm@0 65 }
andrewm@0 66
andrewm@0 67 //==============================================================================
andrewm@0 68 const String PhaserAudioProcessor::getName() const
andrewm@0 69 {
andrewm@0 70 return JucePlugin_Name;
andrewm@0 71 }
andrewm@0 72
andrewm@0 73 int PhaserAudioProcessor::getNumParameters()
andrewm@0 74 {
andrewm@0 75 return kNumParameters;
andrewm@0 76 }
andrewm@0 77
andrewm@0 78 float PhaserAudioProcessor::getParameter (int index)
andrewm@0 79 {
andrewm@0 80 // This method will be called by the host, probably on the audio thread, so
andrewm@0 81 // it's absolutely time-critical. Don't use critical sections or anything
andrewm@0 82 // UI-related, or anything at all that may block in any way!
andrewm@0 83 switch (index)
andrewm@0 84 {
andrewm@0 85 case kBaseFrequencyParam: return baseFrequency_;
andrewm@0 86 case kSweepWidthParam: return sweepWidth_;
andrewm@0 87 case kDepthParam: return depth_;
andrewm@0 88 case kFeedbackParam: return feedback_;
andrewm@0 89 case kLFOFrequencyParam: return lfoFrequency_;
andrewm@0 90 case kFiltersParam: return (float)filtersPerChannel_;
andrewm@0 91 case kWaveformParam: return (float)waveform_;
andrewm@0 92 case kStereoParam: return (float)stereo_;
andrewm@0 93 default: return 0.0f;
andrewm@0 94 }
andrewm@0 95 }
andrewm@0 96
andrewm@0 97 void PhaserAudioProcessor::setParameter (int index, float newValue)
andrewm@0 98 {
andrewm@0 99 // This method will be called by the host, probably on the audio thread, so
andrewm@0 100 // it's absolutely time-critical. Don't use critical sections or anything
andrewm@0 101 // UI-related, or anything at all that may block in any way!
andrewm@0 102
andrewm@0 103 switch (index)
andrewm@0 104 {
andrewm@0 105 case kBaseFrequencyParam:
andrewm@0 106 baseFrequency_ = newValue;
andrewm@0 107 break;
andrewm@0 108 case kSweepWidthParam:
andrewm@0 109 sweepWidth_ = newValue;
andrewm@0 110 break;
andrewm@0 111 case kDepthParam:
andrewm@0 112 depth_ = newValue;
andrewm@0 113 break;
andrewm@0 114 case kFeedbackParam:
andrewm@0 115 feedback_ = newValue;
andrewm@0 116 break;
andrewm@0 117 case kLFOFrequencyParam:
andrewm@0 118 lfoFrequency_ = newValue;
andrewm@0 119 break;
andrewm@0 120 case kFiltersParam:
andrewm@0 121 if(filtersPerChannel_ != (int)newValue) {
andrewm@0 122 filtersPerChannel_ = (int)newValue;
andrewm@0 123 reallocateFilters();
andrewm@0 124 }
andrewm@0 125 break;
andrewm@0 126 case kWaveformParam:
andrewm@0 127 waveform_ = (int)newValue;
andrewm@0 128 break;
andrewm@0 129 case kStereoParam:
andrewm@0 130 stereo_ = (int)newValue;
andrewm@0 131 break;
andrewm@0 132 default:
andrewm@0 133 break;
andrewm@0 134 }
andrewm@0 135 }
andrewm@0 136
andrewm@0 137 const String PhaserAudioProcessor::getParameterName (int index)
andrewm@0 138 {
andrewm@0 139 switch (index)
andrewm@0 140 {
andrewm@0 141 case kBaseFrequencyParam: return "base frequency";
andrewm@0 142 case kSweepWidthParam: return "sweep width";
andrewm@0 143 case kDepthParam: return "depth";
andrewm@0 144 case kFeedbackParam: return "feedback";
andrewm@0 145 case kLFOFrequencyParam: return "LFO frequency";
andrewm@0 146 case kWaveformParam: return "waveform";
andrewm@0 147 case kStereoParam: return "stereo";
andrewm@0 148 default: break;
andrewm@0 149 }
andrewm@0 150
andrewm@0 151 return String::empty;
andrewm@0 152 }
andrewm@0 153
andrewm@0 154 const String PhaserAudioProcessor::getParameterText (int index)
andrewm@0 155 {
andrewm@0 156 return String (getParameter (index), 2);
andrewm@0 157 }
andrewm@0 158
andrewm@0 159 const String PhaserAudioProcessor::getInputChannelName (int channelIndex) const
andrewm@0 160 {
andrewm@0 161 return String (channelIndex + 1);
andrewm@0 162 }
andrewm@0 163
andrewm@0 164 const String PhaserAudioProcessor::getOutputChannelName (int channelIndex) const
andrewm@0 165 {
andrewm@0 166 return String (channelIndex + 1);
andrewm@0 167 }
andrewm@0 168
andrewm@0 169 bool PhaserAudioProcessor::isInputChannelStereoPair (int index) const
andrewm@0 170 {
andrewm@0 171 return true;
andrewm@0 172 }
andrewm@0 173
andrewm@0 174 bool PhaserAudioProcessor::isOutputChannelStereoPair (int index) const
andrewm@0 175 {
andrewm@0 176 return true;
andrewm@0 177 }
andrewm@0 178
andrewm@0 179 bool PhaserAudioProcessor::silenceInProducesSilenceOut() const
andrewm@0 180 {
andrewm@0 181 #if JucePlugin_SilenceInProducesSilenceOut
andrewm@0 182 return true;
andrewm@0 183 #else
andrewm@0 184 return false;
andrewm@0 185 #endif
andrewm@0 186 }
andrewm@0 187
andrewm@0 188 double PhaserAudioProcessor::getTailLengthSeconds() const
andrewm@0 189 {
andrewm@0 190 return 0.0;
andrewm@0 191 }
andrewm@0 192
andrewm@0 193 bool PhaserAudioProcessor::acceptsMidi() const
andrewm@0 194 {
andrewm@0 195 #if JucePlugin_WantsMidiInput
andrewm@0 196 return true;
andrewm@0 197 #else
andrewm@0 198 return false;
andrewm@0 199 #endif
andrewm@0 200 }
andrewm@0 201
andrewm@0 202 bool PhaserAudioProcessor::producesMidi() const
andrewm@0 203 {
andrewm@0 204 #if JucePlugin_ProducesMidiOutput
andrewm@0 205 return true;
andrewm@0 206 #else
andrewm@0 207 return false;
andrewm@0 208 #endif
andrewm@0 209 }
andrewm@0 210
andrewm@0 211 int PhaserAudioProcessor::getNumPrograms()
andrewm@0 212 {
andrewm@0 213 return 0;
andrewm@0 214 }
andrewm@0 215
andrewm@0 216 int PhaserAudioProcessor::getCurrentProgram()
andrewm@0 217 {
andrewm@0 218 return 0;
andrewm@0 219 }
andrewm@0 220
andrewm@0 221 void PhaserAudioProcessor::setCurrentProgram (int index)
andrewm@0 222 {
andrewm@0 223 }
andrewm@0 224
andrewm@0 225 const String PhaserAudioProcessor::getProgramName (int index)
andrewm@0 226 {
andrewm@0 227 return String::empty;
andrewm@0 228 }
andrewm@0 229
andrewm@0 230 void PhaserAudioProcessor::changeProgramName (int index, const String& newName)
andrewm@0 231 {
andrewm@0 232 }
andrewm@0 233
andrewm@0 234 //==============================================================================
andrewm@0 235 void PhaserAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
andrewm@0 236 {
andrewm@0 237 lfoPhase_ = 0.0;
andrewm@0 238 inverseSampleRate_ = 1.0/sampleRate;
andrewm@0 239 sampleCount_ = 0;
andrewm@0 240
andrewm@0 241 const ScopedLock sl (lock_);
andrewm@0 242 allocateFilters();
andrewm@0 243 }
andrewm@0 244
andrewm@0 245 void PhaserAudioProcessor::releaseResources()
andrewm@0 246 {
andrewm@0 247 const ScopedLock sl (lock_);
andrewm@0 248 deallocateFilters();
andrewm@0 249 }
andrewm@0 250
andrewm@0 251 void PhaserAudioProcessor::reset()
andrewm@0 252 {
andrewm@0 253 // Use this method as the place to clear any delay lines, buffers, etc, as it
andrewm@0 254 // means there's been a break in the audio's continuity.
andrewm@0 255
andrewm@0 256 lfoPhase_ = 0.0;
andrewm@0 257 sampleCount_ = 0;
andrewm@0 258 for(int i = 0; i < numLastFilterOutputs_; i++)
andrewm@0 259 lastFilterOutputs_[i] = 0.0f;
andrewm@0 260 }
andrewm@0 261
andrewm@0 262
andrewm@0 263 void PhaserAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
andrewm@0 264 {
andrewm@0 265 const ScopedLock sl (lock_);
andrewm@0 266
andrewm@0 267 // Helpful information about this block of samples:
andrewm@0 268 const int numInputChannels = getNumInputChannels(); // How many input channels for our effect?
andrewm@0 269 const int numOutputChannels = getNumOutputChannels(); // How many output channels for our effect?
andrewm@0 270 const int numSamples = buffer.getNumSamples(); // How many samples in the buffer for this block?
andrewm@0 271 float ph, channel0EndPhase = lfoPhase_;
andrewm@0 272 unsigned int sc;
andrewm@0 273
andrewm@0 274 // Go through each channel of audio that's passed in, applying one or more allpass filters
andrewm@0 275 // to each. Each channel will be treated identically in a (non-stereo) phaser, but we have
andrewm@0 276 // to have separate filter objects for each channel since the filters store the last few samples
andrewm@0 277 // passed through them.
andrewm@0 278
andrewm@0 279 // Filters are stored with all channel 0 filters first, then all channel 1 filters, etc.
andrewm@0 280
andrewm@0 281 for(int channel = 0; channel < numInputChannels; ++channel)
andrewm@0 282 {
andrewm@0 283 // channelData is an array of length numSamples which contains the audio for one channel
b@1 284 float* channelData = buffer.getWritePointer(channel);
andrewm@0 285
andrewm@0 286 ph = lfoPhase_;
andrewm@0 287 sc = sampleCount_;
andrewm@0 288
andrewm@0 289 // For stereo phasing, keep the channels 90 degrees out of phase with each other
andrewm@0 290 if(stereo_ != 0 && channel != 0)
andrewm@0 291 ph = fmodf(ph + 0.25, 1.0);
andrewm@0 292
andrewm@0 293 for (int sample = 0; sample < numSamples; ++sample)
andrewm@0 294 {
andrewm@0 295 float out = channelData[sample];
andrewm@0 296
andrewm@0 297 // If feedback is enabled, include the feedback from the last sample in the
andrewm@0 298 // input of the allpass filter chain. This is actually not accurate to how
andrewm@0 299 // analog phasers work because there is a sample of delay between output and
andrewm@0 300 // input, which adds a further phase shift of up to 180 degrees at half the
andrewm@0 301 // sampling frequency. To truly model an analog phaser with feedback involves
andrewm@0 302 // modelling a delay-free loop, which is beyond the scope of this example.
andrewm@0 303
andrewm@0 304 if(feedback_ != 0.0 && channel < numLastFilterOutputs_)
andrewm@0 305 out += feedback_ * lastFilterOutputs_[channel];
andrewm@0 306
andrewm@0 307 // See OnePoleAllpassFilter.cpp for calculation of coefficients and application
andrewm@0 308 // of filter to audio data. The filter processes the audio buffer in place,
andrewm@0 309 // putting the output sample in place of the input.
andrewm@0 310
andrewm@0 311 for(int j = 0; j < filtersPerChannel_; ++j)
andrewm@0 312 {
andrewm@0 313 // Safety check
andrewm@0 314 if(channel * filtersPerChannel_ + j >= totalNumFilters_)
andrewm@0 315 continue;
andrewm@0 316
andrewm@0 317 // First, update the current allpass filter coefficients depending on the parameter
andrewm@0 318 // settings and the LFO phase
andrewm@0 319
andrewm@0 320 // Recalculating the filter coefficients is much more expensive than calculating
andrewm@0 321 // a sample. Only update the coefficients at a fraction of the sample rate; since
andrewm@0 322 // the LFO moves slowly, the difference won't generally be audible.
andrewm@0 323 if(sc % filterUpdateInterval_ == 0)
andrewm@0 324 {
andrewm@0 325 allpassFilters_[channel * filtersPerChannel_ + j]->makeAllpass(inverseSampleRate_,
andrewm@0 326 baseFrequency_ + sweepWidth_*lfo(ph, waveform_));
andrewm@0 327 }
andrewm@0 328 out = allpassFilters_[channel * filtersPerChannel_ + j]->processSingleSampleRaw(out);
andrewm@0 329 }
andrewm@0 330
andrewm@0 331 if(channel < numLastFilterOutputs_)
andrewm@0 332 lastFilterOutputs_[channel] = out;
andrewm@0 333
andrewm@0 334 // Add the allpass signal to the output, though maintaining constant level
andrewm@0 335 // depth = 0 --> input only ; depth = 1 --> evenly balanced input and output
andrewm@0 336 channelData[sample] = (1.0f-0.5f*depth_)*channelData[sample] + 0.5f*depth_*out;
andrewm@0 337
andrewm@0 338 // Update the LFO phase, keeping it in the range 0-1
andrewm@0 339 ph += lfoFrequency_*inverseSampleRate_;
andrewm@0 340 if(ph >= 1.0)
andrewm@0 341 ph -= 1.0;
andrewm@0 342 sc++;
andrewm@0 343 }
andrewm@0 344
andrewm@0 345 // Use channel 0 only to keep the phase in sync between calls to processBlock()
andrewm@0 346 // Otherwise quadrature phase on multiple channels will create problems.
andrewm@0 347 if(channel == 0)
andrewm@0 348 channel0EndPhase = ph;
andrewm@0 349 }
andrewm@0 350
andrewm@0 351 lfoPhase_ = channel0EndPhase;
andrewm@0 352 sampleCount_ = sc;
andrewm@0 353
andrewm@0 354 // Go through the remaining channels. In case we have more outputs
andrewm@0 355 // than inputs, or there aren't enough filters, we'll clear any
andrewm@0 356 // remaining output channels (which could otherwise contain garbage)
andrewm@0 357 for(int channel = numInputChannels; channel < numOutputChannels; ++channel)
andrewm@0 358 {
andrewm@0 359 buffer.clear (channel++, 0, buffer.getNumSamples());
andrewm@0 360 }
andrewm@0 361 }
andrewm@0 362
andrewm@0 363 //==============================================================================
andrewm@0 364 bool PhaserAudioProcessor::hasEditor() const
andrewm@0 365 {
andrewm@0 366 return true; // (change this to false if you choose to not supply an editor)
andrewm@0 367 }
andrewm@0 368
andrewm@0 369 AudioProcessorEditor* PhaserAudioProcessor::createEditor()
andrewm@0 370 {
andrewm@0 371 return new PhaserAudioProcessorEditor (this);
andrewm@0 372 }
andrewm@0 373
andrewm@0 374 //==============================================================================
andrewm@0 375 void PhaserAudioProcessor::getStateInformation (MemoryBlock& destData)
andrewm@0 376 {
andrewm@0 377 // You should use this method to store your parameters in the memory block.
andrewm@0 378 // You could do that either as raw data, or use the XML or ValueTree classes
andrewm@0 379 // as intermediaries to make it easy to save and load complex data.
andrewm@0 380
andrewm@0 381 // Create an outer XML element..
andrewm@0 382 XmlElement xml("C4DMPLUGINSETTINGS");
andrewm@0 383
andrewm@0 384 // add some attributes to it..
andrewm@0 385 xml.setAttribute("uiWidth", lastUIWidth_);
andrewm@0 386 xml.setAttribute("uiHeight", lastUIHeight_);
andrewm@0 387 xml.setAttribute("baseFrequency_", baseFrequency_);
andrewm@0 388 xml.setAttribute("feedback", feedback_);
andrewm@0 389 xml.setAttribute("sweepWidth", sweepWidth_);
andrewm@0 390 xml.setAttribute("depth", depth_);
andrewm@0 391 xml.setAttribute("lfoFrequency", lfoFrequency_);
andrewm@0 392 xml.setAttribute("filtersPerChannel", filtersPerChannel_);
andrewm@0 393 xml.setAttribute("waveform", waveform_);
andrewm@0 394 xml.setAttribute("stereo", stereo_);
andrewm@0 395
andrewm@0 396 // then use this helper function to stuff it into the binary blob and return it..
andrewm@0 397 copyXmlToBinary(xml, destData);
andrewm@0 398 }
andrewm@0 399
andrewm@0 400 void PhaserAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
andrewm@0 401 {
andrewm@0 402 // You should use this method to restore your parameters from this memory block,
andrewm@0 403 // whose contents will have been created by the getStateInformation() call.
andrewm@0 404
andrewm@0 405 // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
andrewm@0 406 ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
andrewm@0 407
andrewm@0 408 if(xmlState != 0)
andrewm@0 409 {
andrewm@0 410 // make sure that it's actually our type of XML object..
andrewm@0 411 if(xmlState->hasTagName("C4DMPLUGINSETTINGS"))
andrewm@0 412 {
andrewm@0 413 // ok, now pull out our parameters..
andrewm@0 414 lastUIWidth_ = xmlState->getIntAttribute("uiWidth", lastUIWidth_);
andrewm@0 415 lastUIHeight_ = xmlState->getIntAttribute("uiHeight", lastUIHeight_);
andrewm@0 416
andrewm@0 417 baseFrequency_ = (float)xmlState->getDoubleAttribute("baseFrequency", baseFrequency_);
andrewm@0 418 feedback_ = (float)xmlState->getDoubleAttribute("feedback", feedback_);
andrewm@0 419 sweepWidth_ = (float)xmlState->getDoubleAttribute("sweepWidth", sweepWidth_);
andrewm@0 420 depth_ = (float)xmlState->getDoubleAttribute("depth", depth_);
andrewm@0 421 lfoFrequency_ = (float)xmlState->getDoubleAttribute("lfoFrequency", lfoFrequency_);
andrewm@0 422 filtersPerChannel_ = xmlState->getIntAttribute("filtersPerChannel", filtersPerChannel_);
andrewm@0 423 waveform_ = xmlState->getIntAttribute("waveform", waveform_);
andrewm@0 424 stereo_ = xmlState->getIntAttribute("stereo", stereo_);
andrewm@0 425 }
andrewm@0 426 }
andrewm@0 427 }
andrewm@0 428
andrewm@0 429 //==============================================================================
andrewm@0 430 // Function for calculating LFO waveforms. Phase runs from 0-1, output is scaled
andrewm@0 431 // from 0 to 1 (note: not -1 to 1 as would be typical of sine).
andrewm@0 432 float PhaserAudioProcessor::lfo(float phase, int waveform)
andrewm@0 433 {
andrewm@0 434 switch(waveform)
andrewm@0 435 {
andrewm@0 436 case kWaveformTriangle:
andrewm@0 437 if(phase < 0.25f)
andrewm@0 438 return 0.5f + 2.0f*phase;
andrewm@0 439 else if(phase < 0.75f)
andrewm@0 440 return 1.0f - 2.0f*(phase - 0.25f);
andrewm@0 441 else
andrewm@0 442 return 2.0f*(phase-0.75f);
andrewm@0 443 case kWaveformSquare:
andrewm@0 444 if(phase < 0.5f)
andrewm@0 445 return 1.0f;
andrewm@0 446 else
andrewm@0 447 return 0.0f;
andrewm@0 448 case kWaveformSawtooth:
andrewm@0 449 if(phase < 0.5f)
andrewm@0 450 return 0.5f + phase;
andrewm@0 451 else
andrewm@0 452 return phase - 0.5f;
andrewm@0 453 case kWaveformSine:
andrewm@0 454 default:
andrewm@0 455 return 0.5f + 0.5f*sinf(2.0 * M_PI * phase);
andrewm@0 456 }
andrewm@0 457 }
andrewm@0 458
andrewm@0 459 void PhaserAudioProcessor::allocateFilters()
andrewm@0 460 {
andrewm@0 461 // Create any filters we need; depends on number of channels and number of
andrewm@0 462 // filters per channel
andrewm@0 463 totalNumFilters_ = getNumInputChannels() * filtersPerChannel_;
andrewm@0 464 if(totalNumFilters_ > 0) {
andrewm@0 465 allpassFilters_ = (OnePoleAllpassFilter**)malloc(totalNumFilters_ * sizeof(OnePoleAllpassFilter*));
andrewm@0 466 if(allpassFilters_ == 0)
andrewm@0 467 totalNumFilters_ = 0;
andrewm@0 468 else {
andrewm@0 469 for(int i = 0; i < totalNumFilters_; i++)
andrewm@0 470 allpassFilters_[i] = new OnePoleAllpassFilter;
andrewm@0 471 }
andrewm@0 472 }
andrewm@0 473
andrewm@0 474 numLastFilterOutputs_ = getNumInputChannels();
andrewm@0 475 lastFilterOutputs_ = (float *)malloc(numLastFilterOutputs_ * sizeof(float));
andrewm@0 476 for(int i = 0; i < numLastFilterOutputs_; i++)
andrewm@0 477 lastFilterOutputs_[i] = 0.0f;
andrewm@0 478
andrewm@0 479 // Coefficients of allpass filters will get updated in processBlock()
andrewm@0 480 }
andrewm@0 481
andrewm@0 482 void PhaserAudioProcessor::deallocateFilters()
andrewm@0 483 {
andrewm@0 484 // Release the filters that were created in prepareToPlay()
andrewm@0 485
andrewm@0 486 for(int i = 0; i < totalNumFilters_; i++)
andrewm@0 487 delete allpassFilters_[i];
andrewm@0 488 if(totalNumFilters_ != 0)
andrewm@0 489 free(allpassFilters_);
andrewm@0 490 totalNumFilters_ = 0;
andrewm@0 491 allpassFilters_ = 0;
andrewm@0 492
andrewm@0 493 if(numLastFilterOutputs_ != 0)
andrewm@0 494 free(lastFilterOutputs_);
andrewm@0 495 numLastFilterOutputs_ = 0;
andrewm@0 496 lastFilterOutputs_ = 0;
andrewm@0 497 }
andrewm@0 498
andrewm@0 499 // Release and recreate the filters in one atomic operation:
andrewm@0 500 // the ScopedLock will not let the audio thread run between
andrewm@0 501 // release and allocation
andrewm@0 502 void PhaserAudioProcessor::reallocateFilters()
andrewm@0 503 {
andrewm@0 504 const ScopedLock sl (lock_);
andrewm@0 505 deallocateFilters();
andrewm@0 506 allocateFilters();
andrewm@0 507 }
andrewm@0 508
andrewm@0 509 //==============================================================================
andrewm@0 510 // This creates new instances of the plugin..
andrewm@0 511 AudioProcessor* JUCE_CALLTYPE createPluginFilter()
andrewm@0 512 {
andrewm@0 513 return new PhaserAudioProcessor();
andrewm@0 514 }