//------------------------------------------------------------------------------
//  Parameters calculator class of buquad unit for graphic equalizer
//  グラフィックイコライザで使う biquad フィルタの係数を計算するクラス
//
//   2017/03/28, Copyright (c) 2017 MIKAMI, Naoki
//------------------------------------------------------------------------------

#ifndef GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP
#define GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP

#include "mbed.h"
#include "BiquadGrEq.hpp"

namespace Mikami
{
    class GrEqParams
    {
    public:
        // Constructor
        GrEqParams(int bands, float fs) : BANDS_(bands), FS_(fs) {}

        // 係数を計算する
        //      gDb : 利得（dB単位）
        BiquadGrEq::Coefs Execute(int band, float f0, float gDb, float qVal)
        {
            const float PI = 3.1415926536f;
            BiquadGrEq::Coefs coefs;
            
            float gSqrt = sqrtf(powf(10, gDb/20.0f));
            float w0 = 2.0f*PI*f0/FS_;
            
            if ( (band != 0) && (band != BANDS_-1) )    // ピーキングフィルタ
            {
                float alpha = sinf(w0)/(2.0f*qVal);
                float beta = 1.0f + alpha/gSqrt;
                coefs.a1 = 2.0f*cosf(w0)/beta;
                coefs.a2 = -(1.0f - alpha/gSqrt)/beta;
                coefs.b0 = (1.0f + alpha*gSqrt)/beta;
                coefs.b1 = -coefs.a1;
                coefs.b2 = (1.0f - alpha*gSqrt)/beta;
            }
            else                                        // シェルビングフィルタ
            {                                           // Q は固定
                w0 = (band == 0) ? w0*1.414f : w0/1.414f;
                float alpha = sinf(w0)/sqrtf(2.0f); // Q = 1/sqrt(2)
                float g_a = sqrtf(gSqrt);
                float cosW0 = cosf(w0);
                float gSqrtP1 = gSqrt+1.0f;
                float gSqrtM1 = gSqrt-1.0f;
                if (band == 0)      // ローシェルビング
                {                   
                    float beta = gSqrtP1 + gSqrtM1*cosW0
                               + 2.0f*g_a*alpha;
                    coefs.a1 = 2.0f*(gSqrtM1 + gSqrtP1*cosW0)/beta;
                    coefs.a2 = -(gSqrtP1 + gSqrtM1*cosW0
                               - 2.0f*g_a*alpha)/beta;
                    coefs.b0 = gSqrt*(gSqrtP1 - gSqrtM1*cosW0
                               + 2.0f*g_a*alpha)/beta;
                    coefs.b1 = 2.0f*gSqrt*(gSqrtM1
                               - gSqrtP1*cosW0)/beta;
                    coefs.b2 = gSqrt*(gSqrtP1 - gSqrtM1*cosW0
                               - 2.0f*g_a*alpha)/beta;
                }
                else                // ハイシェルビング
                {
                    float beta = gSqrtP1 - gSqrtM1*cosW0
                               + 2.0f*g_a*alpha;
                    coefs.a1 = -2.0f*(gSqrtM1 - gSqrtP1*cosW0)/beta;
                    coefs.a2 = -(gSqrtP1 - gSqrtM1*cosW0
                               - 2.0f*g_a*alpha)/beta;
                    coefs.b0 = gSqrt*(gSqrtP1 + gSqrtM1*cosW0
                               + 2.0f*g_a*alpha)/beta;
                    coefs.b1 = -2.0f*gSqrt*(gSqrtM1 + gSqrtP1*cosW0)/beta;
                    coefs.b2 = gSqrt*(gSqrtP1 + gSqrtM1*cosW0
                               - 2.0f*g_a*alpha)/beta;
                }
            }

            return coefs;
        }

    private:
        const int BANDS_;
        const float FS_;
    };
}
#endif  // GRAPHIC_EQALIZER_PARAMETER_CALCULATOR_HPP
