add early prototype of leveller
This commit is contained in:
parent
522b45a7f8
commit
f5758537c7
3 changed files with 192 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ FULLNAME = $(DISTNAME)-$(VERSION)
|
||||||
BIN ?= ./bin
|
BIN ?= ./bin
|
||||||
VST_SDK_DIR ?= .
|
VST_SDK_DIR ?= .
|
||||||
|
|
||||||
BOTH = eq eq_const eq_const_T420 eq_const_T420_svf mugi4 noise tube
|
BOTH = eq eq_const eq_const_T420 eq_const_T420_svf mugi4 noise tube level
|
||||||
LADSPA = $(BOTH)
|
LADSPA = $(BOTH)
|
||||||
VST = $(BOTH) delay_test
|
VST = $(BOTH) delay_test
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ crap T420 Speaker Compensation | crap\_eq\_const\_T420 | `0x0DEFAE91` | lenovo t
|
||||||
crap T420 Speaker Compensation (SVF) | crap\_eq\_const\_T420\_svf | `0x0DEFB3CA` | trying out State Variable Filters (SVFs)
|
crap T420 Speaker Compensation (SVF) | crap\_eq\_const\_T420\_svf | `0x0DEFB3CA` | trying out State Variable Filters (SVFs)
|
||||||
crap mugi4 (moog-like) | crap\_mugi4 | `0xD8D0D8D0` | nonlinear moog filter implementation: [see reference][moog]
|
crap mugi4 (moog-like) | crap\_mugi4 | `0xD8D0D8D0` | nonlinear moog filter implementation: [see reference][moog]
|
||||||
crap Tube Distortion | crap\_tube | `0x50F7BA11` | static waveshaper with 6x oversampling and parameter smoothing. doesn't actually emulate a tube. not actually for crapping in.
|
crap Tube Distortion | crap\_tube | `0x50F7BA11` | static waveshaper with 6x oversampling and parameter smoothing. doesn't actually emulate a tube. not actually for crapping in.
|
||||||
|
crap Leveller | crap\_level | `0xAAAAAAAA` | an early prototype of a heavy leveller.
|
||||||
|
|
||||||
[moog]: https://aaltodoc.aalto.fi/bitstream/handle/123456789/14420/article6.pdf
|
[moog]: https://aaltodoc.aalto.fi/bitstream/handle/123456789/14420/article6.pdf
|
||||||
|
|
||||||
|
|
190
crap/level.hpp
Normal file
190
crap/level.hpp
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
#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 constexpr 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(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 constexpr ulong id = 0xAAAAAAAA;
|
||||||
|
static constexpr char label[] = "crap_level";
|
||||||
|
static constexpr char name[] = "crap Leveller";
|
||||||
|
static constexpr char author[] = "Connor Olding";
|
||||||
|
static constexpr char copyright[] = "MIT";
|
||||||
|
|
||||||
|
static constexpr ulong bands = 2;
|
||||||
|
static constexpr ulong parameters = 0;
|
||||||
|
|
||||||
|
v2df sc[BLOCK_SIZE]; // sidechain
|
||||||
|
biquad filters_L[bands];
|
||||||
|
biquad filters_R[bands];
|
||||||
|
ulong window_size;
|
||||||
|
ulong lookahead;
|
||||||
|
double *window;
|
||||||
|
double env, attack, release;
|
||||||
|
Delay<v2df> delay;
|
||||||
|
Delay<double> window_delay;
|
||||||
|
|
||||||
|
Crap_level()
|
||||||
|
{
|
||||||
|
window = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~Crap_level()
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
free(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
process2(v2df *buf, ulong rem)
|
||||||
|
{
|
||||||
|
biquad *f0, *f1;
|
||||||
|
f0 = filters_L;
|
||||||
|
f1 = filters_R;
|
||||||
|
memcpy(sc, buf, rem*sizeof(v2df));
|
||||||
|
for (ulong i = 0; i < bands; i++) {
|
||||||
|
biquad_run_block_stereo(f0, f1, sc, rem);
|
||||||
|
f0++;
|
||||||
|
f1++;
|
||||||
|
}
|
||||||
|
double envs[rem];
|
||||||
|
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;
|
||||||
|
|
||||||
|
// MaxFIR
|
||||||
|
double applied[window_size];
|
||||||
|
for (ulong i = 0; i < rem; i++) {
|
||||||
|
window_delay.delay(envs[i]);
|
||||||
|
for (ulong j = 0; j < window_size; j++)
|
||||||
|
applied[j] = window[j]*window_delay[j];
|
||||||
|
double max_ = 0;
|
||||||
|
for (ulong j = 0; j < window_size; j++)
|
||||||
|
max_ = fmax(max_, applied[j]);
|
||||||
|
envs[i] = max_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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[rem];
|
||||||
|
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)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual 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 = round(window_length);
|
||||||
|
lookahead = round(window_length*0.6);
|
||||||
|
global_delay = lookahead;
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
free(window);
|
||||||
|
window = (double *) calloc(window_size, sizeof(double));
|
||||||
|
|
||||||
|
for (int 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
attack = 1 - exp(-1/(fs*0.002));
|
||||||
|
release = 1 - exp(-1/(fs*0.050));
|
||||||
|
|
||||||
|
resume();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr char Crap_level::label[];
|
||||||
|
constexpr char Crap_level::name[];
|
||||||
|
constexpr char Crap_level::author[];
|
||||||
|
constexpr char Crap_level::copyright[];
|
Loading…
Add table
Reference in a new issue