//-------------------------------------------------------------------
//  IIR フィルタを双１次 z 変換で設計し，その周波数特性を描画するためのクラス
//  
//  2017/03/27, Copyright (c) 2017 MIKAMI, Naoki
//-------------------------------------------------------------------

#include "BtwthDesignerDrawer.hpp"

namespace Mikami
{
    // Constructor
    BtwthDesignerDrawer::BtwthDesignerDrawer(
        uint16_t x0, uint16_t y0, float db1,
        int fs, int order, float fc,
        uint16_t fL, uint16_t fH, BilinearDesign::Type lpHp)
        : lcd_(GuiBase::GetLcd()),
          X0_(x0), Y0_(y0), ORDER_(order),
          CURSOR_Y0_(y0+1-db1*60), CURSOR_LENGTH_(db1*60-1),
          MIN_F_(fL), MAX_F_(fH),
          CURSOR_COLOR_(0xFFE000D0), CURSOR_TOUCHED_COLOR_(0xFFFF80FF),
          coefs_(order/2), ck_((Array<Biquad::Coefs>&)coefs_),
          drawerObj_(x0, 100.0f, 20000.0f, 140,
                     y0, -60, 0, db1, 10, fs),
          designObj_(order, fs),
          tp_(drawerObj_.X(MIN_F_), drawerObj_.X(MAX_F_), CURSOR_Y0_, y0),
          lblFrq_(x0+70, 38, "Cutoff frequency = %4d Hz")
    {
        // 双１次 z 変換による IIR フィルタの設計
        fC_ = fc;               // 最初に与える遮断周波数
        designObj_.Execute(fC_, lpHp, coefs_, g0_);
        frqResp_.SetParams(ORDER_, g0_, ck_);

        lp_ = lpHp;
        cursorRedraw_ = false;
    }

    // フィルタの再設計と周波数特性の再描画
    bool BtwthDesignerDrawer::ReDesignAndDraw(Biquad::Coefs ck[], float &g0,
                                         BilinearDesign::Type lpHp)
    {
        bool changed = (lpHp != lp_) ? true : false;
        bool tch = tp_.IsTouched(cursorX_, cursorX_);
        if (tch || changed)
        {
            int newFc = Frq10(drawerObj_.PosToFrq(cursorX_));
            newFc = (newFc > MAX_F_) ? MAX_F_ : newFc;
            if ((abs(newFc - fC_) >= 1) || changed)
            {
                fC_ = newFc;
                lblFrq_.Draw(newFc);
                designObj_.Execute(newFc, lpHp, coefs_, g0_);
                GetCoefficients(ck, g0);

                frqResp_.SetParams(ORDER_, g0_, ck_);
                drawerObj_.Erase();
                drawerObj_.DrawAxis();              // 目盛線の描画
                drawerObj_.DrawGraph(frqResp_);     // 周波数特性のグラフのカーブを描画する

                if (tch)    // カーソルの移動
                {
                    lcd_.SetTextColor(CURSOR_TOUCHED_COLOR_);
                    lcd_.DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
                    lcd_.DrawVLine(cursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_);
                    lcd_.DrawVLine(cursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_);
                }
                cursorRedraw_ = true;
                oldCursorX_ = cursorX_;
                lp_ = lpHp;
                return true;
            }
        }
        
        if (!tch && cursorRedraw_)   // カーソルを元の色に戻す
        {
            lcd_.SetTextColor(CURSOR_COLOR_);
            lcd_.DrawVLine(oldCursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
            lcd_.DrawVLine(oldCursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_);
            lcd_.DrawVLine(oldCursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_);
            cursorRedraw_ = false;
        }
        return false;
    }

    // 周波数特性の描画
    void BtwthDesignerDrawer::DrawResponse()
    {
        lblFrq_.Draw(fC_);
        drawerObj_.DrawAxis();             // 目盛線の描画
        FrqRespDrawer::AxisX_Char numX[] =  // 横軸の目盛値を描画する際に使う構造体の配列
            {{  100, "0.1"}, {  200, "0.2"}, {  500, "0.5"}, { 1000,  "1"},
             { 2000,   "2"}, { 5000,   "5"}, {10000,  "10"}, {20000, "20"}};
        drawerObj_.DrawNumericX(numX, 8, 6, "Frequency [kHz]");     // 横軸の目盛
        drawerObj_.DrawNumericY(-24, -6, 20, "%3d");                // 縦軸の目盛は 20 dB 間隔
        drawerObj_.DrawGraph(frqResp_);     // 周波数特性のカーブの描画

        cursorX_ = drawerObj_.X(fC_);
        lcd_.SetTextColor(CURSOR_COLOR_);
        lcd_.DrawVLine(cursorX_, CURSOR_Y0_, CURSOR_LENGTH_);
        lcd_.DrawVLine(cursorX_-1, CURSOR_Y0_, CURSOR_LENGTH_);
        lcd_.DrawVLine(cursorX_+1, CURSOR_Y0_, CURSOR_LENGTH_);
    }

    // フィルタ係数の取得
    void BtwthDesignerDrawer::GetCoefficients(Biquad::Coefs c[], float &g0)
    {
        for (int k=0; k<ORDER_/2; k++) c[k] = ck_[k];
        g0 = g0_;
    }
    
    // 周波数を 10, 20, 50, 100 Hz の倍数にする
    int BtwthDesignerDrawer::Frq10(float f)
    {
        if (f < 1000)
            return ((int)(f/10.0f + 0.5f))*10;
        if (f < 2000)
            return ((int)(f/20.0f + 0.5f))*20;
        if (f < 3000)
            return ((int)(f/50.0f + 0.5f))*50;           
        else
            return ((int)(f/100.0f + 0.5f))*100;
    }
}
