|
|
|
/**
|
|
|
|
|
|
|
|
Copyright (c) 2013-2014 Pascal Gauthier.
|
|
|
|
Copyright (c) 2013-2014 Filatov Vadim.
|
|
|
|
|
|
|
|
Filter taken from the Obxd project :
|
|
|
|
https://github.com/2DaT/Obxd
|
|
|
|
|
|
|
|
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 3 of the License, or
|
|
|
|
(at your option) 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.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _USE_MATH_DEFINES
|
|
|
|
#include <math.h>
|
|
|
|
#include "PluginFx.h"
|
|
|
|
#include "synth.h"
|
|
|
|
|
|
|
|
const float dc = 1e-18;
|
|
|
|
|
|
|
|
inline static float tptpc(float& state, float inp, float cutoff) {
|
|
|
|
float v = (inp - state) * cutoff / (1 + cutoff);
|
|
|
|
float res = v + state;
|
|
|
|
state = res + v;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) {
|
|
|
|
cutoff = (cutoff * srInv) * M_PI;
|
|
|
|
float v = (inp - state) * cutoff / (1 + cutoff);
|
|
|
|
float res = v + state;
|
|
|
|
state = res + v;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//static float linsc(float param,const float min,const float max) {
|
|
|
|
// return (param) * (max - min) + min;
|
|
|
|
//}
|
|
|
|
|
|
|
|
static float logsc(float param, const float min, const float max, const float rolloff = 19.0f) {
|
|
|
|
return ((EXP_FUNC(param * LOG_FUNC(rolloff + 1)) - 1.0f) / (rolloff)) * (max - min) + min;
|
|
|
|
}
|
|
|
|
|
|
|
|
PluginFx::PluginFx() {
|
|
|
|
Cutoff = 1;
|
|
|
|
Reso = 0;
|
|
|
|
Gain = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PluginFx::init(int sr) {
|
|
|
|
mm = 0;
|
|
|
|
s1 = s2 = s3 = s4 = c = d = 0;
|
|
|
|
R24 = 0;
|
|
|
|
|
|
|
|
mmch = (int)(mm * 3);
|
|
|
|
mmt = mm * 3 - mmch;
|
|
|
|
|
|
|
|
sampleRate = sr;
|
|
|
|
sampleRateInv = 1 / sampleRate;
|
|
|
|
#if defined(ARM_SQRT_FUNC)
|
|
|
|
float rcrate; ARM_SQRT_FUNC(44000 / sampleRate, &rcrate);
|
|
|
|
#else
|
|
|
|
float rcrate = SQRT_FUNC((44000 / sampleRate));
|
|
|
|
#endif
|
|
|
|
rcor24 = (970.0 / 44000) * rcrate;
|
|
|
|
rcor24Inv = 1 / rcor24;
|
|
|
|
|
|
|
|
bright = tanf((sampleRate * 0.5f - 10) * M_PI * sampleRateInv);
|
|
|
|
|
|
|
|
R = 1;
|
|
|
|
rcor = (480.0 / 44000) * rcrate;
|
|
|
|
rcorInv = 1 / rcor;
|
|
|
|
bandPassSw = false;
|
|
|
|
|
|
|
|
pCutoff = -1;
|
|
|
|
pReso = -1;
|
|
|
|
|
|
|
|
dc_r = 1.0 - (126.0 / sr);
|
|
|
|
dc_id = 0;
|
|
|
|
dc_od = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline float PluginFx::NR24(float sample, float g, float lpc) {
|
|
|
|
float ml = 1 / (1 + g);
|
|
|
|
float S = (lpc * (lpc * (lpc * s1 + s2) + s3) + s4) * ml;
|
|
|
|
float G = lpc * lpc * lpc * lpc;
|
|
|
|
float y = (sample - R24 * S) / (1 + R24 * G);
|
|
|
|
return y + 1e-8;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline float PluginFx::NR(float sample, float g) {
|
|
|
|
float y = ((sample - R * s1 * 2 - g * s1 - s2) / (1 + g * (2 * R + g))) + dc;
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PluginFx::process(float *work, int sampleSize) {
|
|
|
|
// very basic DC filter
|
|
|
|
float t_fd = work[0];
|
|
|
|
work[0] = work[0] - dc_id + dc_r * dc_od;
|
|
|
|
dc_id = t_fd;
|
|
|
|
for (int i = 1; i < sampleSize; i++) {
|
|
|
|
t_fd = work[i];
|
|
|
|
work[i] = work[i] - dc_id + dc_r * work[i - 1];
|
|
|
|
dc_id = t_fd;
|
|
|
|
|
|
|
|
}
|
|
|
|
dc_od = work[sampleSize - 1];
|
|
|
|
|
|
|
|
if ( Gain != 1 ) {
|
|
|
|
for (int i = 0; i < sampleSize; i++ )
|
|
|
|
work[i] *= Gain;
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't apply the LPF if the cutoff is to maximum
|
|
|
|
if ( Cutoff == 1 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( Cutoff != pCutoff || Reso != pReso ) {
|
|
|
|
rReso = (0.991 - logsc(1 - Reso, 0, 0.991));
|
|
|
|
R24 = 3.5 * rReso;
|
|
|
|
|
|
|
|
float cutoffNorm = logsc(Cutoff, 60, 19000);
|
|
|
|
rCutoff = (float)tanf(cutoffNorm * sampleRateInv * M_PI);
|
|
|
|
|
|
|
|
pCutoff = Cutoff;
|
|
|
|
pReso = Reso;
|
|
|
|
|
|
|
|
R = 1 - rReso;
|
|
|
|
}
|
|
|
|
|
|
|
|
// THIS IS MY FAVORITE 4POLE OBXd filter
|
|
|
|
|
|
|
|
// maybe smooth this value
|
|
|
|
float g = rCutoff;
|
|
|
|
float lpc = g / (1 + g);
|
|
|
|
|
|
|
|
for (int i = 0; i < sampleSize; i++ ) {
|
|
|
|
float s = work[i];
|
|
|
|
s = s - 0.45 * tptlpupw(c, s, 15, sampleRateInv);
|
|
|
|
s = tptpc(d, s, bright);
|
|
|
|
|
|
|
|
float y0 = NR24(s, g, lpc);
|
|
|
|
|
|
|
|
//first low pass in cascade
|
|
|
|
float v = (y0 - s1) * lpc;
|
|
|
|
float res = v + s1;
|
|
|
|
s1 = res + v;
|
|
|
|
|
|
|
|
//damping
|
|
|
|
s1 = atanf(s1 * rcor24) * rcor24Inv;
|
|
|
|
float y1 = res;
|
|
|
|
float y2 = tptpc(s2, y1, g);
|
|
|
|
float y3 = tptpc(s3, y2, g);
|
|
|
|
float y4 = tptpc(s4, y3, g);
|
|
|
|
float mc = 0.0;
|
|
|
|
|
|
|
|
switch (mmch) {
|
|
|
|
case 0:
|
|
|
|
mc = ((1 - mmt) * y4 + (mmt) * y3);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
mc = ((1 - mmt) * y3 + (mmt) * y2);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mc = ((1 - mmt) * y2 + (mmt) * y1);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
mc = y1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//half volume comp
|
|
|
|
work[i] = mc * (1 + R24 * 0.45);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
// THIS IS THE 2POLE FILTER
|
|
|
|
|
|
|
|
for(int i=0; i < sampleSize; i++ ) {
|
|
|
|
float s = work[i];
|
|
|
|
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
|
|
|
|
s = tptpc(d,s,bright);
|
|
|
|
|
|
|
|
//float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
|
|
|
|
float v = NR(s,g);
|
|
|
|
float y1 = v*g + s1;
|
|
|
|
//damping
|
|
|
|
s1 = atanf(s1 * rcor) * rcorInv;
|
|
|
|
|
|
|
|
float y2 = y1*g + s2;
|
|
|
|
s2 = y2 + y1*g;
|
|
|
|
|
|
|
|
float mc;
|
|
|
|
if(!bandPassSw)
|
|
|
|
mc = (1-mm)*y2 + (mm)*v;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
mc =2 * ( mm < 0.5 ?
|
|
|
|
((0.5 - mm) * y2 + (mm) * y1):
|
|
|
|
((1-mm) * y1 + (mm-0.5) * v)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
work[i] = mc;
|
|
|
|
}
|
|
|
|
|
|
|
|
*/
|