//------------------------------------------------
//  リアルタイムスペクトログラム
//      入力： MEMS マイク
//
//  2017/04/13, Copyright (c) 2017 MIKAMI, Naoki
//------------------------------------------------

#ifndef F746_SPECTRUMANALYZER_MAIN
#define F746_SPECTRUMANALYZER_MAIN

#include "SAI_InOut.hpp"
#include "F746_GUI.hpp"
#include "MethodCollection.hpp"

#include "Matrix.hpp"

using namespace Mikami;

void Spectrogram()
{
    const int FS = AUDIO_FREQUENCY_16K; // 標本化周波数：　16 kHz
    const int N_FFT = 512;              // FFT の点数
    const float FRAME = (N_FFT/(float)FS)*1000.0f;  // 1 フレームに対応する時間（単位：ms）

    const int X0    = 40;           // 表示領域の x 座標の原点
    const int Y0    = 200;          // 表示領域の y 座標の原点
    const int H0    = 160;          // 表示する際の周波数軸の長さ（5 kHz に対応）
    const uint16_t PX_1KHZ = H0/5;  // 1 kHz に対応するピクセル数
    const int W0    = 360;          // 横方向の全体の表示の幅（単位：ピクセル）
    const int H_BAR = 2;            // 表示する際の 1 フレームに対応する横方向のピクセル数
    const int SIZE_X = W0/H_BAR;
    const uint16_t MS100 = 100*H_BAR/FRAME; // 100 ms に対応するピクセル数
    const uint32_t AXIS_COLOR = LCD_COLOR_WHITE;//0xFFCCFFFF;
    
    Matrix<uint32_t> spectra(SIZE_X, H0+1, GuiBase::ENUM_BACK);

    SaiIO mySai(SaiIO::INPUT, N_FFT+1, FS,
                INPUT_DEVICE_DIGITAL_MICROPHONE_2);

    LCD_DISCO_F746NG &lcd = GuiBase::GetLcd();  // LCD 表示器のオブジェクトの参照
    lcd.Clear(GuiBase::ENUM_BACK);
    Label myLabel1(240, 2, "Real-time spectrogram", Label::CENTER, Font16);

    // ButtonGroup の設定
    const uint16_t B_W = 50;
    const uint16_t B_Y = 242;
    const uint16_t B_H = 30;
    const string RUN_STOP[2] = {"RUN", "STOP"};
    ButtonGroup runStop(325, B_Y, B_W, B_H, 2, RUN_STOP, 0, 0, 2, 1);
    
    Button clear(430, B_Y, B_W, B_H, "CLEAR");
    clear.Inactivate();
    // ButtonGroup の設定（ここまで）
    
    ResetButton reset;  // リセット･ボタンを使う

    // 座標軸
    DrawAxis(X0, Y0, W0, H0, AXIS_COLOR, MS100, PX_1KHZ, lcd);

    Array<float> sn(N_FFT+1);
    Array<float> db(N_FFT/2+1);

    // 色と dB の関係の表示
    ColorDb(Y0, AXIS_COLOR, lcd);
        
    FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT);

    // ループ内で使う変数の初期化
    int stop = 1;       // 0: run, 1: stop

    while(!runStop.GetTouchedNumber(stop)) { reset.DoIfTouched(); }
    reset.Draw();
    // データ読み込み開始
    mySai.RecordIn();
    
    while (true)
    {
        runStop.GetTouchedNumber(stop);

        if (stop == 0)
        {
            clear.Inactivate();
            if (mySai.IsCaptured())
            {
                // １ブロック分の信号の入力
                for (int n=0; n<mySai.GetLength(); n++)
                {
                    int16_t xL, xR;
                    mySai.Input(xL, xR);
                    sn[n] = (float)xL;
                }

                // スペクトルの更新
                SpectrumUpdate(spectra, fftAnalyzer, sn, db);
                // スペクトルの表示
                DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
            }
        }
        else
        {
            if (!clear.IsActive()) clear.Activate();
            if (clear.Touched())
            {
                spectra.Fill(GuiBase::ENUM_BACK);   // スペクトルの表示をクリア
                DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
                clear.Draw();
            }
        }
        reset.DoIfTouched();    // リセットボタンがタッチされればメニューに戻る
    }
}
#endif  // F746_SPECTRUMANALYZER_MAIN
