andrewm@0: /*
andrewm@0: This code accompanies the textbook:
andrewm@0:
andrewm@0: Digital Audio Effects: Theory, Implementation and Application
andrewm@0: Joshua D. Reiss and Andrew P. McPherson
andrewm@0:
andrewm@0: ---
andrewm@0:
andrewm@0: Reverb: algorithmic reverb effect based on MVerb
andrewm@0: See textbook Chapter 11: Reverberation
andrewm@0:
andrewm@0: Original code by Martin Eastwood: MVerb (see MVerb.h)
andrewm@0: Adapted for JUCE by Brecht De Man
andrewm@0:
andrewm@0: When using this code (or a modified version thereof) please cite:
andrewm@0:
andrewm@0: R. Stables, S. Enderby, B. De Man, G. Fazekas, J. D. Reiss, "SAFE:
andrewm@0: A System for the Extraction and Retrieval of Semantic Audio
andrewm@0: Descriptors," 15th International Society for Music Information
andrewm@0: Retrieval Conference (ISMIR 2014), 2014.
andrewm@0:
andrewm@0: ---
andrewm@0:
andrewm@0: This program is free software: you can redistribute it and/or modify
andrewm@0: it under the terms of the GNU General Public License as published by
andrewm@0: the Free Software Foundation, either version 3 of the License, or
andrewm@0: (at your option) any later version.
andrewm@0:
andrewm@0: This program is distributed in the hope that it will be useful,
andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0: GNU General Public License for more details.
andrewm@0:
andrewm@0: You should have received a copy of the GNU General Public License
andrewm@0: along with this program. If not, see .
andrewm@0: */
andrewm@0:
andrewm@0:
andrewm@0: #include "PluginProcessor.h"
andrewm@0: #include "PluginEditor.h"
andrewm@0:
andrewm@0: #if JUCE_INTEL
andrewm@0: #define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8 || n > 1.0e-8)) n = 0;
andrewm@0: #else
andrewm@0: #define JUCE_SNAP_TO_ZERO(n)
andrewm@0: #endif
andrewm@0:
andrewm@0: ReverbAudioProcessor::ReverbAudioProcessor()
andrewm@0: :
andrewm@0: _numChannels (1)
andrewm@0: ,_numSamples (1) // dummy - will be set in prepareToPlay
andrewm@0: ,_sampleRate (1) // dummy - will be set in prepareToPlay
andrewm@0: ,_density (1.0)
andrewm@0: ,_decay (1.0)
andrewm@0: ,_size (1.0)
andrewm@0: ,_damp (1.0)
andrewm@0: ,_bandwidth (1.0)
andrewm@0: ,_predelay (0.0)
andrewm@0: ,_gain (1.0)
andrewm@0: ,_mix (0.5)
andrewm@0: ,_lateEarly (0.5)
andrewm@0: ,tempInput (1,1)// dummy - will be set in prepareToPlay
andrewm@0: ,tempOutput (1,1)// dummy - will be set in prepareToPlay
andrewm@0: ,_lastUIWidth (850)
andrewm@0: ,_lastUIHeight (650)
andrewm@0:
andrewm@0: {
andrewm@0: // Update all parameters
andrewm@0: for (int index = 0; index < MVerb::NUM_PARAMS; ++index)
andrewm@0: {
andrewm@0: updateParameters(index);
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: ReverbAudioProcessor::~ReverbAudioProcessor()
andrewm@0: {
andrewm@0: }
andrewm@0:
andrewm@0: //-----------------------------------------------------------------------------
andrewm@0: // P R E P A R E T O P L A Y
andrewm@0: void ReverbAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
andrewm@0: {
andrewm@0: // If sample rate/block size changes or straight after construction
andrewm@0: if (_numSamples != samplesPerBlock || _sampleRate != sampleRate)
andrewm@0: {
andrewm@0: _sampleRate = sampleRate;
andrewm@0: _numSamples = samplesPerBlock;
andrewm@0: _numChannels = getNumInputChannels();
andrewm@0:
andrewm@0: tempInput.setSize (_numChannels,_numSamples);
andrewm@0: tempOutput.setSize(_numChannels,_numSamples);
andrewm@0: tempInput.clear();
andrewm@0: tempOutput.clear();
andrewm@0:
andrewm@0: _mverb.reset();
andrewm@0: _mverb.setSampleRate (_sampleRate); // set reverb sample rate
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: //-----------------------------------------------------------------------------
andrewm@0: // P R O C E S S B L O C K
andrewm@0: void ReverbAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
andrewm@0: {
andrewm@0: int numSamples = buffer.getNumSamples();
andrewm@0: int numChannels = buffer.getNumChannels();
andrewm@0:
andrewm@0: for(int channel = 0; channel < numChannels; channel++)
andrewm@0: {
andrewm@0: tempInput.copyFrom (channel, 0, buffer, channel, 0, numSamples);
andrewm@0: }
andrewm@0:
andrewm@0: float** input = tempInput.getArrayOfWritePointers();
andrewm@0: float** output = tempOutput.getArrayOfWritePointers();
andrewm@0:
andrewm@0: _mverb.process (input, output, numSamples); // processing by MVerb
andrewm@0:
andrewm@0: for(int channel = 0; channel < numChannels; channel++)
andrewm@0: {
andrewm@0: buffer.copyFrom (channel, 0, output [channel], numSamples);
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: //-----------------------------------------------------------------------------
andrewm@0: // U P D A T E P A R A M E T E R S
andrewm@0: void ReverbAudioProcessor::updateParameters (int index)
andrewm@0: {
andrewm@0: switch(index)
andrewm@0: {
andrewm@0: case MVerb::DAMPINGFREQ:
andrewm@0: _mverb.setParameter (index, _damp);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::DENSITY:
andrewm@0: _mverb.setParameter (index, _density);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::BANDWIDTHFREQ:
andrewm@0: _mverb.setParameter (index, _bandwidth);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::PREDELAY:
andrewm@0: _mverb.setParameter (index, _predelay);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::DECAY:
andrewm@0: _mverb.setParameter (index, _decay);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::SIZE:
andrewm@0: _mverb.setParameter (index, _size);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::GAIN:
andrewm@0: _mverb.setParameter (index, _gain);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::MIX:
andrewm@0: _mverb.setParameter (index, _mix);
andrewm@0: break;
andrewm@0:
andrewm@0: case MVerb::EARLYMIX:
andrewm@0: _mverb.setParameter (index, _lateEarly);
andrewm@0: break;
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: //-----------------------------------------------------------------------------
andrewm@0: // R E S E T
andrewm@0: void ReverbAudioProcessor::Reset()
andrewm@0: {
andrewm@0: _mverb.reset(); // not used
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: //-----------------------------------------------------------------------------
andrewm@0: //
andrewm@0: void ReverbAudioProcessor::releaseResources()
andrewm@0: {
andrewm@0: // When playback stops, you can use this to free up any spare memory, etc.
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::hasEditor() const
andrewm@0: {
andrewm@0: return true; // (change this to false if you choose to not supply an editor)
andrewm@0: }
andrewm@0:
andrewm@0: AudioProcessorEditor* ReverbAudioProcessor::createEditor()
andrewm@0: {
andrewm@0: return new ReverbAudioProcessorEditor (this);
andrewm@0: }
andrewm@0:
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: void ReverbAudioProcessor::getStateInformation (MemoryBlock& destData)
andrewm@0: {
andrewm@0: // SAVE STATE INFO
andrewm@0: XmlElement xml("JRAMReverb_XML");
andrewm@0:
andrewm@0: // Knobs
andrewm@0: xml.setAttribute("_density" ,_density);
andrewm@0: xml.setAttribute("_decay" ,_decay);
andrewm@0: xml.setAttribute("_size" ,_size);
andrewm@0: xml.setAttribute("_damp" ,_damp);
andrewm@0: xml.setAttribute("_bandwidth" ,_bandwidth);
andrewm@0: xml.setAttribute("_predelay" ,_predelay);
andrewm@0: xml.setAttribute("_gain" ,_gain);
andrewm@0: xml.setAttribute("_mix" ,_mix);
andrewm@0: xml.setAttribute("_lateEarly" ,_lateEarly);
andrewm@0:
andrewm@0:
andrewm@0: // then use this helper function to stuff it into the binary blob and return it..
andrewm@0: copyXmlToBinary(xml, destData);
andrewm@0: }
andrewm@0:
andrewm@0: void ReverbAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
andrewm@0: {
andrewm@0: // LOAD STATE INFO
andrewm@0: ScopedPointer xmlState (getXmlFromBinary (data, sizeInBytes));
andrewm@0:
andrewm@0: // make sure that it's actually our type of XML object..
andrewm@0: if(xmlState->hasTagName("JRAMReverb_XML"))
andrewm@0: {
andrewm@0: // Knobs
andrewm@0: _density = (float) xmlState->getDoubleAttribute("_density",true);
andrewm@0: _decay = (float) xmlState->getDoubleAttribute("_decay",true);
andrewm@0: _size = (float) xmlState->getDoubleAttribute("_size",true);
andrewm@0: _damp = (float) xmlState->getDoubleAttribute("_damp",true);
andrewm@0: _bandwidth = (float) xmlState->getDoubleAttribute("_bandwidth",true);
andrewm@0: _predelay = (float) xmlState->getDoubleAttribute("_predelay",true);
andrewm@0: _gain = (float) xmlState->getDoubleAttribute("_gain",true);
andrewm@0: _mix = (float) xmlState->getDoubleAttribute("_mix",true);
andrewm@0: _lateEarly = (float) xmlState->getDoubleAttribute("_lateEarly",true);
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: // This creates new instances of the plugin..
andrewm@0: AudioProcessor* JUCE_CALLTYPE createPluginFilter()
andrewm@0: {
andrewm@0: return new ReverbAudioProcessor();
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getName() const
andrewm@0: {
andrewm@0: return JucePlugin_Name;
andrewm@0: }
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::silenceInProducesSilenceOut() const
andrewm@0: {
andrewm@0: return true;
andrewm@0: }
andrewm@0:
andrewm@0: int ReverbAudioProcessor::getNumParameters()
andrewm@0: {
andrewm@0: return MVerb::NUM_PARAMS;
andrewm@0: }
andrewm@0:
andrewm@0: float ReverbAudioProcessor::getParameter (int index) // externally accessible
andrewm@0: {
andrewm@0: switch (index)
andrewm@0: {
andrewm@0: case MVerb::DENSITY: return GetDensity();
andrewm@0: case MVerb::DECAY: return GetDecay();
andrewm@0: case MVerb::SIZE: return GetSize();
andrewm@0: case MVerb::DAMPINGFREQ: return GetDamp();
andrewm@0: case MVerb::BANDWIDTHFREQ: return GetBandwidth();
andrewm@0: case MVerb::PREDELAY: return GetPredelay();
andrewm@0: case MVerb::GAIN: return GetGain();
andrewm@0: case MVerb::MIX: return GetMix();
andrewm@0: case MVerb::EARLYMIX: return GetLateEarly();
andrewm@0: default: return 0.0f;
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: void ReverbAudioProcessor::setParameter (int index, float newValue) // externally accessible
andrewm@0: {
andrewm@0: switch (index)
andrewm@0: {
andrewm@0: case MVerb::DENSITY:
andrewm@0: SetDensity(newValue);
andrewm@0: break;
andrewm@0: case MVerb::DECAY:
andrewm@0: SetDecay(newValue);
andrewm@0: break;
andrewm@0: case MVerb::SIZE:
andrewm@0: SetSize(newValue);
andrewm@0: break;
andrewm@0: case MVerb::DAMPINGFREQ:
andrewm@0: SetDamp(newValue);
andrewm@0: break;
andrewm@0: case MVerb::BANDWIDTHFREQ:
andrewm@0: SetBandwidth(newValue);
andrewm@0: break;
andrewm@0: case MVerb::PREDELAY:
andrewm@0: SetPredelay(newValue);
andrewm@0: break;
andrewm@0: case MVerb::GAIN:
andrewm@0: SetGain(newValue);
andrewm@0: break;
andrewm@0: case MVerb::MIX:
andrewm@0: SetMix(newValue);
andrewm@0: break;
andrewm@0: case MVerb::EARLYMIX:
andrewm@0: SetLateEarly(newValue);
andrewm@0: break;
andrewm@0: default:
andrewm@0: break;
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getParameterName (int index) // externally accessible
andrewm@0: {
andrewm@0: switch (index)
andrewm@0: {
andrewm@0: case MVerb::DENSITY: return "Density";
andrewm@0: case MVerb::DECAY: return "Decay";
andrewm@0: case MVerb::SIZE: return "Size";
andrewm@0: case MVerb::DAMPINGFREQ: return "Damp";
andrewm@0: case MVerb::BANDWIDTHFREQ: return "Bandwidth";
andrewm@0: case MVerb::PREDELAY: return "Predelay";
andrewm@0: case MVerb::GAIN: return "Gain";
andrewm@0: case MVerb::MIX: return "Mix";
andrewm@0: case MVerb::EARLYMIX: return "Late vs. early reflections";
andrewm@0: default: break;
andrewm@0: }
andrewm@0: return String::empty;
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getParameterText (int index)
andrewm@0: {
andrewm@0: return String (getParameter (index), 2);
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getInputChannelName (int channelIndex) const
andrewm@0: {
andrewm@0: return String (channelIndex + 1);
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getOutputChannelName (int channelIndex) const
andrewm@0: {
andrewm@0: return String (channelIndex + 1);
andrewm@0: }
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::isInputChannelStereoPair (int index) const
andrewm@0: {
andrewm@0: return true;
andrewm@0: }
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::isOutputChannelStereoPair (int index) const
andrewm@0: {
andrewm@0: return true;
andrewm@0: }
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::acceptsMidi() const
andrewm@0: {
andrewm@0: #if JucePlugin_WantsMidiInput
andrewm@0: return true;
andrewm@0: #else
andrewm@0: return false;
andrewm@0: #endif
andrewm@0: }
andrewm@0:
andrewm@0: bool ReverbAudioProcessor::producesMidi() const
andrewm@0: {
andrewm@0: #if JucePlugin_ProducesMidiOutput
andrewm@0: return true;
andrewm@0: #else
andrewm@0: return false;
andrewm@0: #endif
andrewm@0: }
andrewm@0:
andrewm@0: int ReverbAudioProcessor::getNumPrograms()
andrewm@0: {
andrewm@0: return 0;
andrewm@0: }
andrewm@0:
andrewm@0: int ReverbAudioProcessor::getCurrentProgram()
andrewm@0: {
andrewm@0: return 0;
andrewm@0: }
andrewm@0:
andrewm@0: void ReverbAudioProcessor::setCurrentProgram (int index)
andrewm@0: {
andrewm@0: }
andrewm@0:
andrewm@0: const String ReverbAudioProcessor::getProgramName (int index)
andrewm@0: {
andrewm@0: return String::empty;
andrewm@0: }
andrewm@0:
andrewm@0: void ReverbAudioProcessor::changeProgramName (int index, const String& newName)
andrewm@0: {
andrewm@0: }