Mesen/Utilities/orfanidis_eq.h
2017-04-15 13:54:47 -04:00

1171 lines
30 KiB
C++

#ifndef ORFANIDIS_EQ_H_
#define ORFANIDIS_EQ_H_
#include <math.h>
#include <vector>
using namespace std;
namespace orfanidis_eq {
//Eq data types.
typedef double eq_single_t;
typedef double eq_double_t;
//NOTE: the default float type usage
//can have shortage of precision
//Eq types
typedef enum
{
none,
butterworth,
chebyshev1,
chebyshev2
} filter_type;
static const char *get_eq_text(filter_type type) {
switch(type) {
case none:
return "not initialized";
case butterworth:
return "butterworth";
case chebyshev1:
return "chebyshev1";
case chebyshev2:
return "chebyshev2";
default:
return "none";
}
}
//Eq errors
typedef enum
{
no_error,
invalid_input_data_error,
processing_error
} eq_error_t;
//Constants
static const eq_double_t pi = 3.1415926535897932384626433832795;
static const unsigned int fo_section_order = 4;
//Default gains
static const int max_base_gain_db = 0;
static const int min_base_gain_db = -60;
static const int butterworth_band_gain_db = -3;
static const int chebyshev1_band_base_gain_db = -6;
static const int chebyshev2_band_base_gain_db = -40;
static const int eq_min_max_gain_db = 46;
//Default freq's
static const eq_double_t lowest_grid_center_freq_hz = 31.25;
static const eq_double_t bands_grid_center_freq_hz = 1000;
static const eq_double_t lowest_audio_freq_hz = 20;
static const eq_double_t highest_audio_freq_hz = 20000;
//Eq config constants
static const unsigned int default_eq_band_filters_order = 4; //>2
static const eq_double_t default_sample_freq_hz = 48000;
//Precomputed Eq (eq2) config constants
static const eq_double_t p_eq_min_max_gain_db = 40;
static const eq_double_t p_eq_gain_step_db = 1;
static const eq_double_t common_base_gain_db = 3;
static const eq_double_t p_eq_default_gain_db = 0;
//Version
static const char* eq_version = "0.01";
//------------ Conversion functions class ------------
class conversions
{
int db_min_max;
std::vector<eq_double_t> lin_gains;
int lin_gains_index(eq_double_t x) {
int int_x = (int)x;
if((x >= -db_min_max) && (x < db_min_max - 1))
return db_min_max + int_x;
return db_min_max;
}
conversions() {}
public:
conversions(int min_max) {
db_min_max = min_max;
//Update table (vector elements) for fast conversions
int step = -min_max;
while(step <= min_max)
lin_gains.push_back(db_2_lin(step++));
}
inline eq_double_t fast_db_2_lin(eq_double_t x) {
int int_part = (int)x;
eq_double_t frac_part = x - int_part;
return lin_gains[lin_gains_index(int_part)] * (1 - frac_part) +
(lin_gains[lin_gains_index(int_part + 1)])*frac_part;
}
inline eq_double_t fast_lin_2_db(eq_double_t x) {
if((x >= lin_gains[0]) && (x < lin_gains[lin_gains.size() - 1])) {
for(unsigned int i = 0; i < lin_gains.size() - 2; i++)
if((x >= lin_gains[i]) && (x < lin_gains[i + 1])) {
int int_part = i - db_min_max;
eq_double_t frac_part = x - (int)(x);
return int_part + frac_part;
}
}
return 0;
}
inline static eq_double_t db_2_lin(eq_double_t x) {
return pow(10, x / 20);
}
inline static eq_double_t lin_2_db(eq_double_t x) {
return 20 * log10(x);
}
inline static eq_double_t rad_2_hz(eq_double_t x, eq_double_t fs) {
return 2 * pi / x*fs;
}
inline static eq_double_t hz_2_rad(eq_double_t x, eq_double_t fs) {
return 2 * pi*x / fs;
}
};
//------------ Band freq's structure ------------
struct band_freqs
{
private:
band_freqs();
public:
eq_double_t min_freq;
eq_double_t center_freq;
eq_double_t max_freq;
band_freqs(eq_double_t f1, eq_double_t f0, eq_double_t f2) :
min_freq(f1), center_freq(f0), max_freq(f2) {}
~band_freqs() {}
};
//------------ Frequency grid class ------------
class freq_grid
{
private:
std::vector<band_freqs> freqs_;
public:
freq_grid() {}
freq_grid(const freq_grid& fg) { this->freqs_ = fg.freqs_; }
~freq_grid() {}
eq_error_t set_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) {
freqs_.clear();
return add_band(fmin, f0, fmax);
}
//fc, fmin, fmax
eq_error_t add_band(eq_double_t fmin, eq_double_t f0, eq_double_t fmax) {
if(fmin < f0 && f0 < fmax)
freqs_.push_back(band_freqs(fmin, f0, fmax));
else
return invalid_input_data_error;
return no_error;
}
//f0, deltaf = fmax - fmin
eq_error_t add_band(eq_double_t f0, eq_double_t df) {
if(f0 >= df / 2) {
eq_double_t fmin = f0 - df / 2;
eq_double_t fmax = f0 + df / 2;
freqs_.push_back(band_freqs(fmin, f0, fmax));
} else
return invalid_input_data_error;
return no_error;
}
eq_error_t set_5_bands(eq_double_t center_freq = bands_grid_center_freq_hz) {
freqs_.clear();
if(lowest_audio_freq_hz < center_freq &&
center_freq < highest_audio_freq_hz) {
//Find lowest center frequency in band
eq_double_t lowest_center_freq = center_freq;
while(lowest_center_freq > lowest_grid_center_freq_hz)
lowest_center_freq /= 4.0;
if(lowest_center_freq < lowest_grid_center_freq_hz)
lowest_center_freq *= 4.0;
//Calculate freq's
eq_double_t f0 = lowest_center_freq;
for(unsigned int i = 0; i < 5; i++) {
freqs_.push_back(band_freqs(f0 / 2, f0, f0 * 2));
f0 *= 4;
}
} else
return invalid_input_data_error;
return no_error;
}
eq_error_t set_10_bands(eq_double_t center_freq = bands_grid_center_freq_hz) {
freqs_.clear();
if(lowest_audio_freq_hz < center_freq &&
center_freq < highest_audio_freq_hz) {
//Find lowest center frequency in band
eq_double_t lowest_center_freq = center_freq;
while(lowest_center_freq > lowest_grid_center_freq_hz)
lowest_center_freq /= 2;
if(lowest_center_freq < lowest_grid_center_freq_hz)
lowest_center_freq *= 2;
//Calculate freq's
eq_double_t f0 = lowest_center_freq;
for(unsigned int i = 0; i < 10; i++) {
freqs_.push_back(band_freqs(f0 / pow(2, 0.5), f0, f0*pow(2, 0.5)));
f0 *= 2;
}
} else
return invalid_input_data_error;
return no_error;
}
eq_error_t set_20_bands(eq_double_t center_freq = bands_grid_center_freq_hz) {
freqs_.clear();
if(lowest_audio_freq_hz < center_freq &&
center_freq < highest_audio_freq_hz) {
//Find lowest center frequency in band
eq_double_t lowest_center_freq = center_freq;
while(lowest_center_freq > lowest_audio_freq_hz)
lowest_center_freq /= pow(2, 0.5);
if(lowest_center_freq < lowest_audio_freq_hz)
lowest_center_freq *= pow(2, 0.5);
//Calculate freq's
eq_double_t f0 = lowest_center_freq;
for(unsigned int i = 0; i < 20; i++) {
freqs_.push_back(band_freqs(f0 / pow(2, 0.25),
f0, f0*pow(2, 0.25)));
f0 *= pow(2, 0.5);
}
} else
return invalid_input_data_error;
return no_error;
}
eq_error_t set_30_bands(eq_double_t center_freq = bands_grid_center_freq_hz) {
freqs_.clear();
if(lowest_audio_freq_hz < center_freq &&
center_freq < highest_audio_freq_hz) {
//Find lowest center frequency in band
eq_double_t lowest_center_freq = center_freq;
while(lowest_center_freq > lowest_audio_freq_hz)
lowest_center_freq /= pow(2.0, 1.0 / 3.0);
if(lowest_center_freq < lowest_audio_freq_hz)
lowest_center_freq *= pow(2.0, 1.0 / 3.0);
//Calculate freq's
eq_double_t f0 = lowest_center_freq;
for(unsigned int i = 0; i < 30; i++) {
freqs_.push_back(band_freqs(f0 / pow(2.0, 1.0 / 6.0),
f0, f0*pow(2.0, 1.0 / 6.0)));
f0 *= pow(2, 1.0 / 3.0);
}
} else
return invalid_input_data_error;
return no_error;
}
unsigned int get_number_of_bands() { return (unsigned int)freqs_.size(); }
std::vector<band_freqs> get_freqs() { return freqs_; }
unsigned int get_freq(unsigned int number) {
if(number < freqs_.size())
return (unsigned int)freqs_[number].center_freq;
else
return 0;
}
unsigned int get_rounded_freq(unsigned int number) {
if(number < freqs_.size()) {
unsigned int freq = (unsigned int)freqs_[number].center_freq;
if(freq < 100)
return freq;
else if(freq >= 100 && freq < 1000) {
unsigned int rest = freq % 10;
if(rest < 5)
return freq - rest;
else
return freq - rest + 10;
} else if(freq >= 1000 && freq < 10000) {
unsigned int rest = freq % 100;
if(rest < 50)
return freq - rest;
else
return freq - rest + 100;
} else if(freq >= 10000) {
unsigned int rest = freq % 1000;
if(rest < 500)
return freq - rest;
else
return freq - rest + 1000;
}
}
return 0;
}
};
//------------ Forth order sections ------------
class fo_section
{
protected:
eq_single_t b0; eq_single_t b1; eq_single_t b2; eq_single_t b3; eq_single_t b4;
eq_single_t a0; eq_single_t a1; eq_single_t a2; eq_single_t a3; eq_single_t a4;
eq_single_t numBuf[fo_section_order];
eq_single_t denumBuf[fo_section_order];
inline eq_single_t df1_fo_process(eq_single_t in) {
eq_single_t out = 0;
out += b0*in;
out += (b1*numBuf[0] - denumBuf[0] * a1);
out += (b2*numBuf[1] - denumBuf[1] * a2);
out += (b3*numBuf[2] - denumBuf[2] * a3);
out += (b4*numBuf[3] - denumBuf[3] * a4);
numBuf[3] = numBuf[2];
numBuf[2] = numBuf[1];
numBuf[1] = numBuf[0];
if(in < 0.000000000001 && in > -0.000000000001) {
//Prevent denormalized values (causes extreme performance loss)
in = 0;
}
*numBuf = in;
denumBuf[3] = denumBuf[2];
denumBuf[2] = denumBuf[1];
denumBuf[1] = denumBuf[0];
if(out < 0.000000000001 && out > -0.000000000001) {
//Prevent denormalized values (causes extreme performance loss)
out = 0;
}
*denumBuf = out;
return(out);
}
public:
fo_section() {
b0 = 1; b1 = 0; b2 = 0; b3 = 0; b4 = 0;
a0 = 1; a1 = 0; a2 = 0; a3 = 0; a4 = 0;
for(unsigned int i = 0; i < fo_section_order; i++) {
numBuf[i] = 0;
denumBuf[i] = 0;
}
}
virtual ~fo_section() {}
eq_single_t process(eq_single_t in) {
return df1_fo_process(in);
}
virtual fo_section get() {
return *this;
}
};
class butterworth_fo_section : public fo_section
{
butterworth_fo_section() {}
butterworth_fo_section(butterworth_fo_section&) {}
public:
butterworth_fo_section(eq_double_t beta,
eq_double_t s, eq_double_t g, eq_double_t g0,
eq_double_t D, eq_double_t c0) {
b0 = (g*g*beta*beta + 2 * g*g0*s*beta + g0*g0) / D;
b1 = -4 * c0*(g0*g0 + g*g0*s*beta) / D;
b2 = 2 * (g0*g0*(1 + 2 * c0*c0) - g*g*beta*beta) / D;
b3 = -4 * c0*(g0*g0 - g*g0*s*beta) / D;
b4 = (g*g*beta*beta - 2 * g*g0*s*beta + g0*g0) / D;
a0 = 1;
a1 = -4 * c0*(1 + s*beta) / D;
a2 = 2 * (1 + 2 * c0*c0 - beta*beta) / D;
a3 = -4 * c0*(1 - s*beta) / D;
a4 = (beta*beta - 2 * s*beta + 1) / D;
}
fo_section get() { return *this; }
};
class chebyshev_type1_fo_section : public fo_section
{
chebyshev_type1_fo_section() {}
chebyshev_type1_fo_section(chebyshev_type1_fo_section&) {}
public:
chebyshev_type1_fo_section(eq_double_t a,
eq_double_t c, eq_double_t tetta_b,
eq_double_t g0, eq_double_t s, eq_double_t b,
eq_double_t D, eq_double_t c0) {
b0 = ((b*b + g0*g0*c*c)*tetta_b*tetta_b + 2 * g0*b*s*tetta_b + g0*g0) / D;
b1 = -4 * c0*(g0*g0 + g0*b*s*tetta_b) / D;
b2 = 2 * (g0*g0*(1 + 2 * c0*c0) - (b*b + g0*g0*c*c)*tetta_b*tetta_b) / D;
b3 = -4 * c0*(g0*g0 - g0*b*s*tetta_b) / D;
b4 = ((b*b + g0*g0*c*c)*tetta_b*tetta_b - 2 * g0*b*s*tetta_b + g0*g0) / D;
a0 = 1;
a1 = -4 * c0*(1 + a*s*tetta_b) / D;
a2 = 2 * (1 + 2 * c0*c0 - (a*a + c*c)*tetta_b*tetta_b) / D;
a3 = -4 * c0*(1 - a*s*tetta_b) / D;
a4 = ((a*a + c*c)*tetta_b*tetta_b - 2 * a*s*tetta_b + 1) / D;
}
fo_section get() { return *this; }
};
class chebyshev_type2_fo_section : public fo_section
{
chebyshev_type2_fo_section() {}
chebyshev_type2_fo_section(chebyshev_type2_fo_section&) {}
public:
chebyshev_type2_fo_section(eq_double_t a,
eq_double_t c, eq_double_t tetta_b,
eq_double_t g, eq_double_t s, eq_double_t b,
eq_double_t D, eq_double_t c0) {
b0 = (g*g*tetta_b*tetta_b + 2 * g*b*s*tetta_b + b*b + g*g*c*c) / D;
b1 = -4 * c0*(b*b + g*g*c*c + g*b*s*tetta_b) / D;
b2 = 2 * ((b*b + g*g*c*c)*(1 + 2 * c0*c0) - g*g*tetta_b*tetta_b) / D;
b3 = -4 * c0*(b*b + g*g*c*c - g*b*s*tetta_b) / D;
b4 = (g*g*tetta_b*tetta_b - 2 * g*b*s*tetta_b + b*b + g*g*c*c) / D;
a0 = 1;
a1 = -4 * c0*(a*a + c*c + a*s*tetta_b) / D;
a2 = 2 * ((a*a + c*c)*(1 + 2 * c0*c0) - tetta_b*tetta_b) / D;
a3 = -4 * c0*(a*a + c*c - a*s*tetta_b) / D;
a4 = (tetta_b*tetta_b - 2 * a*s*tetta_b + a*a + c*c) / D;
}
fo_section get() { return *this; }
};
//------------ Bandpass filters ------------
class bp_filter
{
public:
bp_filter() {}
virtual ~bp_filter() {}
virtual eq_single_t process(eq_single_t in) = 0;
};
class butterworth_bp_filter : public bp_filter
{
private:
std::vector<fo_section> sections_;
butterworth_bp_filter() {}
public:
butterworth_bp_filter(butterworth_bp_filter& f) {
this->sections_ = f.sections_;
}
butterworth_bp_filter(unsigned int N,
eq_double_t w0, eq_double_t wb,
eq_double_t G, eq_double_t Gb, eq_double_t G0) {
//Case if G == 0 : allpass
if(G == 0 && G0 == 0) {
sections_.push_back(fo_section());
return;
}
//Get number of analog sections
unsigned int r = N % 2;
unsigned int L = (N - r) / 2;
//Convert gains to linear scale
G = conversions::db_2_lin(G);
Gb = conversions::db_2_lin(Gb);
G0 = conversions::db_2_lin(G0);
eq_double_t epsilon = pow(((eq_double_t)(G*G - Gb*Gb)) /
(Gb*Gb - G0*G0), 0.5);
eq_double_t g = pow(((eq_double_t)G), 1.0 / ((eq_double_t)N));
eq_double_t g0 = pow(((eq_double_t)G0), 1.0 / ((eq_double_t)N));
eq_double_t beta = pow(((eq_double_t)epsilon), -1.0 / ((eq_double_t)N))*
tan(wb / 2.0);
eq_double_t c0 = cos(w0);
if(w0 == 0) c0 = 1;
if(w0 == pi / 2) c0 = 0;
if(w0 == pi) c0 = -1;
//Calculate every section
for(unsigned int i = 1; i <= L; i++) {
eq_double_t ui = (2.0*i - 1) / N;
eq_double_t si = sin(pi*ui / 2.0);
eq_double_t Di = beta*beta + 2 * si*beta + 1;
sections_.push_back
(butterworth_fo_section(beta, si, g, g0, Di, c0));
}
}
~butterworth_bp_filter() {}
static eq_single_t compute_bw_gain_db(eq_single_t gain) {
eq_single_t bw_gain = 0;
if(gain <= -6)
bw_gain = gain + common_base_gain_db;
else if(gain > -6 && gain < 6)
bw_gain = gain*0.5;
else if(gain >= 6)
bw_gain = gain - common_base_gain_db;
return bw_gain;
}
virtual eq_single_t process(eq_single_t in) {
eq_single_t p0 = in;
eq_single_t p1 = 0;
//Process FO sections in serial connection
for(size_t i = 0, len = sections_.size(); i < len; i++) {
p1 = sections_[i].process(p0);
p0 = p1;
}
return p1;
}
};
class chebyshev_type1_bp_filter : public bp_filter
{
private:
std::vector<fo_section> sections_;
chebyshev_type1_bp_filter() {}
public:
chebyshev_type1_bp_filter(unsigned int N,
eq_double_t w0, eq_double_t wb,
eq_double_t G, eq_double_t Gb, eq_double_t G0) {
//Case if G == 0 : allpass
if(G == 0 && G0 == 0) {
sections_.push_back(fo_section());
return;
}
//Get number of analog sections
unsigned int r = N % 2;
unsigned int L = (N - r) / 2;
//Convert gains to linear scale
G = conversions::db_2_lin(G);
Gb = conversions::db_2_lin(Gb);
G0 = conversions::db_2_lin(G0);
eq_double_t epsilon = pow((eq_double_t)(G*G - Gb*Gb) /
(Gb*Gb - G0*G0), 0.5);
eq_double_t g0 = pow((eq_double_t)(G0), 1.0 / N);
eq_double_t alfa =
pow(1.0 / epsilon + pow(1 + pow(epsilon, -2.0), 0.5), 1.0 / N);
eq_double_t beta =
pow(G / epsilon + Gb*pow(1 + pow(epsilon, -2.0), 0.5), 1.0 / N);
eq_double_t a = 0.5*(alfa - 1.0 / alfa);
eq_double_t b = 0.5*(beta - g0*g0*(1 / beta));
eq_double_t tetta_b = tan(wb / 2);
eq_double_t c0 = cos(w0);
if(w0 == 0) c0 = 1;
if(w0 == pi / 2) c0 = 0;
if(w0 == pi) c0 = -1;
//Calculate every section
for(unsigned int i = 1; i <= L; i++) {
eq_double_t ui = (2.0*i - 1.0) / N;
eq_double_t ci = cos(pi*ui / 2.0);
eq_double_t si = sin(pi*ui / 2.0);
eq_double_t Di = (a*a + ci*ci)*tetta_b*tetta_b +
2.0*a*si*tetta_b + 1;
sections_.push_back(
chebyshev_type1_fo_section(a, ci, tetta_b, g0, si, b, Di, c0));
}
}
~chebyshev_type1_bp_filter() {}
static eq_single_t compute_bw_gain_db(eq_single_t gain) {
eq_single_t bw_gain = 0;
if(gain <= -6)
bw_gain = gain + 1;
else if(gain > -6 && gain < 6)
bw_gain = gain*0.9;
else if(gain >= 6)
bw_gain = gain - 1;
return bw_gain;
}
eq_single_t process(eq_single_t in) {
eq_single_t p0 = in;
eq_single_t p1 = 0;
//Process FO sections in serial connection
for(size_t i = 0, len = sections_.size(); i < len; i++) {
p1 = sections_[i].process(p0);
p0 = p1;
}
return p1;
}
};
class chebyshev_type2_bp_filter : public bp_filter
{
private:
std::vector<fo_section> sections_;
chebyshev_type2_bp_filter() {}
public:
chebyshev_type2_bp_filter(unsigned int N,
eq_double_t w0, eq_double_t wb,
eq_double_t G, eq_double_t Gb, eq_double_t G0) {
//Case if G == 0 : allpass
if(G == 0 && G0 == 0) {
sections_.push_back(fo_section());
return;
}
//Get number of analog sections
unsigned int r = N % 2;
unsigned int L = (N - r) / 2;
//Convert gains to linear scale
G = conversions::db_2_lin(G);
Gb = conversions::db_2_lin(Gb);
G0 = conversions::db_2_lin(G0);
eq_double_t epsilon = pow((eq_double_t)((G*G - Gb*Gb) /
(Gb*Gb - G0*G0)), 0.5);
eq_double_t g = pow((eq_double_t)(G), 1.0 / N);
eq_double_t eu = pow(epsilon + sqrt(1 + epsilon*epsilon), 1.0 / N);
eq_double_t ew = pow(G0*epsilon + Gb*sqrt(1 + epsilon*epsilon), 1.0 / N);
eq_double_t a = (eu - 1.0 / eu) / 2.0;
eq_double_t b = (ew - g*g / ew) / 2.0;
eq_double_t tetta_b = tan(wb / 2);
eq_double_t c0 = cos(w0);
if(w0 == 0) c0 = 1;
if(w0 == pi / 2) c0 = 0;
if(w0 == pi) c0 = -1;
//Calculate every section
for(unsigned int i = 1; i <= L; i++) {
eq_double_t ui = (2.0*i - 1.0) / N;
eq_double_t ci = cos(pi*ui / 2.0);
eq_double_t si = sin(pi*ui / 2.0);
eq_double_t Di = tetta_b*tetta_b + 2 * a*si*tetta_b + a*a + ci*ci;
sections_.push_back(
chebyshev_type2_fo_section(a, ci, tetta_b, g, si, b, Di, c0));
}
}
~chebyshev_type2_bp_filter() {}
static eq_single_t compute_bw_gain_db(eq_single_t gain) {
eq_single_t bw_gain = 0;
if(gain <= -6)
bw_gain = -common_base_gain_db;
else if(gain > -6 && gain < 6)
bw_gain = gain*0.3;
else if(gain >= 6)
bw_gain = common_base_gain_db;
return bw_gain;
}
eq_single_t process(eq_single_t in) {
eq_single_t p0 = in;
eq_single_t p1 = 0;
//Process FO sections in serial connection
for(size_t i = 0, len = sections_.size(); i < len; i++) {
p1 = sections_[i].process(p0);
p0 = p1;
}
return p1;
}
};
// ------------ eq1 ------------
// Equalizer with single precomputed filter for every band
class eq1
{
private:
conversions conv_;
eq_double_t sampling_frequency_;
freq_grid freq_grid_;
std::vector<eq_single_t> band_gains_;
std::vector<bp_filter*> filters_;
filter_type current_eq_type_;
eq1() :conv_(eq_min_max_gain_db) {}
eq1(const eq1&) :conv_(eq_min_max_gain_db) {}
void cleanup_filters_array() {
for(unsigned int j = 0; j < filters_.size(); j++)
delete filters_[j];
}
public:
eq1(const freq_grid *fg, filter_type eq_t) : conv_(eq_min_max_gain_db) {
sampling_frequency_ = default_sample_freq_hz;
freq_grid_ = *fg;
current_eq_type_ = eq_t;
set_eq(freq_grid_, eq_t);
}
~eq1() { cleanup_filters_array(); }
eq_error_t set_eq(freq_grid& fg, filter_type eqt) {
band_gains_.clear();
cleanup_filters_array();
filters_.clear();
freq_grid_ = fg;
for(unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) {
eq_double_t wb = conversions::hz_2_rad(
freq_grid_.get_freqs()[i].max_freq -
freq_grid_.get_freqs()[i].min_freq,
sampling_frequency_);
eq_double_t w0 = conversions::hz_2_rad(
freq_grid_.get_freqs()[i].center_freq,
sampling_frequency_);
switch(eqt) {
case (butterworth): {
butterworth_bp_filter* bf =
new butterworth_bp_filter(
default_eq_band_filters_order,
w0,
wb,
max_base_gain_db,
butterworth_band_gain_db,
min_base_gain_db
);
filters_.push_back(bf);
break;
}
case (chebyshev1): {
chebyshev_type1_bp_filter* cf1 =
new chebyshev_type1_bp_filter(
default_eq_band_filters_order,
w0,
wb,
max_base_gain_db,
chebyshev1_band_base_gain_db,
min_base_gain_db
);
filters_.push_back(cf1);
break;
}
case (chebyshev2): {
chebyshev_type2_bp_filter* cf2 =
new chebyshev_type2_bp_filter(
default_eq_band_filters_order,
w0,
wb,
max_base_gain_db,
chebyshev2_band_base_gain_db,
min_base_gain_db
);
filters_.push_back(cf2);
break;
}
default:
current_eq_type_ = none;
return invalid_input_data_error;
}
band_gains_.push_back(max_base_gain_db);
}
current_eq_type_ = eqt;
return no_error;
}
eq_error_t set_eq(filter_type eqt)
{
return set_eq(freq_grid_, eqt);
}
eq_error_t set_sample_rate(eq_double_t sr) {
eq_error_t err = no_error;
sampling_frequency_ = sr;
err = set_eq(freq_grid_, current_eq_type_);
return err;
}
eq_error_t change_gains(std::vector<eq_single_t> band_gains) {
if(band_gains_.size() == band_gains.size())
band_gains_ = band_gains;
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_gains_db(std::vector<eq_single_t> band_gains) {
if(band_gains_.size() == band_gains.size())
for(unsigned int j = 0; j < get_number_of_bands(); j++)
band_gains_[j] = conv_.fast_db_2_lin(band_gains[j]);
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_band_gain(unsigned int band_number,
eq_single_t band_gain) {
if(band_number < get_number_of_bands())
band_gains_[band_number] = band_gain;
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_band_gain_db(unsigned int band_number, eq_single_t band_gain) {
if(band_number < get_number_of_bands())
band_gains_[band_number] = conv_.fast_db_2_lin(band_gain);
else
return invalid_input_data_error;
return no_error;
}
eq_error_t sbs_process_band(unsigned int band_number, eq_single_t *in, eq_single_t *out) {
//if(band_number < get_number_of_bands())
*out = band_gains_[band_number] *
filters_[band_number]->process(*in);
//else
//return invalid_input_data_error;
return no_error;
}
eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) {
eq_error_t err = no_error;
eq_single_t acc_out = 0;
for(unsigned int j = 0, len = get_number_of_bands(); j < len; j++) {
eq_single_t band_out = 0;
err = sbs_process_band(j, in, &band_out);
acc_out += band_out;
}
*out = acc_out;
return err;
}
filter_type get_eq_type() { return current_eq_type_; }
const char* get_string_eq_type() { return get_eq_text(current_eq_type_); }
unsigned int get_number_of_bands() {
return freq_grid_.get_number_of_bands();
}
const char* get_version() { return eq_version; }
};
//!!! New functionality
// ------------ eq_channel ------------
// Precomputed equalizer channel,
// consists of vector of filters for every gain value
class eq_channel
{
eq_single_t f0_;
eq_single_t fb_;
eq_single_t sampling_frequency_;
eq_single_t min_max_gain_db_;
eq_single_t gain_step_db_;
unsigned int current_filter_index_;
eq_single_t current_gain_db_;
std::vector<bp_filter*> filters_;
filter_type current_channel_type_;
eq_channel() {}
unsigned int get_flt_index(eq_single_t gain_db) {
unsigned int number_of_filters = (unsigned int)filters_.size();
eq_single_t scale_coef = gain_db / min_max_gain_db_;
return (unsigned int)((number_of_filters / 2) + (number_of_filters / 2)*scale_coef);
}
void cleanup_filters_array() {
for(unsigned int j = 0; j < filters_.size(); j++)
delete filters_[j];
}
public:
eq_channel(filter_type ft,
eq_single_t fs, eq_single_t f0, eq_single_t fb,
eq_single_t min_max_gain_db = p_eq_min_max_gain_db,
eq_single_t step_db = p_eq_gain_step_db) {
//Init data fields
sampling_frequency_ = fs;
f0_ = f0;
fb_ = fb;
min_max_gain_db_ = min_max_gain_db;
gain_step_db_ = step_db;
current_gain_db_ = 0;
current_filter_index_ = 0;
current_channel_type_ = ft;
set_channel(current_channel_type_, sampling_frequency_);
}
~eq_channel() { cleanup_filters_array(); }
eq_error_t set_channel(filter_type ft, eq_single_t fs) {
eq_double_t wb = conversions::hz_2_rad(fb_, sampling_frequency_);
eq_double_t w0 = conversions::hz_2_rad(f0_, sampling_frequency_);
for(eq_single_t gain = -min_max_gain_db_; gain <= min_max_gain_db_;
gain += gain_step_db_) {
switch(ft) {
case (butterworth): {
eq_single_t bw_gain =
butterworth_bp_filter::compute_bw_gain_db(gain);
butterworth_bp_filter* bf =
new butterworth_bp_filter(
default_eq_band_filters_order,
w0,
wb,
gain,
bw_gain,
p_eq_default_gain_db
);
filters_.push_back(bf);
break;
}
case (chebyshev1): {
eq_single_t bw_gain =
chebyshev_type1_bp_filter::compute_bw_gain_db(gain);
chebyshev_type1_bp_filter* cf1 =
new chebyshev_type1_bp_filter(
default_eq_band_filters_order,
w0,
wb,
gain,
bw_gain,
p_eq_default_gain_db
);
filters_.push_back(cf1);
break;
}
case (chebyshev2): {
eq_single_t bw_gain =
chebyshev_type2_bp_filter::compute_bw_gain_db(gain);
chebyshev_type2_bp_filter* cf2 =
new chebyshev_type2_bp_filter(
default_eq_band_filters_order,
w0,
wb,
gain,
bw_gain,
p_eq_default_gain_db
);
filters_.push_back(cf2);
break;
}
default: {
current_channel_type_ = none;
return invalid_input_data_error;
}
}
}
//Get current filter index
current_gain_db_ = 0;
current_filter_index_ = get_flt_index(current_gain_db_);
return no_error;
}
eq_error_t set_gain_db(eq_single_t db) {
if(db > -min_max_gain_db_ && db < min_max_gain_db_) {
current_gain_db_ = db;
current_filter_index_ = get_flt_index(db);
} else
return invalid_input_data_error;
return no_error;
}
eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) {
*out = filters_[current_filter_index_]->process(*in);
return no_error;
}
};
// ------------ eq2 ------------
// Precomputed equalizer
class eq2
{
conversions conv_;
eq_double_t sampling_frequency_;
freq_grid freq_grid_;
std::vector<eq_channel*> channels_;
filter_type current_eq_type_;
void cleanup_channels_array() {
for(unsigned int j = 0; j < channels_.size(); j++)
delete channels_[j];
}
public:
eq2(freq_grid &fg, filter_type eq_t) : conv_(eq_min_max_gain_db) {
sampling_frequency_ = default_sample_freq_hz;
freq_grid_ = fg;
current_eq_type_ = eq_t;
set_eq(freq_grid_, eq_t);
}
~eq2() { cleanup_channels_array(); }
eq_error_t set_eq(const freq_grid& fg, filter_type ft) {
cleanup_channels_array();
channels_.clear();
freq_grid_ = fg;
for(unsigned int i = 0; i < freq_grid_.get_number_of_bands(); i++) {
band_freqs b_fres = freq_grid_.get_freqs()[i];
eq_channel* eq_ch = new eq_channel(ft, sampling_frequency_,
b_fres.center_freq, b_fres.max_freq - b_fres.min_freq);
channels_.push_back(eq_ch);
channels_[i]->set_gain_db(p_eq_default_gain_db);
}
current_eq_type_ = ft;
return no_error;
}
eq_error_t set_eq(filter_type ft) {
eq_error_t err = set_eq(freq_grid_, ft);
return err;
}
eq_error_t set_sample_rate(eq_double_t sr) {
sampling_frequency_ = sr;
eq_error_t err = set_eq(current_eq_type_);
return err;
}
eq_error_t change_gains(std::vector<eq_single_t> band_gains) {
if(channels_.size() == band_gains.size())
for(unsigned int j = 0; j < channels_.size(); j++)
channels_[j]->set_gain_db(conv_.fast_lin_2_db(band_gains[j]));
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_gains_db(std::vector<eq_single_t> band_gains) {
if(channels_.size() == band_gains.size())
for(unsigned int j = 0; j < channels_.size(); j++)
channels_[j]->set_gain_db(band_gains[j]);
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_band_gain(unsigned int band_number,
eq_single_t band_gain) {
if(band_number < channels_.size())
channels_[band_number]->set_gain_db(conv_.fast_lin_2_db(band_gain));
else
return invalid_input_data_error;
return no_error;
}
eq_error_t change_band_gain_db(unsigned int band_number,
eq_single_t band_gain) {
if(band_number < channels_.size())
channels_[band_number]->set_gain_db(band_gain);
else
return invalid_input_data_error;
return no_error;
}
eq_error_t sbs_process_band(unsigned int band_number,
eq_single_t *in, eq_single_t *out) {
if(band_number < get_number_of_bands())
channels_[band_number]->sbs_process(in, out);
else
return invalid_input_data_error;
return no_error;
}
eq_error_t sbs_process(eq_single_t *in, eq_single_t *out) {
eq_error_t err = no_error;
eq_single_t in_out = *in;
for(unsigned int i = 0; i < get_number_of_bands(); i++)
err = sbs_process_band(i, &in_out, &in_out);
*out = in_out;
return err;
}
filter_type get_eq_type() { return current_eq_type_; }
const char* get_string_eq_type() { return get_eq_text(current_eq_type_); }
unsigned int get_number_of_bands() {
return freq_grid_.get_number_of_bands();
}
const char* get_version() { return eq_version; }
};
} //namespace orfanidis_eq
#endif //ORFANIDIS_EQ_H_