Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61231f5c authored by Antti S. Lankila's avatar Antti S. Lankila
Browse files

Smooth biquad interpolation for equalizer

Equalizer now uses linear coefficient interpolation to reduce
chance of producing snapping artifacts in the dynamic mode.

Change-Id: I2f3c175e7c647da7c800202157479112409f39ac
parent 9f3cd90b
Loading
Loading
Loading
Loading
+51 −14
Original line number Diff line number Diff line
@@ -24,34 +24,56 @@ static int64_t toFixedPoint(float in) {
Biquad::Biquad()
{
    reset();
    setCoefficients(1, 0, 0, 0, 0, 0);
    setCoefficients(0, 1, 0, 0, 1, 0, 0);
}

Biquad::~Biquad()
{
}

void Biquad::setCoefficients(float a0, float a1, float a2, float b0, float b1, float b2)
void Biquad::setCoefficients(int32_t steps, float a0, float a1, float a2, float b0, float b1, float b2)
{
    mA1 = -toFixedPoint(a1/a0);
    mA2 = -toFixedPoint(a2/a0);
    mB0 = toFixedPoint(b0/a0);
    mB1 = toFixedPoint(b1/a0);
    mB2 = toFixedPoint(b2/a0);
    int64_t A1 = -toFixedPoint(a1/a0);
    int64_t A2 = -toFixedPoint(a2/a0);
    int64_t B0 = toFixedPoint(b0/a0);
    int64_t B1 = toFixedPoint(b1/a0);
    int64_t B2 = toFixedPoint(b2/a0);

    if (steps == 0) {
	mA1 = A1;
	mA2 = A2;
	mB0 = B0;
	mB1 = B1;
	mB2 = B2;
	mInterpolationSteps = 0;
    } else {
	mA1dif = (A1 - mA1) / steps;
	mA2dif = (A2 - mA2) / steps;
	mB0dif = (B0 - mB0) / steps;
	mB1dif = (B1 - mB1) / steps;
	mB2dif = (B2 - mB2) / steps;
	mInterpolationSteps = steps;
    }
}

void Biquad::reset()
{
    mInterpolationSteps = 0;
    mA1 = 0;
    mA2 = 0;
    mB0 = 0;
    mB1 = 0;
    mB2 = 0;
    mX1 = 0;
    mX2 = 0;
    mY1 = 0;
    mY2 = 0;
}

void Biquad::setHighShelf(float center_frequency, float sampling_frequency, float db_gain, float slope)
void Biquad::setHighShelf(int32_t steps, float center_frequency, float sampling_frequency, float gainDb, float slope, float overallGainDb)
{
    float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
    float A = powf(10, db_gain/40);
    float A = powf(10, gainDb/40);
    float alpha = sinf(w0)/2 * sqrtf( (A + 1/A)*(1/slope - 1) + 2 );

    float b0 =    A*( (A+1) + (A-1)*cosf(w0) + 2*sqrtf(A)*alpha );
@@ -61,10 +83,15 @@ void Biquad::setHighShelf(float center_frequency, float sampling_frequency, floa
    float a1 =    2*( (A-1) - (A+1)*cosf(w0)                   );
    float a2 =        (A+1) - (A-1)*cosf(w0) - 2*sqrtf(A)*alpha  ;

    setCoefficients(a0, a1, a2, b0, b1, b2);
    float overallGain = powf(10, overallGainDb / 20);
    b0 *= overallGain;
    b1 *= overallGain;
    b2 *= overallGain;

    setCoefficients(steps, a0, a1, a2, b0, b1, b2);
}

void Biquad::setBandPass(float center_frequency, float sampling_frequency, float resonance)
void Biquad::setBandPass(int32_t steps, float center_frequency, float sampling_frequency, float resonance)
{
    float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
    float alpha = sinf(w0) / (2*resonance);
@@ -76,10 +103,10 @@ void Biquad::setBandPass(float center_frequency, float sampling_frequency, float
    float a1 =  -2*cosf(w0);
    float a2 =   1 - alpha;

    setCoefficients(a0, a1, a2, b0, b1, b2);
    setCoefficients(steps, a0, a1, a2, b0, b1, b2);
}

void Biquad::setLowPass(float center_frequency, float sampling_frequency, float resonance)
void Biquad::setLowPass(int32_t steps, float center_frequency, float sampling_frequency, float resonance)
{
    float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
    float alpha = sinf(w0) / (2*resonance);
@@ -91,7 +118,7 @@ void Biquad::setLowPass(float center_frequency, float sampling_frequency, float
    float a1 =  -2*cosf(w0);
    float a2 =   1 - alpha;

    setCoefficients(a0, a1, a2, b0, b1, b2);
    setCoefficients(steps, a0, a1, a2, b0, b1, b2);
}

int32_t Biquad::process(int32_t x0)
@@ -109,5 +136,15 @@ int32_t Biquad::process(int32_t x0)
    mX2 = mX1;
    mX1 = x0;

    /* Interpolate biquad parameters */
    if (mInterpolationSteps != 0) {
	mInterpolationSteps --;
	mB0 += mB0dif;
	mB1 += mB1dif;
	mB2 += mB2dif;
	mA1 += mA1dif;
	mA2 += mA2dif;
    }

    return y0;
}
+6 −4
Original line number Diff line number Diff line
@@ -7,15 +7,17 @@ class Biquad {
    int32_t mX1, mX2;
    int32_t mY1, mY2;
    int64_t mB0, mB1, mB2, mA1, mA2;
    int64_t mB0dif, mB1dif, mB2dif, mA1dif, mA2dif;
    int32_t mInterpolationSteps;

    void setCoefficients(float a0, float a1, float a2, float b0, float b1, float b2);
    void setCoefficients(int32_t steps, float a0, float a1, float a2, float b0, float b1, float b2);

    public:
    Biquad();
    virtual ~Biquad();
    void setHighShelf(float cf, float sf, float gain, float slope);
    void setBandPass(float cf, float sf, float resonance);
    void setLowPass(float cf, float sf, float resonance);
    void setHighShelf(int32_t steps, float cf, float sf, float gaindB, float slope, float overallGain);
    void setBandPass(int32_t steps, float cf, float sf, float resonance);
    void setLowPass(int32_t steps, float cf, float sf, float resonance);
    int32_t process(int32_t in);
    void reset();
};
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ int32_t EffectBassBoost::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD
void EffectBassBoost::refreshStrength()
{
    /* Q = 0.5 .. 2.0 */
    mBoost.setLowPass(55.0f, mSamplingRate, 0.5f + mStrength / 666.0f);
    mBoost.setLowPass(0, 55.0f, mSamplingRate, 0.5f + mStrength / 666.0f);
}

int32_t EffectBassBoost::process(audio_buffer_t* in, audio_buffer_t* out)
+2 −2
Original line number Diff line number Diff line
@@ -53,8 +53,8 @@ int32_t EffectCompression::command(uint32_t cmdCode, uint32_t cmdSize, void* pCm

        /* This filter gives a reasonable approximation of A- and C-weighting
         * which is close to correct for 100 - 10 kHz. 10 dB gain must be added to result. */
	mWeigherBP[0].setBandPass(2200, mSamplingRate, 0.33);
	mWeigherBP[1].setBandPass(2200, mSamplingRate, 0.33);
	mWeigherBP[0].setBandPass(0, 2200, mSamplingRate, 0.33);
	mWeigherBP[1].setBandPass(0, 2200, mSamplingRate, 0.33);

	*replyData = 0;
	return 0;
+4 −7
Original line number Diff line number Diff line
@@ -230,14 +230,15 @@ float EffectEqualizer::getAdjustedBand(int32_t band) {

void EffectEqualizer::refreshBands()
{
    mGain = toFixedPoint(powf(10.0f, getAdjustedBand(0) / 20.0f));
    for (int32_t band = 0; band < 5; band ++) {
	/* 15.625, 62.5, 250, 1000, 4000, 16000 */
        float centerFrequency = 15.625f * powf(4, band);
        float dB = getAdjustedBand(band + 1) - getAdjustedBand(band);

        mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f);
        mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f);
	float overallGain = band == 0 ? getAdjustedBand(0) : 0.0f;

        mFilterL[band].setHighShelf(mNextUpdateInterval, centerFrequency * 2.0f, mSamplingRate, dB, 1.0f, overallGain);
        mFilterR[band].setHighShelf(mNextUpdateInterval, centerFrequency * 2.0f, mSamplingRate, dB, 1.0f, overallGain);
    }
}

@@ -283,10 +284,6 @@ int32_t EffectEqualizer::process(audio_buffer_t *in, audio_buffer_t *out)
        int64_t weight = tmpL + tmpR;
        mPowerSquared += weight * weight;
     
        /* first "shelve" is just gain */ 
        tmpL = tmpL * mGain >> 32;
        tmpR = tmpR * mGain >> 32;
 
        /* evaluate the other filters. */
        for (int32_t j = 0; j < 5; j ++) {
            tmpL = mFilterL[j].process(tmpL);
Loading