crap/crap/level.hpp

190 lines
3.7 KiB
C++

#include <string.h>
#include <math.h>
#include "util.hpp"
#include "Param.hpp"
#include "Crap.hpp"
#include "Buffer2.hpp"
#include "biquad.hpp"
#define DELAY 1
static ulong global_delay = 0;
TEMPLATE
struct Delay {
static const ulong size = 4096;
// needs to be twice the size for a memcpy trick later
T buf[size*2];
int length, pos;
inline void
setup(int newlen)
{
pos = 0;
length = newlen;
for (int i = 0; i < size*2; i++)
buf[i] = T(0);
};
inline T
delay(const T &s)
{
pos--;
if (pos <= 0) {
memcpy(buf + size, buf, size*sizeof(T));
pos = size;
}
buf[pos] = s;
return buf[pos + length];
};
inline T &
operator[](int index) {
return buf[pos + index];
}
inline const T &
operator[](int index) const {
return buf[pos + index];
}
};
struct Crap_level
:public AdjustAll<Buffer2<Crap>> {
static const ulong id = 0xAAAAAAAA;
static const char *label;
static const char *name;
static const char *author;
static const char *copyright;
static const ulong bands = 2;
static const ulong parameters = 0;
v2df sc[BLOCK_SIZE]; // sidechain
biquad filters_L[bands];
biquad filters_R[bands];
ulong window_size;
ulong lookahead;
double *window, window_sum;
double env, attack, release;
Delay<v2df> delay;
Delay<double> window_delay;
Crap_level()
{
window = NULL;
};
virtual
~Crap_level()
{
if (window)
delete window;
}
inline void
process2(v2df *buf, ulong rem)
{
biquad *f0, *f1;
f0 = filters_L;
f1 = filters_R;
for (ulong i = 0; i < rem; i++)
sc[i] = buf[i];
for (ulong i = 0; i < bands; i++) {
biquad_run_block_stereo(f0, f1, sc, rem);
f0++;
f1++;
}
double envs[BLOCK_SIZE];
for (ulong i = 0; i < rem; i++)
envs[i] = fabs(sc[i][0]) + fabs(sc[i][1]);
for (ulong i = 0; i < rem; i++)
envs[i] *= 0.5;
// FIR
for (ulong i = 0; i < rem; i++) {
window_delay.delay(envs[i]);
double sum = 0;
for (ulong j = 0; j < window_size; j++)
sum += window[j]*window_delay[j];
envs[i] = sum/window_sum*2;
}
// Follower
for (ulong i = 0; i < rem; i++) {
env += (envs[i] - env)*(env < envs[i] ? attack : release);
env = fmax(0.00001, env);
envs[i] = env;
}
double gains[BLOCK_SIZE];
for (ulong i = 0; i < rem; i++)
gains[i] = 0.3991 - 0.01769/(envs[i] + 0.044);
for (ulong i = 0; i < rem; i++)
gains[i] = fmax(0, gains[i]);
for (ulong i = 0; i < rem; i++)
gains[i] /= envs[i];
for (ulong i = 0; i < rem; i++) {
v2df gain = v2df(gains[i]);
buf[i] = delay.delay(buf[i])*gain;
}
}
inline void
pause()
{}
inline void
resume()
{
for (int i = 0; i < bands; i++) {
biquad_init(&filters_L[i]);
biquad_init(&filters_R[i]);
}
env = 0;
delay.setup(lookahead);
window_delay.setup(window_size);
}
static inline void
construct_params(Param *params)
{}
void
adjust_all(Param *params)
{
biquad *f = filters_L;
f[ 0] = biquad_gen(FILT_PEAKING, 50.0, -10, 4.00, fs);
f[ 1] = biquad_gen(FILT_PEAKING, 5000, 5, 4.00, fs);
for (int i = 0; i < bands; i++)
filters_R[i] = filters_L[i];
double window_length = fs*0.010/0.60;
window_size = (ulong) round(window_length);
lookahead = (ulong) round(window_length*0.6);
global_delay = lookahead;
if (window)
delete window;
window = new double[window_size];
window_sum = 0;
for (ulong i = 0; i < window_size; i++) {
double x = double(i)/window_size;
double y = -(x - 0)*(x - 1)*(x + 0.6)/0.288;
window[i] = y;
window_sum += y;
}
attack = 1 - exp(-1/(fs*0.002));
release = 1 - exp(-1/(fs*0.050));
resume();
}
};
const char *Crap_level::label = "crap_level";
const char *Crap_level::name = "crap Leveller";
const char *Crap_level::author = "Connor Olding";
const char *Crap_level::copyright = "MIT";