Saturday 23 December 2017

The Code For Biquad IIR Filters (RBJ) In Java

package com.nerdscentral.audio.pitch.algorithm;

import com.nerdscentral.audio.core.SFConstants;

/*
 * RBJ Filters from C++ version by arguru[AT]smartelectronix[DOT]com based on eq filter cookbook by Robert Bristow-Johnson
 * <rbj@audioimagination.com> The C++ code is believed to be public domain and license free after best efforts to establish its licensing. As this is a Java translation of that code I have placed this in the public domain as well.
 */
public class SFRBJFilter
{

    // filter coeffs
    double b0a0, b1a0, b2a0, a1a0, a2a0;

    // in/out history
    double ou1, ou2, in1, in2;

    public SFRBJFilter()
    {
        // reset filter coeffs
        b0a0 = b1a0 = b2a0 = a1a0 = a2a0 = 0.0;

        // reset in/out history
        ou1 = ou2 = in1 = in2 = 0.0f;
    }

    public double filter(double in0)
    {
        // filter
        final double yn = b0a0 * in0 + b1a0 * in1 + b2a0 * in2 - a1a0 * ou1 - a2a0 * ou2;

        // push in/out buffers
        in2 = in1;
        in1 = in0;
        ou2 = ou1;
        ou1 = yn;

        // return output
        return yn;
    }

    public double limitedFilter(double in0)
    {
        // filter
        double yn = b0a0 * in0 + b1a0 * in1 + b2a0 * in2 - a1a0 * ou1 - a2a0 * ou2;
    double ay = yn < 0 ? -yn : yn;
    if(ay > 1.0)
    {
        yn = yn < 0 ? -1.0 : 1.0;
    }
   
        // push in/out buffers
        in2 = in1;
        in1 = in0;
        ou2 = ou1;
        ou1 = yn;

        // return output
        return yn;
    }

    public enum FilterType
    {
        LOWPASS, HIGHPASS, BANDPASS_SKIRT, BANDPASS_PEAK, NOTCH, ALLPASS, PEAK, LOWSHELF, HIGHSHELF
    }

    public void calc_filter_coeffs(final FilterType type, final double frequency, final double q, final double db_gain)
    {
        boolean q_is_bandwidth;
        final double sample_rate = SFConstants.SAMPLE_RATE;
        switch (type)
        {
        case ALLPASS:
        case HIGHPASS:
        case LOWPASS:
        case LOWSHELF:
        case HIGHSHELF:
            q_is_bandwidth = false;
            break;
        default:
            q_is_bandwidth = true;
            break;
        }
        // System.out.println("Q Is Bandwidth " + q_is_bandwidth);
        // temp pi
        final double temp_pi = 3.1415926535897932384626433832795;

        // temp coef vars
        double alpha, a0 = 0, a1 = 0, a2 = 0, b0 = 0, b1 = 0, b2 = 0;

        // peaking, lowshelf and hishelf
        if (type == FilterType.PEAK || type == FilterType.HIGHSHELF || type == FilterType.LOWSHELF)
        {
            final double A = Math.pow(10.0, (db_gain / 40.0));
            final double omega = 2.0 * temp_pi * frequency / sample_rate;
            final double tsin = Math.sin(omega);
            final double tcos = Math.cos(omega);
            if (type == FilterType.PEAK) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin);
            else
                alpha = tsin / 2.0 * Math.sqrt((A + 1 / A) * (1 / q - 1) + 2);

            final double beta = Math.sqrt(A) / q;

            // peaking
            if (type == FilterType.PEAK)
            {
                b0 = (1.0 + alpha * A);
                b1 = (-2.0 * tcos);
                b2 = (1.0 - alpha * A);
                a0 = (1.0 + alpha / A);
                a1 = (-2.0 * tcos);
                a2 = (1.0 - alpha / A);
            }

            // lowshelf
            if (type == FilterType.LOWSHELF)
            {
                b0 = (A * ((A + 1.0) - (A - 1.0) * tcos + beta * tsin));
                b1 = (2.0 * A * ((A - 1.0) - (A + 1.0) * tcos));
                b2 = (A * ((A + 1.0) - (A - 1.0) * tcos - beta * tsin));
                a0 = ((A + 1.0) + (A - 1.0) * tcos + beta * tsin);
                a1 = (-2.0 * ((A - 1.0) + (A + 1.0) * tcos));
                a2 = ((A + 1.0) + (A - 1.0) * tcos - beta * tsin);
            }

            // hishelf
            if (type == FilterType.HIGHSHELF)
            {
                b0 = (A * ((A + 1.0) + (A - 1.0) * tcos + beta * tsin));
                b1 = (-2.0 * A * ((A - 1.0) + (A + 1.0) * tcos));
                b2 = (A * ((A + 1.0) + (A - 1.0) * tcos - beta * tsin));
                a0 = ((A + 1.0) - (A - 1.0) * tcos + beta * tsin);
                a1 = (2.0 * ((A - 1.0) - (A + 1.0) * tcos));
                a2 = ((A + 1.0) - (A - 1.0) * tcos - beta * tsin);
            }
        }
        else
        {
            // other filters
            final double omega = 2.0 * temp_pi * frequency / sample_rate;
            final double tsin = Math.sin(omega);
            final double tcos = Math.cos(omega);

            if (q_is_bandwidth) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin);
            else
                alpha = tsin / (2.0 * q);

            // lowpass
            if (type == FilterType.LOWPASS)
            {
                b0 = (1.0 - tcos) / 2.0;
                b1 = 1.0 - tcos;
                b2 = (1.0 - tcos) / 2.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // hipass
            if (type == FilterType.HIGHPASS)
            {
                b0 = (1.0 + tcos) / 2.0;
                b1 = -(1.0 + tcos);
                b2 = (1.0 + tcos) / 2.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // bandpass csg
            if (type == FilterType.BANDPASS_SKIRT)
            {
                b0 = tsin / 2.0;
                b1 = 0.0;
                b2 = -tsin / 2;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // bandpass czpg
            if (type == FilterType.BANDPASS_PEAK)
            {
                b0 = alpha;
                b1 = 0.0;
                b2 = -alpha;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // notch
            if (type == FilterType.NOTCH)
            {
                b0 = 1.0;
                b1 = -2.0 * tcos;
                b2 = 1.0;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }

            // allpass
            if (type == FilterType.ALLPASS)
            {
                b0 = 1.0 - alpha;
                b1 = -2.0 * tcos;
                b2 = 1.0 + alpha;
                a0 = 1.0 + alpha;
                a1 = -2.0 * tcos;
                a2 = 1.0 - alpha;
            }
        }

        // set filter coeffs
        b0a0 = (b0 / a0);
        b1a0 = (b1 / a0);
        b2a0 = (b2 / a0);
        a1a0 = (a1 / a0);
        a2a0 = (a2 / a0);
    }
}

5 comments:

  1. Very Good Post thanks for Sharing information....
    SEO Training in Bangalore | SEO Course Fees | Best SEO Classes - Join SEO Training in Bangalore at i Digital Academy and learn how to increase your website Traffic by
    Google Certified Trainers with 100% Placements and affordable course fees. Book a Free Demo!

    ReplyDelete
  2. Seriously, I consider your blog is one amongst best blogs that I found. Your efforts awfully help make reading your blog considerably easier.

    Java Training in Chennai

    Java Course in Chennai

    ReplyDelete