add split eq
This commit is contained in:
538
filter/spliteq.h
Normal file
538
filter/spliteq.h
Normal file
@@ -0,0 +1,538 @@
|
||||
#pragma once
|
||||
#include "audio_math.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace trnr {
|
||||
|
||||
// Filter type enum
|
||||
enum filter_type {
|
||||
LOWPASS = 0,
|
||||
HIGHPASS = 1
|
||||
};
|
||||
|
||||
struct cascade_filter {
|
||||
filter_type type;
|
||||
int stages; // Number of cascaded stages
|
||||
double cutoff; // Cutoff frequency (Hz)
|
||||
double samplerate; // Sample rate (Hz)
|
||||
double alpha; // Filter coefficient
|
||||
std::vector<double> state; // State per stage
|
||||
};
|
||||
|
||||
inline void cascade_filter_setup(cascade_filter& f, filter_type _type, int _stages, double _cutoff, double _samplerate)
|
||||
{
|
||||
f.type = _type;
|
||||
f.stages = _stages;
|
||||
f.cutoff = _cutoff;
|
||||
f.samplerate = _samplerate;
|
||||
|
||||
// alpha = iirAmount = exp(-2 * pi * cutoff / samplerate);
|
||||
double x = exp(-2.0 * M_PI * f.cutoff / f.samplerate);
|
||||
f.alpha = 1.0 - x;
|
||||
|
||||
f.state.resize(f.stages, 0.0);
|
||||
}
|
||||
|
||||
// Process one sample
|
||||
inline double cascade_filter_process(cascade_filter& f, double input)
|
||||
{
|
||||
double out = input;
|
||||
for (int i = 0; i < f.stages; ++i) {
|
||||
if (f.type == LOWPASS) {
|
||||
f.state[i] = (f.state[i] * (1.0 - f.alpha)) + (out * f.alpha);
|
||||
out = f.state[i];
|
||||
} else { // CASCADE_HIGHPASS
|
||||
f.state[i] = (f.state[i] * (1.0 - f.alpha)) + (out * f.alpha);
|
||||
out -= f.state[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// 2nd order Butterworth biquad filter
|
||||
struct butterworth {
|
||||
filter_type type;
|
||||
double cutoff;
|
||||
double a1, a2;
|
||||
double b0, b1, b2;
|
||||
double x1, x2; // previous inputs
|
||||
double y1, y2; // previous outputs
|
||||
};
|
||||
|
||||
// Biquad coefficient calculation
|
||||
inline void butterworth_biquad_coeffs(butterworth& b, double samplerate)
|
||||
{
|
||||
double omega = 2.0 * M_PI * b.cutoff / samplerate;
|
||||
double sin_omega = sin(omega);
|
||||
double cos_omega = cos(omega);
|
||||
|
||||
double Q = 1.0 / sqrt(2.0); // Butterworth Q for 2nd order
|
||||
double alpha = sin_omega / (2.0 * Q);
|
||||
double a0 = 1.0 + alpha;
|
||||
|
||||
switch (b.type) {
|
||||
case LOWPASS:
|
||||
b.b0 = (1.0 - cos_omega) / 2.0 / a0;
|
||||
b.b1 = (1.0 - cos_omega) / a0;
|
||||
b.b2 = (1.0 - cos_omega) / 2.0 / a0;
|
||||
b.a1 = -2.0 * cos_omega / a0;
|
||||
b.a2 = (1.0 - alpha) / a0;
|
||||
break;
|
||||
case HIGHPASS:
|
||||
b.b0 = (1.0 + cos_omega) / 2.0 / a0;
|
||||
b.b1 = -(1.0 + cos_omega) / a0;
|
||||
b.b2 = (1.0 + cos_omega) / 2.0 / a0;
|
||||
b.a1 = -2.0 * cos_omega / a0;
|
||||
b.a2 = (1.0 - alpha) / a0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Biquad sample processing
|
||||
inline double butterworth_biquad_process(butterworth& b, double input)
|
||||
{
|
||||
double y = b.b0 * input + b.b1 * b.x1 + b.b2 * b.x2 - b.a1 * b.y1 - b.a2 * b.y2;
|
||||
b.x2 = b.x1;
|
||||
b.x1 = input;
|
||||
b.y2 = b.y1;
|
||||
b.y1 = y;
|
||||
return y;
|
||||
}
|
||||
|
||||
struct aw_filter {
|
||||
filter_type type;
|
||||
float amount;
|
||||
bool flip;
|
||||
double sampleLAA;
|
||||
double sampleLAB;
|
||||
double sampleLBA;
|
||||
double sampleLBB;
|
||||
double sampleLCA;
|
||||
double sampleLCB;
|
||||
double sampleLDA;
|
||||
double sampleLDB;
|
||||
double sampleLE;
|
||||
double sampleLF;
|
||||
double sampleLG;
|
||||
double samplerate;
|
||||
};
|
||||
|
||||
inline void aw_filter_init(aw_filter& f, filter_type type, float amount, double samplerate)
|
||||
{
|
||||
f.type = type;
|
||||
f.amount = amount;
|
||||
f.samplerate = samplerate;
|
||||
|
||||
f.sampleLAA = 0.0;
|
||||
f.sampleLAB = 0.0;
|
||||
f.sampleLBA = 0.0;
|
||||
f.sampleLBB = 0.0;
|
||||
f.sampleLCA = 0.0;
|
||||
f.sampleLCB = 0.0;
|
||||
f.sampleLDA = 0.0;
|
||||
f.sampleLDB = 0.0;
|
||||
f.sampleLE = 0.0;
|
||||
f.sampleLF = 0.0;
|
||||
f.sampleLG = 0.0;
|
||||
|
||||
f.flip = false;
|
||||
}
|
||||
|
||||
inline void aw_filter_process_block(aw_filter& f, float* audio, int frames)
|
||||
{
|
||||
double overallscale = 1.0;
|
||||
overallscale /= 44100.0;
|
||||
double compscale = overallscale;
|
||||
overallscale = f.samplerate;
|
||||
compscale = compscale * overallscale;
|
||||
bool engage = false;
|
||||
|
||||
double iir_amt = 0.0;
|
||||
|
||||
if (f.type == LOWPASS) {
|
||||
iir_amt = (((f.amount * f.amount * 15.0) + 1.0) * 0.0188) + 0.7;
|
||||
if (iir_amt > 1.0) iir_amt = 1.0;
|
||||
if (((f.amount * f.amount * 15.0) + 1.0) < 15.99) engage = true;
|
||||
} else if (f.type == HIGHPASS) {
|
||||
iir_amt = (((f.amount * f.amount * 1570.0) + 30.0) * 1.0) / overallscale;
|
||||
if (((f.amount * f.amount * 1570.0) + 30.0) > 30.01) engage = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < frames; i++) {
|
||||
float input = audio[i];
|
||||
f.flip = !f.flip;
|
||||
|
||||
if (engage) {
|
||||
switch (f.type) {
|
||||
case LOWPASS:
|
||||
if (f.flip) {
|
||||
f.sampleLAA = (f.sampleLAA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLAA;
|
||||
f.sampleLBA = (f.sampleLBA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLBA;
|
||||
f.sampleLCA = (f.sampleLCA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLCA;
|
||||
f.sampleLDA = (f.sampleLDA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLDA;
|
||||
f.sampleLE = (f.sampleLE * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLE;
|
||||
} else {
|
||||
f.sampleLAB = (f.sampleLAB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLAB;
|
||||
f.sampleLBB = (f.sampleLBB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLBB;
|
||||
f.sampleLCB = (f.sampleLCB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLCB;
|
||||
f.sampleLDB = (f.sampleLDB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLDB;
|
||||
f.sampleLF = (f.sampleLF * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = f.sampleLF;
|
||||
}
|
||||
f.sampleLG = (f.sampleLG * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input = (f.sampleLG * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
break;
|
||||
case HIGHPASS:
|
||||
if (f.flip) {
|
||||
f.sampleLAA = (f.sampleLAA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLAA;
|
||||
f.sampleLBA = (f.sampleLBA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLBA;
|
||||
f.sampleLCA = (f.sampleLCA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLCA;
|
||||
f.sampleLDA = (f.sampleLDA * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLDA;
|
||||
} else {
|
||||
f.sampleLAB = (f.sampleLAB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLAB;
|
||||
f.sampleLBB = (f.sampleLBB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLBB;
|
||||
f.sampleLCB = (f.sampleLCB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLCB;
|
||||
f.sampleLDB = (f.sampleLDB * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLDB;
|
||||
}
|
||||
f.sampleLE = (f.sampleLE * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLE;
|
||||
f.sampleLF = (f.sampleLF * (1.0 - iir_amt)) + (input * iir_amt);
|
||||
input -= f.sampleLF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
audio[i] = input;
|
||||
}
|
||||
}
|
||||
|
||||
struct spliteq {
|
||||
aw_filter lp_l, lp_r, hp_l, hp_r; // lowpass and highpass filters
|
||||
|
||||
// cascaded filters
|
||||
cascade_filter bass_l, bass_r;
|
||||
cascade_filter treble_l, treble_r;
|
||||
|
||||
// butterworth biquads
|
||||
butterworth bass1_l, bass2_l, bass1_r, bass2_r;
|
||||
// Mid: two cascaded highpass THEN two cascaded lowpass per channel
|
||||
butterworth mid_hp1_l, mid_hp2_l, mid_lp1_l, mid_lp2_l;
|
||||
butterworth mid_hp1_r, mid_hp2_r, mid_lp1_r, mid_lp2_r;
|
||||
// Treble: two cascaded highpass filters per channel
|
||||
butterworth treble1_l, treble2_l, treble1_r, treble2_r;
|
||||
|
||||
double low_mid_crossover = 150.0; // Hz
|
||||
double mid_high_crossover = 1700.0; // Hz
|
||||
|
||||
// adjusted crossover frequencies for cascade filters
|
||||
double low_mid_crossover_adj = 150.0;
|
||||
double mid_high_crossover_adj = 1700.0;
|
||||
|
||||
double samplerate = 48000.0;
|
||||
|
||||
float bass_gain = 1.0f;
|
||||
float mid_gain = 1.0f;
|
||||
float treble_gain = 1.0f;
|
||||
|
||||
// adjusted gain for cascade filters
|
||||
float bass_gain_adj = 1.0f;
|
||||
float mid_gain_adj = 1.0f;
|
||||
float treble_gain_adj = 1.0f;
|
||||
|
||||
bool linkwitz_riley_enabled = false;
|
||||
};
|
||||
|
||||
inline void spliteq_init(spliteq& eq, double samplerate, double low_mid_crossover, double mid_high_crossover)
|
||||
{
|
||||
low_mid_crossover /= 2.0;
|
||||
mid_high_crossover /= 2.0;
|
||||
|
||||
eq.samplerate = samplerate;
|
||||
|
||||
eq.low_mid_crossover = low_mid_crossover;
|
||||
eq.mid_high_crossover = mid_high_crossover;
|
||||
eq.low_mid_crossover_adj = low_mid_crossover;
|
||||
eq.mid_high_crossover_adj = mid_high_crossover;
|
||||
|
||||
// initialize lp/hp filters
|
||||
aw_filter_init(eq.lp_l, LOWPASS, 1.0f, samplerate);
|
||||
aw_filter_init(eq.lp_r, LOWPASS, 1.0f, samplerate);
|
||||
aw_filter_init(eq.hp_l, HIGHPASS, 0.0f, samplerate);
|
||||
aw_filter_init(eq.hp_r, HIGHPASS, 0.0f, samplerate);
|
||||
|
||||
// init cascade filters
|
||||
cascade_filter_setup(eq.bass_l, LOWPASS, 2, low_mid_crossover, samplerate);
|
||||
cascade_filter_setup(eq.bass_r, LOWPASS, 2, low_mid_crossover, samplerate);
|
||||
cascade_filter_setup(eq.treble_l, HIGHPASS, 2, mid_high_crossover, samplerate);
|
||||
cascade_filter_setup(eq.treble_r, HIGHPASS, 2, mid_high_crossover, samplerate);
|
||||
|
||||
// init butterworth filters
|
||||
// bass filters
|
||||
eq.bass1_l.type = LOWPASS;
|
||||
eq.bass1_l.cutoff = low_mid_crossover;
|
||||
eq.bass1_l.x1 = eq.bass1_l.x2 = eq.bass1_l.y1 = eq.bass1_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.bass1_l, samplerate);
|
||||
|
||||
eq.bass2_l.type = LOWPASS;
|
||||
eq.bass2_l.cutoff = low_mid_crossover;
|
||||
eq.bass2_l.x1 = eq.bass2_l.x2 = eq.bass2_l.y1 = eq.bass2_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.bass2_l, samplerate);
|
||||
|
||||
eq.bass1_r.type = LOWPASS;
|
||||
eq.bass1_r.cutoff = low_mid_crossover;
|
||||
eq.bass1_r.x1 = eq.bass1_r.x2 = eq.bass1_r.y1 = eq.bass1_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.bass1_r, samplerate);
|
||||
|
||||
eq.bass2_r.type = LOWPASS;
|
||||
eq.bass2_r.cutoff = low_mid_crossover;
|
||||
eq.bass2_r.x1 = eq.bass2_r.x2 = eq.bass2_r.y1 = eq.bass2_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.bass2_r, samplerate);
|
||||
|
||||
// mid filters (HPF x2, then LPF x2)
|
||||
eq.mid_hp1_l.type = HIGHPASS;
|
||||
eq.mid_hp1_l.cutoff = low_mid_crossover;
|
||||
eq.mid_hp1_l.x1 = eq.mid_hp1_l.x2 = eq.mid_hp1_l.y1 = eq.mid_hp1_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_hp1_l, samplerate);
|
||||
|
||||
eq.mid_hp2_l.type = HIGHPASS;
|
||||
eq.mid_hp2_l.cutoff = low_mid_crossover;
|
||||
eq.mid_hp2_l.x1 = eq.mid_hp2_l.x2 = eq.mid_hp2_l.y1 = eq.mid_hp2_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_hp2_l, samplerate);
|
||||
|
||||
eq.mid_lp1_l.type = LOWPASS;
|
||||
eq.mid_lp1_l.cutoff = mid_high_crossover;
|
||||
eq.mid_lp1_l.x1 = eq.mid_lp1_l.x2 = eq.mid_lp1_l.y1 = eq.mid_lp1_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_lp1_l, samplerate);
|
||||
|
||||
eq.mid_lp2_l.type = LOWPASS;
|
||||
eq.mid_lp2_l.cutoff = mid_high_crossover;
|
||||
eq.mid_lp2_l.x1 = eq.mid_lp2_l.x2 = eq.mid_lp2_l.y1 = eq.mid_lp2_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_lp2_l, samplerate);
|
||||
|
||||
eq.mid_hp1_r.type = HIGHPASS;
|
||||
eq.mid_hp1_r.cutoff = low_mid_crossover;
|
||||
eq.mid_hp1_r.x1 = eq.mid_hp1_r.x2 = eq.mid_hp1_r.y1 = eq.mid_hp1_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_hp1_r, samplerate);
|
||||
|
||||
eq.mid_hp2_r.type = HIGHPASS;
|
||||
eq.mid_hp2_r.cutoff = low_mid_crossover;
|
||||
eq.mid_hp2_r.x1 = eq.mid_hp2_r.x2 = eq.mid_hp2_r.y1 = eq.mid_hp2_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_hp2_r, samplerate);
|
||||
|
||||
eq.mid_lp1_r.type = LOWPASS;
|
||||
eq.mid_lp1_r.cutoff = mid_high_crossover;
|
||||
eq.mid_lp1_r.x1 = eq.mid_lp1_r.x2 = eq.mid_lp1_r.y1 = eq.mid_lp1_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_lp1_r, samplerate);
|
||||
|
||||
eq.mid_lp2_r.type = LOWPASS;
|
||||
eq.mid_lp2_r.cutoff = mid_high_crossover;
|
||||
eq.mid_lp2_r.x1 = eq.mid_lp2_r.x2 = eq.mid_lp2_r.y1 = eq.mid_lp2_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.mid_lp2_r, samplerate);
|
||||
|
||||
// treble filters
|
||||
eq.treble1_l.type = HIGHPASS;
|
||||
eq.treble1_l.cutoff = mid_high_crossover;
|
||||
eq.treble1_l.x1 = eq.treble1_l.x2 = eq.treble1_l.y1 = eq.treble1_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.treble1_l, samplerate);
|
||||
|
||||
eq.treble2_l.type = HIGHPASS;
|
||||
eq.treble2_l.cutoff = mid_high_crossover;
|
||||
eq.treble2_l.x1 = eq.treble2_l.x2 = eq.treble2_l.y1 = eq.treble2_l.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.treble2_l, samplerate);
|
||||
|
||||
eq.treble1_r.type = HIGHPASS;
|
||||
eq.treble1_r.cutoff = mid_high_crossover;
|
||||
eq.treble1_r.x1 = eq.treble1_r.x2 = eq.treble1_r.y1 = eq.treble1_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.treble1_r, samplerate);
|
||||
|
||||
eq.treble2_r.type = HIGHPASS;
|
||||
eq.treble2_r.cutoff = mid_high_crossover;
|
||||
eq.treble2_r.x1 = eq.treble2_r.x2 = eq.treble2_r.y1 = eq.treble2_r.y2 = 0.0;
|
||||
butterworth_biquad_coeffs(eq.treble2_r, samplerate);
|
||||
}
|
||||
|
||||
// Process block (stereo)
|
||||
inline void spliteq_process_block(spliteq& eq, float** audio, int frames)
|
||||
{
|
||||
aw_filter_process_block(eq.hp_l, audio[0], frames);
|
||||
aw_filter_process_block(eq.hp_r, audio[1], frames);
|
||||
|
||||
for (int i = 0; i < frames; i++) {
|
||||
if (eq.linkwitz_riley_enabled) {
|
||||
// butterwort/linkwitz-riley
|
||||
|
||||
// Left channel
|
||||
double input_l = audio[0][i];
|
||||
// Bass
|
||||
double bass_l = butterworth_biquad_process(eq.bass1_l, input_l);
|
||||
bass_l = butterworth_biquad_process(eq.bass2_l, bass_l);
|
||||
// Mid
|
||||
double mid_l = butterworth_biquad_process(eq.mid_hp1_l, input_l);
|
||||
mid_l = butterworth_biquad_process(eq.mid_hp2_l, mid_l);
|
||||
mid_l = butterworth_biquad_process(eq.mid_lp1_l, mid_l);
|
||||
mid_l = butterworth_biquad_process(eq.mid_lp2_l, mid_l);
|
||||
// Treble
|
||||
double treble_l = butterworth_biquad_process(eq.treble1_l, input_l);
|
||||
treble_l = butterworth_biquad_process(eq.treble2_l, treble_l);
|
||||
|
||||
// Apply gains
|
||||
bass_l *= eq.bass_gain;
|
||||
mid_l *= eq.mid_gain;
|
||||
treble_l *= eq.treble_gain;
|
||||
|
||||
// Sum bands
|
||||
audio[0][i] = bass_l + mid_l + treble_l;
|
||||
|
||||
// Right channel
|
||||
double input_r = audio[1][i];
|
||||
double bass_r = butterworth_biquad_process(eq.bass1_r, input_r);
|
||||
bass_r = butterworth_biquad_process(eq.bass2_r, bass_r);
|
||||
|
||||
double mid_r = butterworth_biquad_process(eq.mid_hp1_r, input_r);
|
||||
mid_r = butterworth_biquad_process(eq.mid_hp2_r, mid_r);
|
||||
mid_r = butterworth_biquad_process(eq.mid_lp1_r, mid_r);
|
||||
mid_r = butterworth_biquad_process(eq.mid_lp2_r, mid_r);
|
||||
|
||||
double treble_r = butterworth_biquad_process(eq.treble1_r, input_r);
|
||||
treble_r = butterworth_biquad_process(eq.treble2_r, treble_r);
|
||||
|
||||
bass_r *= eq.bass_gain;
|
||||
mid_r *= eq.mid_gain;
|
||||
treble_r *= eq.treble_gain;
|
||||
|
||||
audio[1][i] = bass_r + mid_r + treble_r;
|
||||
} else {
|
||||
// cascade/sum
|
||||
double input_l = audio[0][i];
|
||||
double input_r = audio[1][i];
|
||||
|
||||
double bass_l = cascade_filter_process(eq.bass_l, input_l);
|
||||
double bass_r = cascade_filter_process(eq.bass_r, input_r);
|
||||
|
||||
double treble_l = cascade_filter_process(eq.treble_l, input_l);
|
||||
double treble_r = cascade_filter_process(eq.treble_r, input_r);
|
||||
|
||||
double mid_l = input_l - bass_l - treble_l;
|
||||
double mid_r = input_r - bass_r - treble_r;
|
||||
|
||||
// Apply gains
|
||||
bass_l *= eq.bass_gain_adj;
|
||||
bass_r *= eq.bass_gain_adj;
|
||||
mid_l *= eq.mid_gain_adj;
|
||||
mid_r *= eq.mid_gain_adj;
|
||||
treble_l *= eq.treble_gain_adj;
|
||||
treble_r *= eq.treble_gain_adj;
|
||||
|
||||
// Sum bands
|
||||
audio[0][i] = bass_l + mid_l + treble_l;
|
||||
audio[1][i] = bass_r + mid_r + treble_r;
|
||||
}
|
||||
}
|
||||
|
||||
aw_filter_process_block(eq.lp_l, audio[0], frames);
|
||||
aw_filter_process_block(eq.lp_r, audio[1], frames);
|
||||
}
|
||||
|
||||
inline void spliteq_update(spliteq& eq, double hp_freq, double lp_freq, double low_mid_crossover,
|
||||
double mid_high_crossover, double bass_gain, double mid_gain, double treble_gain)
|
||||
{
|
||||
low_mid_crossover /= 2.0;
|
||||
mid_high_crossover /= 2.0;
|
||||
|
||||
eq.bass_gain = db_2_lin(bass_gain);
|
||||
eq.mid_gain = db_2_lin(mid_gain);
|
||||
eq.treble_gain = db_2_lin(treble_gain);
|
||||
|
||||
if (bass_gain > 0.f) {
|
||||
eq.bass_gain = eq.bass_gain_adj = db_2_lin(bass_gain * 0.85f);
|
||||
eq.low_mid_crossover_adj = low_mid_crossover;
|
||||
} else {
|
||||
eq.bass_gain_adj = db_2_lin(bass_gain);
|
||||
eq.low_mid_crossover_adj = low_mid_crossover * 2.0;
|
||||
}
|
||||
|
||||
if (mid_gain > 0.0f) eq.mid_gain_adj = db_2_lin(mid_gain * 0.85f);
|
||||
else eq.mid_gain_adj = db_2_lin(mid_gain * 0.74f);
|
||||
|
||||
if (treble_gain > 0.f) {
|
||||
eq.treble_gain_adj = db_2_lin(treble_gain * 1.1f);
|
||||
eq.mid_high_crossover_adj = mid_high_crossover;
|
||||
} else {
|
||||
eq.treble_gain_adj = db_2_lin(treble_gain);
|
||||
eq.mid_high_crossover_adj = mid_high_crossover / 2.0;
|
||||
}
|
||||
|
||||
eq.low_mid_crossover = low_mid_crossover;
|
||||
eq.mid_high_crossover = mid_high_crossover;
|
||||
|
||||
eq.hp_l.amount = hp_freq;
|
||||
eq.hp_r.amount = hp_freq;
|
||||
eq.lp_l.amount = lp_freq;
|
||||
eq.lp_r.amount = lp_freq;
|
||||
|
||||
cascade_filter_setup(eq.bass_l, LOWPASS, 2, eq.low_mid_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.bass_r, LOWPASS, 2, eq.low_mid_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_l, HIGHPASS, 2, eq.mid_high_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_r, HIGHPASS, 2, eq.mid_high_crossover_adj, eq.samplerate);
|
||||
|
||||
eq.bass1_l.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.bass1_l, eq.samplerate);
|
||||
eq.bass2_l.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.bass2_l, eq.samplerate);
|
||||
eq.bass1_r.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.bass1_r, eq.samplerate);
|
||||
eq.bass2_r.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.bass2_r, eq.samplerate);
|
||||
|
||||
eq.mid_hp1_l.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_hp1_l, eq.samplerate);
|
||||
eq.mid_hp2_l.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_hp2_l, eq.samplerate);
|
||||
eq.mid_lp1_l.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_lp1_l, eq.samplerate);
|
||||
eq.mid_lp2_l.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_lp2_l, eq.samplerate);
|
||||
|
||||
eq.mid_hp1_r.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_hp1_r, eq.samplerate);
|
||||
eq.mid_hp2_r.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_hp2_r, eq.samplerate);
|
||||
eq.mid_lp1_r.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_lp1_r, eq.samplerate);
|
||||
eq.mid_lp2_r.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.mid_lp2_r, eq.samplerate);
|
||||
|
||||
eq.treble1_l.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.treble1_l, eq.samplerate);
|
||||
eq.treble2_l.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.treble2_l, eq.samplerate);
|
||||
eq.treble1_r.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.treble1_r, eq.samplerate);
|
||||
eq.treble2_r.cutoff = mid_high_crossover;
|
||||
butterworth_biquad_coeffs(eq.treble2_r, eq.samplerate);
|
||||
}
|
||||
|
||||
inline void spliteq_update(spliteq& eq, double bass_gain, double mid_gain, double treble_gain)
|
||||
{
|
||||
trnr::spliteq_update(eq, eq.hp_l.amount, eq.lp_l.amount, eq.low_mid_crossover * 2.0, eq.mid_high_crossover * 2.0,
|
||||
bass_gain, mid_gain, treble_gain);
|
||||
}
|
||||
} // namespace trnr
|
||||
Reference in New Issue
Block a user