crap/crap/mugi4.hpp
2015-06-10 23:57:19 -07:00

203 lines
4.4 KiB
C++

/*
an implementation of:
S. D Angelo and V. Välimäki. Generalized Moog Ladder Filter: Part II
Explicit Nonlinear Model through a Novel Delay-Free Loop Implementation Method.
IEEE Trans. Audio, Speech, and Lang. Process.,
vol. 22, no. 12, pp. 1873 1883, December 2014.
https://aaltodoc.aalto.fi/bitstream/handle/123456789/14420/article6.pdf
*/
#include <stdio.h>
#include <string.h>
#include "util.hpp"
#include "Param.hpp"
#include "Crap.hpp"
#include "os2piir.hpp"
#define OVERSAMPLING 2
#define FULL_SIZE (BLOCK_SIZE*OVERSAMPLING)
#include "Buffer2OS2.hpp"
#define VT 0.026
#define N 4
#define VT2 T(2.*VT)
TEMPLATE INNER PURE T
tanh2(T x)
{
//return T(tanh(x[0]), tanh(x[1]));
T xx = x*x;
T a = ((xx + T(378))*xx + T(17325))*xx + T(135135);
T b = ((T(28)*xx + T(3150))*xx + T(62370))*xx + T(135135);
return x*a/b;
}
struct freqdata {
v2df g;
v2df p0;
v2df q0, q1, q2, q3;
v2df r1, r2, r3, r4;
v2df L_p0;
v2df L_q0;
v2df L_r1;
};
struct stage {
v2df sum, sumback, dout;
TEMPLATE inline T
process(freqdata fd, T in)
{
T temp = (in + sumback)*VT2*fd.L_p0*fd.g;
T out = temp + sum;
sum += T(2)*temp;
dout = tanh2<T>(out/VT2);
sumback = in*fd.L_r1 - dout*fd.L_q0;
return out;
}
};
struct mugi4 {
freqdata fd;
stage s1, s2, s3, s4;
v2df sumback1, sumback2, sumback3, sumback4;
v2df drive, feedback;
TEMPLATE inline T
process(T in)
{
in *= drive;
T sum = in + sumback1;
T pre = -fd.p0*sum;
s1.process<T>(fd, tanh2<T>(pre/VT2));
s2.process<T>(fd, s1.dout);
s3.process<T>(fd, s2.dout);
T out = s4.process<T>(fd, s3.dout);
T back = feedback*out;
sumback1 = fd.r1*in + fd.q0*back + sumback2;
sumback2 = fd.r2*in + fd.q1*back + sumback3;
sumback3 = fd.r3*in + fd.q2*back + sumback4;
sumback4 = fd.r4*in + fd.q3*back;
T compensate = -(feedback + T(1));
return out/drive*compensate;
}
inline void
setup(double wc, double drive_, double feedback_)
{
drive = v2df(drive_);
feedback = v2df(feedback_);
double k = feedback_;
double bc1 = -4; //-binomial(N, 1);
double bc2 = -6; //-binomial(N, 2);
double bc3 = -4; //-binomial(N, 3);
double bc4 = -1; //-binomial(N, 4);
// apparently fd_set is used by some stdio implementations, so
#define crap_fd_set(L, R) double L = R; fd.L = (v2df){L, L}
crap_fd_set(g, tan(wc));
double gg1 = g/(g + 1);
double gg1Nk = k*gg1*gg1*gg1*gg1;
double g1g1 = (g - 1)/(g + 1);
crap_fd_set(p0, 1/(1 + gg1Nk));
crap_fd_set(r1, bc1*gg1Nk);
crap_fd_set(r2, bc2*gg1Nk);
crap_fd_set(r3, bc3*gg1Nk);
crap_fd_set(r4, bc4*gg1Nk);
crap_fd_set(q0, r1 + bc1*g1g1);
crap_fd_set(q1, r2 + bc2*g1g1*g1g1);
crap_fd_set(q2, r3 + bc3*g1g1*g1g1*g1g1);
crap_fd_set(q3, r4 + bc4*g1g1*g1g1*g1g1*g1g1);
crap_fd_set(L_p0, 1/(1 + g));
crap_fd_set(L_q0, 1 - g);
crap_fd_set(L_r1, -g);
#undef crap_fd_set
}
};
struct Crap_mugi4
:public AdjustAll<Buffer2OS2<Crap>> {
static constexpr ulong id = 0xD8D0D8D0;
static constexpr char label[] = "crap_mugi4";
static constexpr char name[] = "crap mugi4 (moog-like)";
static constexpr char author[] = "Connor Olding";
static constexpr char copyright[] = "MIT";
static constexpr ulong parameters = 3;
mugi4 filter;
inline
Crap_mugi4()
{
memset(&filter, 0, sizeof(mugi4));
}
inline void
process2(v2df *buf, ulong rem)
{
for (ulong i = 0; i < rem; i++)
buf[i] = filter.process(buf[i]);
}
static inline void
construct_params(Param *params)
{
sprintf(params[0].name, "Frequency");
params[0].min = 20;
params[0].max = 20000;
params[0].scale = SCALE_HZ;
params[0].def = DEFAULT_MAX;
params[0].reset();
sprintf(params[1].name, "Drive");
params[1].min = -40;
params[1].max = 0;
params[1].scale = SCALE_DB;
params[1].def = DEFAULT_MIN;
params[1].reset();
sprintf(params[2].name, "Feedback");
params[2].min = 0;
params[2].max = 1;
params[2].scale = SCALE_FLOAT;
params[2].def = DEFAULT_MIN;
params[2].reset();
}
inline void
pause()
{}
inline void
resume()
{
memset(&hb_up, 0, sizeof(halfband_t<v2df>));
memset(&hb_down, 0, sizeof(halfband_t<v2df>));
}
inline void
adjust_all(Param *params)
{
double f = params[0].value;
if (f < 20) f = 20;
if (f > fs/6*OVERSAMPLING) f = fs/6*OVERSAMPLING;
double wc = M_PI*f/fs/OVERSAMPLING;
double drive = DB2LIN(params[1].value);
double feedback = params[2].value*N;
filter.setup(wc, drive, feedback);
}
};
constexpr char Crap_mugi4::label[];
constexpr char Crap_mugi4::name[];
constexpr char Crap_mugi4::author[];
constexpr char Crap_mugi4::copyright[];