diff --git a/crap/tube.h b/crap/tube.h index 17264a4..957b16d 100644 --- a/crap/tube.h +++ b/crap/tube.h @@ -1,22 +1,50 @@ #include +#include #include "util.h" +#include "param.h" #define ID 0x50F7BA11 #define LABEL "crap_tube" #define NAME "crap Tube Distortion" #define AUTHOR "Connor Olding" #define COPYRIGHT "MIT" -#define PARAMETERS 0 +#define PARAMETERS 2 #define HIST_SIZE 36 #define HIST_SIZE_2 18 +typedef struct { + double desired, actual, speed; + int log; // use multiplication instead of addition for speed +} smoothval; + typedef struct { double history_L[HIST_SIZE]; double history_R[HIST_SIZE]; + smoothval drive, wet; } personal; +static double +smooth(smoothval *val) +{ + double a = val->actual; + double d = val->desired; + double s = val->speed; + double l = val->log; + if (a < d) { + if (l) a *= s; + else a += s; + if (a > d) a = d; + } else if (a > d) { + if (l) a /= s; + else a -= s; + if (a < d) a = d; + } + val->actual = a; + return a; +} + static double distort(double x) { @@ -39,6 +67,8 @@ static double upsample(double h[HIST_SIZE_2], double x) { double y; + // -3 at 18600/44100/2, -96 stopband + // designed with LOWPASS(0, +0.71327159,+0.00688573,-0.45391337,+0.88734229); LOWPASS(1, +0.63347126,+0.05572752,-0.36946634,+0.69213639); LOWPASS(2, +0.55963645,+0.13990391,-0.26487901,+0.52405582); @@ -55,6 +85,8 @@ static double downsample(double h[HIST_SIZE_2], double x) { double y; + // -3 at 17544/44100/4, -96 stopband + // same idea as upsample() LOWPASS(0, +0.62136966,-0.87573986,-1.56336581,+0.93036527); LOWPASS(1, +0.56540370,-0.77393348,-1.44258778,+0.79946170); LOWPASS(2, +0.49824084,-0.63630306,-1.31114921,+0.67132784); @@ -68,14 +100,28 @@ downsample(double h[HIST_SIZE_2], double x) } static double -process_one(double h[HIST_SIZE], double x) +process_one(double x, double drive, double wet) { + return (distort(x*drive)/drive*0.79 - x)*wet + x; +} + +static double +oversample(personal *data, double x, int right) +{ + double *h0 = (!right) ? data->history_L : data->history_R; + double *h1 = h0 + HIST_SIZE_2; double y; - y = downsample(h + HIST_SIZE_2, distort(4*upsample(h, x))); - downsample(h + HIST_SIZE_2, distort(4*upsample(h, 0))); - downsample(h + HIST_SIZE_2, distort(4*upsample(h, 0))); - downsample(h + HIST_SIZE_2, distort(4*upsample(h, 0))); - return y*0.71; + + #define doit(SAMP) \ + downsample(h1, process_one(4*upsample(h0, SAMP), \ + smooth(&data->drive), smooth(&data->wet))) + y = doit(x); + doit(0); + doit(0); + doit(0); + #undef doit + + return y; } static void @@ -86,8 +132,8 @@ process(personal *data, { disable_denormals(); for (unsigned long pos = 0; pos < count; pos++) { - out_L[pos] = process_one(data->history_L, in_L[pos]); - out_R[pos] = process_one(data->history_R, in_R[pos]); + out_L[pos] = oversample(data, in_L[pos], 0); + out_R[pos] = oversample(data, in_R[pos], 1); } } @@ -99,8 +145,8 @@ process_double(personal *data, { disable_denormals(); for (unsigned long pos = 0; pos < count; pos++) { - out_L[pos] = process_one(data->history_L, in_L[pos]); - out_R[pos] = process_one(data->history_R, in_R[pos]); + out_L[pos] = oversample(data, in_L[pos], 0); + out_R[pos] = oversample(data, in_R[pos], 1); } } @@ -118,14 +164,50 @@ pause(personal *data) static void construct(personal *data) { - resume(data); + memset(data, 0, sizeof(personal)); } + +static void +construct_params(param *params) +{ + sprintf(params[0].name, "Drive"); + params[0].min = -30; + params[0].max = 15; + params[0].scale = SCALE_DB; + params[0].def = DEFAULT_0; + + sprintf(params[1].name, "Wetness"); + params[1].min = 0; + params[1].max = 1; + params[1].scale = SCALE_FLOAT; + params[1].def = DEFAULT_1; + + param_reset(¶ms[0]); + param_reset(¶ms[1]); +} + static void destruct(personal *data) {} static void -adjust(personal *data, unsigned long fs) +adjust(personal *data, param *params, unsigned long fs_long) { resume(data); + double fs = fs_long; + data->drive.desired = DB2LIN(params[0].value); + data->wet.desired = params[1].value; + data->drive.actual = data->drive.desired; + data->wet.actual = data->wet.desired; + data->drive.speed = 1 + 20/fs/4; + data->wet.speed = 20/fs/4; + data->drive.log = 1; + data->wet.log = 0; +} + +static void +adjust_one(personal *data, param *params, unsigned int index) +{ + data->drive.desired = DB2LIN(params[0].value); + data->wet.desired = params[1].value; }