|
- /*
- * Power Juice Plugin
- * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, 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 <cstdlib>
- #include <algorithm>
-
- 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<targetGR) {
- //approach targetGR at attackSamples rate
- GR -= (GR-targetGR)/(attackSamples);
- } else {
- //approach targetGR at releaseSamples rate
- GR -= (GR-targetGR)/releaseSamples;
- }
-
- sanitizeDenormal(GR);
- } else {
- //release stage
- //approach targetGR at releaseSamples rate, targetGR = 0.0f
- GR -= GR/releaseSamples;
- }
-
- //store audio in lookahead buffer
-
- lookaheadStack.data[lookaheadStack.start++] = std::max(in1[i], in2[i]);
- //printf("rms\n");
- if (lookaheadStack.start == kFloatLookaheadStackCount)
- lookaheadStack.start = 0;
-
- if (++averageCounter >= 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
|