/* * Power Juice Plugin * Copyright (C) 2014 Andre Sklenar , www.juicelab.cz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ #include "PowerJuiceX2Plugin.hpp" #include #include START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- PowerJuiceX2Plugin::PowerJuiceX2Plugin() : Plugin(paramCount, 1, 0) // 1 program, 0 states { std::memset(&RMSStack, 0, sizeof(RMSStack)); std::memset(&lookaheadStack, 0, sizeof(lookaheadStack)); // set default values loadProgram(0); // reset deactivate(); } PowerJuiceX2Plugin::~PowerJuiceX2Plugin() { std::free(RMSStack.data); std::free(lookaheadStack.data); } // ----------------------------------------------------------------------- // Init void PowerJuiceX2Plugin::initParameter(uint32_t index, Parameter& parameter) { switch (index) { case paramAttack: parameter.hints = kParameterIsAutomatable; parameter.name = "Attack"; parameter.symbol = "att"; parameter.unit = "ms"; parameter.ranges.def = 20.0f; parameter.ranges.min = 0.1f; parameter.ranges.max = 1000.0f; break; case paramRelease: parameter.hints = kParameterIsAutomatable; parameter.name = "Release"; parameter.symbol = "rel"; parameter.unit = "ms"; parameter.ranges.def = 200.0f; parameter.ranges.min = 0.1f; parameter.ranges.max = 1000.0f; break; case paramThreshold: parameter.hints = kParameterIsAutomatable; parameter.name = "Threshold"; parameter.symbol = "thr"; parameter.unit = "dB"; parameter.ranges.def = 0.0f; parameter.ranges.min = -60.0f; parameter.ranges.max = 0.0f; break; case paramRatio: parameter.hints = kParameterIsAutomatable; parameter.name = "Ratio"; parameter.symbol = "rat"; parameter.unit = ""; parameter.ranges.def = 1.0f; parameter.ranges.min = 1.0f; parameter.ranges.max = 10.0f; break; case paramMakeup: parameter.hints = kParameterIsAutomatable; parameter.name = "Make-Up"; parameter.symbol = "mak"; parameter.unit = ""; parameter.ranges.def = 0.0f; parameter.ranges.min = 0.0f; parameter.ranges.max = 20.0f; break; case paramMix: parameter.hints = kParameterIsAutomatable; parameter.name = "Mix"; parameter.symbol = "Mix"; parameter.unit = ""; parameter.ranges.def = 1.0f; parameter.ranges.min = 0.0f; parameter.ranges.max = 1.0f; break; } } void PowerJuiceX2Plugin::initProgramName(uint32_t index, String& programName) { if (index != 0) return; programName = "Default"; } // ----------------------------------------------------------------------- // Internal data float PowerJuiceX2Plugin::getParameterValue(uint32_t index) const { switch (index) { case paramAttack: return attack; case paramRelease: return release; case paramThreshold: return threshold; case paramRatio: return ratio; case paramMakeup: return makeup; case paramMix: return mix; default: return 0.0f; } } void PowerJuiceX2Plugin::setParameterValue(uint32_t index, float value) { switch (index) { case paramAttack: attack = value; attackSamples = getSampleRate()*(attack/1000.0f); break; case paramRelease: release = value; releaseSamples = getSampleRate()*(release/1000.0f); break; case paramThreshold: threshold = value; break; case paramRatio: ratio = value; break; case paramMakeup: makeup = value; makeupFloat = fromDB(makeup); break; case paramMix: mix = value; break; } } void PowerJuiceX2Plugin::loadProgram(uint32_t index) { if (index != 0) return; /* Default parameter values */ attack = 20.0f; release = 200.0f; threshold = 0.0f; ratio = 1.0f; makeup = 0.0f; mix = 1.0f; makeupFloat = fromDB(makeup); attackSamples = getSampleRate()*(attack/1000.0f); releaseSamples = getSampleRate()*(release/1000.0f); w = 563; //waveform plane size, size of the plane in pixels; w2 = 1126; //wavefowm array h = 121; //waveform plane height x = 27; //waveform plane positions y = 53; dc = 113; //0DC line y position /* Default variable values */ averageCounter = 0; inputMax = 0.0f; balancer = 1.0f; GR = 1.0f; newRepaint = false; input.start = 0; rms.start = 0; gainReduction.start = 0; RMSStack.start = 0; lookaheadStack.start = 0; repaintSkip = 0; kFloatRMSStackCount = 400.0f/44100.0f*getSampleRate(); std::free(RMSStack.data); RMSStack.data = (float*) calloc(kFloatRMSStackCount, sizeof(float)); kFloatLookaheadStackCount = 800.0f/44100.0f*getSampleRate(); std::free(lookaheadStack.data); lookaheadStack.data = (float*) calloc(kFloatLookaheadStackCount, sizeof(float)); refreshSkip= 300.0f/44100.0f*getSampleRate(); std::memset(rms.data, 0, sizeof(float)*kFloatStackCount); std::memset(gainReduction.data, 0, sizeof(float)*kFloatStackCount); std::memset(RMSStack.data, 0, sizeof(float)*kFloatRMSStackCount); std::memset(lookaheadStack.data, 0, sizeof(float)*kFloatLookaheadStackCount); for (int j=0; j < kFloatStackCount; ++j) history.rms[j] = h +y; for (int j=0; j < kFloatStackCount; ++j) history.gainReduction[j] = h +y; activate(); } float PowerJuiceX2Plugin::getRMSHistory(int n) { return history.rms[n]; } bool PowerJuiceX2Plugin::repaintNeeded() { return newRepaint; } float PowerJuiceX2Plugin::getGainReductionHistory(int n) { if (n == kFloatStackCount-1) { newRepaint = false; //printf("falsing!\n"); } return history.gainReduction[n]; } // ----------------------------------------------------------------------- // Process void PowerJuiceX2Plugin::activate() { } void PowerJuiceX2Plugin::deactivate() { // all values to zero } void PowerJuiceX2Plugin::run(const float** inputs, float** outputs, uint32_t frames) { const float* in1 = inputs[0]; const float* in2 = inputs[1]; float* out1 = outputs[0]; float* out2 = outputs[1]; float sum; float data; float difference; for (uint32_t i=0; i < frames; i++) { sum = 0.0f; data = 0.0f; difference = 0; //sanitizeDenormal(in1[i]); // FIXME - you cannot modify inputs //sanitizeDenormal(in2[i]); // FIXME - you cannot modify inputs /* compute last RMS */ //store audio samples in an RMS buffer line RMSStack.data[RMSStack.start++] = std::max(in1[i], in2[i]); if (RMSStack.start == kFloatRMSStackCount) RMSStack.start = 0; //compute RMS over last kFloatRMSStackCount samples for (int j=0; j < kFloatRMSStackCount; ++j) { data = RMSStack.data[(RMSStack.start+j) % kFloatRMSStackCount]; sum += data * data; } //root mean SQUARE float RMS = sqrt(sum / kFloatRMSStackCount); sanitizeDenormal(RMS); /* compute gain reduction if needed */ float RMSDB = toDB(RMS); if (RMSDB>threshold) { //attack stage float difference = (RMSDB-threshold); //sanitizeDenormal(difference); targetGR = difference - difference/ratio; if (targetGR>difference/(ratio/4.0f)) { targetGR = difference - difference/(ratio*1.5f); //more power! } // if (GR= refreshSkip) { //add relevant values to the shared memory rms.data[rms.start++] = RMSDB; gainReduction.data[gainReduction.start++] = GR; //rewind stack reading heads if needed if (rms.start == kFloatStackCount) rms.start = 0; if (gainReduction.start == kFloatStackCount) gainReduction.start = 0; //saving in gfx format, for speed //share memory for (int j=0; j < kFloatStackCount; ++j) history.rms[j] = -toIEC(rms.data[(rms.start+j) % kFloatStackCount])/200*h +h +y; for (int j=0; j < kFloatStackCount; ++j) { history.gainReduction[j] = -toIEC(-gainReduction.data[(gainReduction.start+j) % kFloatStackCount])/200*h +h +y; } repaintSkip++; if (repaintSkip>5) { repaintSkip = 0; newRepaint = true; } averageCounter = 0; inputMax = 0.0f; } /* compress, mix, done. */ float realGR = fromDB(-GR); float compressedSignal1 = in1[i]*realGR; float compressedSignal2 = in2[i]*realGR; out1[i] = (compressedSignal1*makeupFloat*mix)+in1[i]*(1-mix); out2[i] = (compressedSignal2*makeupFloat*mix)+in2[i]*(1-mix); } } // ----------------------------------------------------------------------- Plugin* createPlugin() { return new PowerJuiceX2Plugin(); } // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO