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: }