#include "PluginProcessor.h" #include "PluginEditor.h" SaftpumpeProcessor::SaftpumpeProcessor() : AudioProcessor(BusesProperties() .withInput("Input", juce::AudioChannelSet::stereo(), true) .withOutput("Output", juce::AudioChannelSet::stereo(), true)), parameters(*this, nullptr, "Parameters", { std::make_unique( thresholdID, "Threshold", juce::NormalisableRange(-48.0f, 0.0f, 0.1f), -20.0f), std::make_unique( ratioID, "Ratio", juce::NormalisableRange(1.0f, 20.0f, 0.1f, 0.5f), 4.0f), std::make_unique( attackID, "Attack", juce::NormalisableRange(0.001f, 0.1f, 0.001f, 0.5f), 0.03f), std::make_unique( releaseID, "Release", juce::NormalisableRange(0.05f, 1.5f, 0.01f, 0.5f), 0.3f), std::make_unique( kneeID, "Knee", juce::NormalisableRange(0.0f, 12.0f, 0.5f), 6.0f), std::make_unique( makeupID, "Makeup", juce::NormalisableRange(0.0f, 24.0f, 0.1f), 0.0f), std::make_unique( mixID, "Mix", juce::NormalisableRange(0.0f, 1.0f, 0.01f), 1.0f), std::make_unique( autoReleaseID, "Auto Release", juce::NormalisableRange(0.0f, 1.0f, 0.01f), 1.0f) }) { inputScope.fill(0.0f); outputScope.fill(0.0f); } SaftpumpeProcessor::~SaftpumpeProcessor() {} void SaftpumpeProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { compressorL.prepare(sampleRate, samplesPerBlock); compressorR.prepare(sampleRate, samplesPerBlock); compressorL.reset(); compressorR.reset(); scopeIndex = 0; } void SaftpumpeProcessor::releaseResources() {} void SaftpumpeProcessor::processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer&) { juce::ScopedNoDenormals noDenormals; auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear(i, 0, buffer.getNumSamples()); updateCompressorParams(); float maxInput = 0.0f; float maxOutput = 0.0f; float maxGR = 0.0f; int numSamples = buffer.getNumSamples(); float* channelDataL = buffer.getWritePointer(0); float* channelDataR = (totalNumInputChannels > 1) ? buffer.getWritePointer(1) : nullptr; for (int sample = 0; sample < numSamples; ++sample) { float inL = channelDataL[sample]; float inR = channelDataR ? channelDataR[sample] : inL; float absIn = std::max(std::abs(inL), std::abs(inR)); if (absIn > maxInput) maxInput = absIn; inputScope[scopeIndex] = inL; float outL = compressorL.processSample(inL); float outR = compressorR.processSample(inR); channelDataL[sample] = outL; if (channelDataR) channelDataR[sample] = outR; float absOut = std::max(std::abs(outL), std::abs(outR)); if (absOut > maxOutput) maxOutput = absOut; float gr = std::abs(compressorL.getGainReduction()); if (gr > maxGR) maxGR = gr; outputScope[scopeIndex] = outL; scopeIndex = (scopeIndex + 1) % scopeSize; } currentInputLevel = currentInputLevel * 0.8f + (maxInput > 0.0001f ? 20.0f * std::log10(maxInput) : -100.0f) * 0.2f; currentOutputLevel = currentOutputLevel * 0.8f + (maxOutput > 0.0001f ? 20.0f * std::log10(maxOutput) : -100.0f) * 0.2f; currentGainReduction = currentGainReduction * 0.7f + maxGR * 0.3f; } void SaftpumpeProcessor::updateCompressorParams() { CompressorDSP::Params p; p.threshold = parameters.getRawParameterValue(thresholdID)->load(); p.ratio = parameters.getRawParameterValue(ratioID)->load(); p.attack = parameters.getRawParameterValue(attackID)->load(); p.release = parameters.getRawParameterValue(releaseID)->load(); p.knee = parameters.getRawParameterValue(kneeID)->load(); p.makeup = parameters.getRawParameterValue(makeupID)->load(); p.mix = parameters.getRawParameterValue(mixID)->load(); p.autoRelease = parameters.getRawParameterValue(autoReleaseID)->load() > 0.5f; compressorL.setParams(p); compressorR.setParams(p); } juce::AudioProcessorEditor* SaftpumpeProcessor::createEditor() { return new SaftpumpeEditor(*this); } void SaftpumpeProcessor::getStateInformation(juce::MemoryBlock& destData) { auto state = parameters.copyState(); std::unique_ptr xml(state.createXml()); copyXmlToBinary(*xml, destData); } void SaftpumpeProcessor::setStateInformation(const void* data, int sizeInBytes) { std::unique_ptr xml(getXmlFromBinary(data, sizeInBytes)); if (xml && xml->hasTagName(parameters.state.getType())) { parameters.replaceState(juce::ValueTree::fromXml(*xml)); } } juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() { return new SaftpumpeProcessor(); }