2018-03-22 07:05:40 -07:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-11-19 09:10:36 -08:00
|
|
|
#include <cmath>
|
|
|
|
|
2018-03-22 07:05:40 -07:00
|
|
|
#include "AL/alc.h"
|
|
|
|
#include "AL/al.h"
|
|
|
|
|
|
|
|
#include "alMain.h"
|
|
|
|
#include "defs.h"
|
|
|
|
|
|
|
|
|
2018-12-04 22:31:08 -08:00
|
|
|
void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rcpQ)
|
2018-03-22 07:05:40 -07:00
|
|
|
{
|
2018-12-04 20:55:10 -08:00
|
|
|
float alpha, sqrtgain_alpha_2;
|
|
|
|
float w0, sin_w0, cos_w0;
|
|
|
|
float a[3] = { 1.0f, 0.0f, 0.0f };
|
|
|
|
float b[3] = { 1.0f, 0.0f, 0.0f };
|
2018-03-22 07:05:40 -07:00
|
|
|
|
|
|
|
// Limit gain to -100dB
|
|
|
|
assert(gain > 0.00001f);
|
|
|
|
|
|
|
|
w0 = F_TAU * f0norm;
|
2018-11-19 09:10:36 -08:00
|
|
|
sin_w0 = std::sin(w0);
|
|
|
|
cos_w0 = std::cos(w0);
|
2018-03-22 07:05:40 -07:00
|
|
|
alpha = sin_w0/2.0f * rcpQ;
|
|
|
|
|
|
|
|
/* Calculate filter coefficients depending on filter type */
|
|
|
|
switch(type)
|
|
|
|
{
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::HighShelf:
|
|
|
|
sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
|
|
|
|
b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
|
|
|
|
b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
|
|
|
|
a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
|
|
|
|
a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
|
|
|
|
a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
|
|
|
|
break;
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::LowShelf:
|
|
|
|
sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
|
|
|
|
b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
|
|
|
|
b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
|
|
|
|
a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
|
|
|
|
a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
|
|
|
|
a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
|
|
|
|
break;
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::Peaking:
|
|
|
|
gain = std::sqrt(gain);
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = 1.0f + alpha * gain;
|
|
|
|
b[1] = -2.0f * cos_w0;
|
|
|
|
b[2] = 1.0f - alpha * gain;
|
|
|
|
a[0] = 1.0f + alpha / gain;
|
|
|
|
a[1] = -2.0f * cos_w0;
|
|
|
|
a[2] = 1.0f - alpha / gain;
|
|
|
|
break;
|
|
|
|
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::LowPass:
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = (1.0f - cos_w0) / 2.0f;
|
|
|
|
b[1] = 1.0f - cos_w0;
|
|
|
|
b[2] = (1.0f - cos_w0) / 2.0f;
|
|
|
|
a[0] = 1.0f + alpha;
|
|
|
|
a[1] = -2.0f * cos_w0;
|
|
|
|
a[2] = 1.0f - alpha;
|
|
|
|
break;
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::HighPass:
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = (1.0f + cos_w0) / 2.0f;
|
|
|
|
b[1] = -(1.0f + cos_w0);
|
|
|
|
b[2] = (1.0f + cos_w0) / 2.0f;
|
|
|
|
a[0] = 1.0f + alpha;
|
|
|
|
a[1] = -2.0f * cos_w0;
|
|
|
|
a[2] = 1.0f - alpha;
|
|
|
|
break;
|
2018-11-19 09:10:36 -08:00
|
|
|
case BiquadType::BandPass:
|
2018-03-22 07:05:40 -07:00
|
|
|
b[0] = alpha;
|
|
|
|
b[1] = 0;
|
|
|
|
b[2] = -alpha;
|
|
|
|
a[0] = 1.0f + alpha;
|
|
|
|
a[1] = -2.0f * cos_w0;
|
|
|
|
a[2] = 1.0f - alpha;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-12-04 22:31:08 -08:00
|
|
|
a1 = a[1] / a[0];
|
|
|
|
a2 = a[2] / a[0];
|
|
|
|
b0 = b[0] / a[0];
|
|
|
|
b1 = b[1] / a[0];
|
|
|
|
b2 = b[2] / a[0];
|
2018-03-22 07:05:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-04 22:31:08 -08:00
|
|
|
void BiquadFilter::process(float *RESTRICT dst, const float *RESTRICT src, int numsamples)
|
2018-03-22 07:05:40 -07:00
|
|
|
{
|
2018-04-24 00:17:07 -07:00
|
|
|
ASSUME(numsamples > 0);
|
|
|
|
|
2018-12-04 22:31:08 -08:00
|
|
|
const float b0{this->b0};
|
|
|
|
const float b1{this->b1};
|
|
|
|
const float b2{this->b2};
|
|
|
|
const float a1{this->a1};
|
|
|
|
const float a2{this->a2};
|
|
|
|
float z1{this->z1};
|
|
|
|
float z2{this->z2};
|
2018-12-04 20:55:10 -08:00
|
|
|
|
2018-04-24 00:17:07 -07:00
|
|
|
/* Processing loop is Transposed Direct Form II. This requires less storage
|
|
|
|
* compared to Direct Form I (only two delay components, instead of a four-
|
|
|
|
* sample history; the last two inputs and outputs), and works better for
|
|
|
|
* floating-point which favors summing similarly-sized values while being
|
|
|
|
* less bothered by overflow.
|
|
|
|
*
|
|
|
|
* See: http://www.earlevel.com/main/2003/02/28/biquads/
|
|
|
|
*/
|
2018-12-04 20:55:10 -08:00
|
|
|
auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](float input) noexcept -> float
|
2018-03-22 07:05:40 -07:00
|
|
|
{
|
2018-12-04 20:55:10 -08:00
|
|
|
float output = input*b0 + z1;
|
2018-04-24 00:17:07 -07:00
|
|
|
z1 = input*b1 - output*a1 + z2;
|
|
|
|
z2 = input*b2 - output*a2;
|
2018-12-04 20:35:23 -08:00
|
|
|
return output;
|
|
|
|
};
|
2018-12-04 22:31:08 -08:00
|
|
|
std::transform(src, src+numsamples, dst, proc_sample);
|
2018-04-24 00:17:07 -07:00
|
|
|
|
2018-12-04 22:31:08 -08:00
|
|
|
this->z1 = z1;
|
|
|
|
this->z2 = z2;
|
2018-03-22 07:05:40 -07:00
|
|
|
}
|