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: Compressor: dynamic range compression effect
andrewm@0: See textbook Chapter 6: Dynamics Processing
andrewm@0:
andrewm@0: Code by Joshua Reiss, Brecht de Man and Andrew McPherson
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: #include "PluginProcessor.h"
andrewm@0: #include "PluginEditor.h"
andrewm@0: CompressorAudioProcessor::CompressorAudioProcessor()
andrewm@0: // Initializer List
andrewm@0: :
andrewm@0: inputBuffer(1,1),
andrewm@0: nhost(0)
andrewm@0: {
andrewm@0: lastUIWidth = 850;
andrewm@0: lastUIHeight = 650;
andrewm@0: lastPosInfo.resetToDefault();
andrewm@0: }
andrewm@0: CompressorAudioProcessor::~CompressorAudioProcessor()
andrewm@0: {
andrewm@0: }
andrewm@0: //==============================================================================
andrewm@0: void CompressorAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
andrewm@0: {
andrewm@0: // Use this method as the place to do any pre-playback initialisation that you need.
andrewm@0: M = round(getNumInputChannels()/2);
andrewm@0: samplerate = (float)getSampleRate();
andrewm@0: bufferSize = getBlockSize();
andrewm@0: // Allocate a lot of dynamic memory here
andrewm@0: x_g .allocate(bufferSize, true);
andrewm@0: x_l .allocate(bufferSize, true);
andrewm@0: y_g .allocate(bufferSize, true);
andrewm@0: y_l .allocate(bufferSize, true);
andrewm@0: c .allocate(bufferSize, true);
andrewm@0: yL_prev=0;
andrewm@0: autoTime = false;
andrewm@0: compressorONOFF = false;
andrewm@0: resetAll();
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::releaseResources()
andrewm@0: {
andrewm@0: // When playback stops, you can use this to free up any spare memory, etc.
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
andrewm@0: {
andrewm@0: if (compressorONOFF)
andrewm@0: {
andrewm@0: inputBuffer.setSize(M,bufferSize);
andrewm@0: inputBuffer.clear();
andrewm@0: for (int m = 0 ; m < M ; ++m)
andrewm@0: {
andrewm@0: if ( (threshold< 0) )
andrewm@0: {
andrewm@0: inputBuffer.clear(m,0,bufferSize);
andrewm@0: // Mix down left-right to analyse the input
andrewm@0: inputBuffer.addFrom(m,0,buffer,m*2,0,bufferSize,0.5);
andrewm@0: inputBuffer.addFrom(m,0,buffer,m*2+1,0,bufferSize,0.5);
andrewm@0: // compression : calculates the control voltage
andrewm@0: compressor(inputBuffer,m);
andrewm@0: // apply control voltage to the audio signal
andrewm@0: for (int i = 0 ; i < bufferSize ; ++i)
andrewm@0: {
b@1: buffer.getWritePointer(2*m+0)[i] *= c[i];
b@1: buffer.getWritePointer(2*m+1)[i] *= c[i];
andrewm@0: }
andrewm@0: inputBuffer.clear(m,0,bufferSize);
andrewm@0: // Mix down left-right to analyse the output
andrewm@0: inputBuffer.addFrom(m,0,buffer,m*2,0,bufferSize,0.5);
andrewm@0: inputBuffer.addFrom(m,0,buffer,m*2+1,0,bufferSize,0.5);
andrewm@0: }
andrewm@0: }
andrewm@0: }
andrewm@0: }
andrewm@0: // compressor functions
andrewm@0: void CompressorAudioProcessor::compressor(AudioSampleBuffer &buffer, int m)
andrewm@0: {
andrewm@0: alphaAttack = exp(-1/(0.001 * samplerate * tauAttack));
andrewm@0: alphaRelease= exp(-1/(0.001 * samplerate * tauRelease));
andrewm@0: for (int i = 0 ; i < bufferSize ; ++i)
andrewm@0: {
andrewm@0: //Level detection- estimate level using peak detector
b@1: if (fabs(buffer.getWritePointer(m)[i]) < 0.000001) x_g[i] =-120;
b@1: else x_g[i] =20*log10(fabs(buffer.getWritePointer(m)[i]));
andrewm@0: //Gain computer- static apply input/output curve
andrewm@0: if (x_g[i] >= threshold) y_g[i] = threshold+ (x_g[i] - threshold) / ratio;
andrewm@0: else y_g[i] = x_g[i];
andrewm@0: x_l[i] = x_g[i] - y_g[i];
andrewm@0: //Ballistics- smoothing of the gain
andrewm@0: if (x_l[0]>yL_prev) y_l[i]=alphaAttack * yL_prev+(1 - alphaAttack ) * x_l[i] ;
andrewm@0: else y_l[i]=alphaRelease* yL_prev+(1 - alphaRelease) * x_l[i] ;
andrewm@0: //find control
andrewm@0: c[i] = pow(10,(makeUpGain - y_l[i])/20);
andrewm@0: yL_prev=y_l[i];
andrewm@0: }
andrewm@0: }
andrewm@0: template const T& CompressorAudioProcessor::max( const T& a, const T& b )
andrewm@0: {
andrewm@0: return (a < b) ? b : a;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::resetAll()
andrewm@0: {
andrewm@0: tauAttack=0;tauRelease = 0;
andrewm@0: alphaAttack=0;alphaRelease = 0;
andrewm@0: threshold = 0;
andrewm@0: ratio= 1;
andrewm@0: makeUpGain= 0;
andrewm@0: yL_prev=0;
andrewm@0: for (int i = 0 ; i < bufferSize ; ++i)
andrewm@0: {
andrewm@0: x_g[i] = 0; y_g[i] = 0;
andrewm@0: x_l[i] = 0; y_l[i] = 0;
andrewm@0: c[i] = 0;
andrewm@0: }
andrewm@0: }
andrewm@0: //////////////////////////////////////////////
andrewm@0: float CompressorAudioProcessor::getThreshold()
andrewm@0: {
andrewm@0: return threshold;
andrewm@0: }
andrewm@0: float CompressorAudioProcessor::getRatio()
andrewm@0: {
andrewm@0: return ratio;
andrewm@0: }
andrewm@0: float CompressorAudioProcessor::getGain()
andrewm@0: {
andrewm@0: return makeUpGain;//problem?
andrewm@0: }
andrewm@0: float CompressorAudioProcessor::getAttackTime()
andrewm@0: {
andrewm@0: return tauAttack;
andrewm@0: }
andrewm@0: float CompressorAudioProcessor::getReleaseTime()
andrewm@0: {
andrewm@0: return tauRelease;
andrewm@0: }
andrewm@0: ////////////////////////////////////////////////////////
andrewm@0: void CompressorAudioProcessor::setThreshold(float T)
andrewm@0: {
andrewm@0: threshold= T;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setGain(float G)
andrewm@0: {
andrewm@0: makeUpGain= G;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setRatio(float R)
andrewm@0: {
andrewm@0: ratio= R;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setAttackTime(float A)
andrewm@0: {
andrewm@0: tauAttack = A;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setReleaseTime(float R)
andrewm@0: {
andrewm@0: tauRelease = R;
andrewm@0: }
andrewm@0: bool CompressorAudioProcessor::hasEditor() const
andrewm@0: {
andrewm@0: return true; // (change this to false if you choose to not supply an editor)
andrewm@0: }
andrewm@0: AudioProcessorEditor* CompressorAudioProcessor::createEditor()
andrewm@0: {
andrewm@0: return new CompressorAudioProcessorEditor (this);
andrewm@0: }
andrewm@0: //==============================================================================
andrewm@0: void CompressorAudioProcessor::getStateInformation (MemoryBlock& destData)
andrewm@0: {
andrewm@0: //Use this to store your parameters in memory block, either as raw data, or use XML or ValueTree classes as intermediaries to make it easy to save and load complex data.
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
andrewm@0: {
andrewm@0: // Use this to restore your parameters from this memory block, whose contents will have been created by the getStateInformation() call.
andrewm@0: }
andrewm@0: // This creates new instances of the plugin..
andrewm@0: AudioProcessor* JUCE_CALLTYPE createPluginFilter()
andrewm@0: {
andrewm@0: return new CompressorAudioProcessor();
andrewm@0: }
andrewm@0: int CompressorAudioProcessor::round(float inn)
andrewm@0: {
andrewm@0: if (inn > 0) return (int) (inn + 0.5);
andrewm@0: else return (int) (inn - 0.5);
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getName() const
andrewm@0: {
andrewm@0: return JucePlugin_Name;
andrewm@0: }
andrewm@0: int CompressorAudioProcessor::getNumParameters()
andrewm@0: {
andrewm@0: return 0;
andrewm@0: }
andrewm@0: float CompressorAudioProcessor::getParameter (int index)
andrewm@0: {
andrewm@0: return 0.0f;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setParameter (int index, float newValue)
andrewm@0: {
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getParameterName (int index)
andrewm@0: {
andrewm@0: return String::empty;
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getParameterText (int index)
andrewm@0: {
andrewm@0: return String::empty;
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getInputChannelName (int channelIndex) const
andrewm@0: {
andrewm@0: return String (channelIndex + 1);
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getOutputChannelName (int channelIndex) const
andrewm@0: {
andrewm@0: return String (channelIndex + 1);
andrewm@0: }
andrewm@0: bool CompressorAudioProcessor::isInputChannelStereoPair (int index) const
andrewm@0: {
andrewm@0: return true;
andrewm@0: }
andrewm@0: bool CompressorAudioProcessor::isOutputChannelStereoPair (int index) const
andrewm@0: {
andrewm@0: return true;
andrewm@0: }
andrewm@0: bool CompressorAudioProcessor::silenceInProducesSilenceOut() const
andrewm@0: {
andrewm@0: #if JucePlugin_SilenceInProducesSilenceOut
andrewm@0: return true;
andrewm@0: #else
andrewm@0: return false;
andrewm@0: #endif
andrewm@0: }
andrewm@0:
andrewm@0: double CompressorAudioProcessor::getTailLengthSeconds() const
andrewm@0: {
andrewm@0: return 0.0;
andrewm@0: }
andrewm@0: bool CompressorAudioProcessor::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: bool CompressorAudioProcessor::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: int CompressorAudioProcessor::getNumPrograms()
andrewm@0: {
andrewm@0: return 0;
andrewm@0: }
andrewm@0: int CompressorAudioProcessor::getCurrentProgram()
andrewm@0: {
andrewm@0: return 0;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::setCurrentProgram (int index)
andrewm@0: {
andrewm@0: }
andrewm@0: const String CompressorAudioProcessor::getProgramName (int index)
andrewm@0: {
andrewm@0: return String::empty;
andrewm@0: }
andrewm@0: void CompressorAudioProcessor::changeProgramName (int index, const String& newName)
andrewm@0: {
andrewm@0: }