//----------------------------------------------------------------------
//  グラフィック･イコライザ，DA 出力はアップサンプリング使用
//      フィルタの係数の計算をマイコン側でも行うタイプ
//
//  PC 側のプログラム： グラフィックイコライザ.exe
//
//  2023/01/17, Copyright (c) 2023 MIKAMI, Naoki
//----------------------------------------------------------------------

#include "MultirateLiPh.hpp"    // DA でアップサンプリング
#include "SerialRxTxIntr.hpp"
#include "GraphicEqualizer.hpp"
#include <cctype>       // isalpha(), isdigit() で使用
using namespace Mikami;

const float FS_ = 44.1f;        // 入力の標本化周波数： 44.1 kHz
MultirateLiPh myAdDa_(FS_);     // 出力標本化周波数を４倍にするオブジェクト

const int BANDS_ = 9;           // グラフィック･イコライザのバンド数
GrEqualizer grEq_(BANDS_, FS_*1000);    // グラフィック･イコライザ用オブジェクト

void Select(string str);        // 有効，無効，平坦化に対応する処理の選択
void NumericCtrl(string str);   // 帯域ごとの利得調整

// グラフィック･イコライザの信号処理
void AdcIsr()
{
    float xn = myAdDa_.Input();     // 入力
    float yn = grEq_.Execute(xn);   // グラフィック･イコライザの処理
    myAdDa_.Output(yn);             // 出力
}

int main()
{
    SerialRxTxIntr com;                 // PC との通信用，9600 baud
    NVIC_SetPriority(USART2_IRQn, 2);   // シリアルポートの割り込み順位設定

    myAdDa_.Start(&AdcIsr); // 標本化を開始する
    while (com.WaitGetBuffer() != "GrEq") {}
    com.TxString("ACK\n");      // "ACK" を送り返す

    // PC からの指令に対応する処理
    while (true)
    {
        string str = com.WaitGetBuffer();
        if (isalpha(str[0])) Select(str);
        if (isdigit(str[0])) NumericCtrl(str);
        // 第1文字がアルファベットでも数字でもない場合は何もしない
    }
}

// 有効，無効，平坦化に対応する処理の選択
void Select(string str)
{
    if (str == "ACTIVE") grEq_.Validate();      // フィルタ処理有効
    if (str == "THROUGH") grEq_.Invalidate();   // フィルタ処理無効
    if (str == "FLAT") grEq_.Flatten();         // フィルタ特性の平坦化
}

// 帯域ごとの利得調整
void NumericCtrl(string str)
{
    // 最初の文字はフィルタの番号
    int k = atoi(str.substr(0, 1).c_str());     // フィルタの番号
    // 次の文字からは dB 値
    grEq_.SetGain(atof(str.substr(1).c_str()), k);
}
