#ifndef _FILTERS_H_
#define _FILTERS_H_
#define NCoef 2

//fc=350Hz
static inline float low_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.00049713569693400649,
        0.00099427139386801299,
        0.00049713569693400649
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.93522955470669530000,
        0.93726236021404663000
    };

    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];

    return y[i][0];
}

//fc=350Hz
static inline float low_cut_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.96839970114733542000,
        -1.93679940229467080000,
        0.96839970114733542000
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.93522955471202770000,
        0.93726236021916731000
    };

    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];

    return y[i][0];
}

//fc=3.5kHz
static inline float high_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.72248704753064896000,
        -1.44497409506129790000,
        0.72248704753064896000
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.36640781670578510000,
        0.52352474706139873000
    };
    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];

    return y[i][0];
}

//fc=3.5kHz
static inline float high_cut_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.03927726802250377400,
        0.07855453604500754700,
        0.03927726802250377400
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.36640781666419950000,
        0.52352474703279628000
    };
    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];

    return y[i][0];
}


#undef NCoef
#define NCoef 2

//fc=3.2kHz
static inline float sb_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.03356837051492005100,
        0.06713674102984010200,
        0.03356837051492005100
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.41898265221812010000,
        0.55326988968868285000
    };
    
/*    float ACoef[NCoef+1] = {
        0.17529642630084405000,
        0.17529642630084405000
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -0.64940759319751051000
    };*/
    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];

    return y[i][0];
}



#undef NCoef
#define NCoef 2

//fc=150Hz
static inline float adgold_highpass_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.98657437157334349000,
        -1.97314874314668700000,
        0.98657437157334349000
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.97223372919758360000,
        0.97261396931534050000
    };

    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
    
    return y[i][0];
}

//fc=150Hz
static inline float adgold_lowpass_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.00009159473951071446,
        0.00018318947902142891,
        0.00009159473951071446
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.97223372919526560000,
        0.97261396931306277000
    };

    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
    
    return y[i][0];
}

//fc=56Hz
static inline float adgold_pseudo_stereo_iir(float NewSample) {
    float ACoef[NCoef+1] = {
        0.00001409030866231767,
        0.00002818061732463533,
        0.00001409030866231767
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.98733021473466760000,
        0.98738361004063568000
    };

    static float y[NCoef+1]; //output samples
    static float x[NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[n] = x[n-1];
       y[n] = y[n-1];
    }

    //Calculate the new output
    x[0] = NewSample;
    y[0] = ACoef[0] * x[0];
    for(n=1; n<=NCoef; n++)
        y[0] += ACoef[n] * x[n] - BCoef[n] * y[n];
    
    return y[0];
}

//fc=3.2kHz - probably incorrect
static inline float dss_iir(float NewSample) {
    float ACoef[NCoef+1] = {
        0.03356837051492005100,
        0.06713674102984010200,
        0.03356837051492005100
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -1.41898265221812010000,
        0.55326988968868285000
    };
    
    static float y[NCoef+1]; //output samples
    static float x[NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[n] = x[n-1];
       y[n] = y[n-1];
    }

    //Calculate the new output
    x[0] = NewSample;
    y[0] = ACoef[0] * x[0];
    for(n=1; n<=NCoef; n++)
        y[0] += ACoef[n] * x[n] - BCoef[n] * y[n];

    return y[0];
}

#undef NCoef
#define NCoef 1
/*Basic high pass to remove DC bias. fc=10Hz*/
static inline float dac_iir(int i, float NewSample) {
    float ACoef[NCoef+1] = {
        0.99901119820285345000,
        -0.99901119820285345000
    };

    float BCoef[NCoef+1] = {
        1.00000000000000000000,
        -0.99869185905052738000
    };

    static float y[2][NCoef+1]; //output samples
    static float x[2][NCoef+1]; //input samples
    int n;

    //shift the old samples
    for(n=NCoef; n>0; n--) {
       x[i][n] = x[i][n-1];
       y[i][n] = y[i][n-1];
    }

    //Calculate the new output
    x[i][0] = NewSample;
    y[i][0] = ACoef[0] * x[i][0];
    for(n=1; n<=NCoef; n++)
        y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n];
    
    return y[i][0];
}


#define SB16_NCoef 51

extern float low_fir_sb16_coef[SB16_NCoef];

static inline float low_fir_sb16(int i, float NewSample)
{
        static float x[2][SB16_NCoef+1]; //input samples
        static int pos = 0;
        float out = 0.0;
        int n;

        //Calculate the new output
        x[i][pos] = NewSample;

        for (n = 0; n < ((SB16_NCoef+1)-pos) && n < SB16_NCoef; n++)
                out += low_fir_sb16_coef[n] * x[i][n+pos];
        for (; n < SB16_NCoef; n++)
                out += low_fir_sb16_coef[n] * x[i][(n+pos) - (SB16_NCoef+1)];

        if (i == 1)
        {
                pos++;
                if (pos > SB16_NCoef)
                        pos = 0;
        }
                        
        return out;
}


#endif /* _FILTERS_H_ */
