//--------------------------------------------------------------
//  MEMS マイクの入力に対して音響効果を与える
//      音響効果：残響生成，周波数シフト
//
//  2017/04/13, Copyright (c) 2017 MIKAMI, Naoki
//--------------------------------------------------------------

#ifndef REVERB_FRSHIFTER_HPP
#define REVERB_FRSHIFTER_HPP

#include "InitializeGUI.hpp"
#include "SAI_InOut.hpp"
#include "Reverberator.hpp"
#include "WeaverModulator.hpp"
#include "GuiChanger.hpp"
using namespace Mikami;

void ReverbFrShifter()
{
    const int FS = AUDIO_FREQUENCY_16K; // 標本化周波数: 16 kHz
    SaiIO mySai(SaiIO::BOTH, 256, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);

    ButtonGroup *onOff;     // "ON", "OFF"
    ButtonGroup *menu;      // "THROUGH", "REVERB", "F_SHIFTER"
    SeekBar *barReverb, *barFqCh;
    NumericLabel<int> *frqLabel;
    WaveformDisplay *displayIn, *displayOut;

    // GUI 部品の初期化
    InitializeGUI(onOff, menu, barReverb, barFqCh,
                  frqLabel, displayIn, displayOut);
    // 処理に応じて GUI 部品の状態を変更する関数の割り当て
    void (*fPtr[])(SeekBar*, SeekBar*, NumericLabel<int>*)
        = { SetThrough, SetReverb, SetFrqShifter };

    ProcessingBase through;     // 0: 信号処理なしで出力
    Reverberator reverb;        // 1: 残響生成
    WeaverMod shifter(FS, 100); // 2: 周波数シフト（シフトの初期値：100 Hz）
    ProcessingBase *func[3] = { &through, &reverb, &shifter };
    ResetButton reset;

    int runStop = 1;
    int menuNum = 0;

    // 入出力の波形表示で使用
    Array<int16_t> snIn(mySai.GetLength());
    Array<int16_t> snOut(mySai.GetLength());

    mySai.RecordIn();
    mySai.PlayOut();
    mySai.PauseOut();

    while (true)
    {
        // On/OFF の設定
        int num;
        if (onOff->GetTouchedNumber(num))
            if (runStop != num)
            {
                if (num == 0) mySai.ResumeOut();
                else          mySai.PauseOut();
                runStop = num;
            }

        // 信号処理の種類の切り替えに対応する GUI 部品の状態の設定
        if (menu->GetTouchedNumber(menuNum))
            fPtr[menuNum](barReverb, barFqCh, frqLabel);

        // 残響の長さを設定
        if ( (menuNum == 1) && (barReverb->Slide()) )
            reverb.SetDelay(6000 - barReverb->GetIntValue());

        // 周波数シフトの値の設定
        if ( (menuNum == 2) && (barFqCh->Slide()) )
        {
            frqLabel->Draw("+%d Hz", barFqCh->GetIntValue());
            shifter.SetFrequency(barFqCh->GetIntValue());
        }

        //---------------------------------------------
        // １ブロック分の信号処理を行い，その結果を出力する
        if ( mySai.IsCompleted())
        {
            for (int n=0; n<mySai.GetLength(); n++)
            {
                int16_t xL, xR;
                mySai.Input(xL, xR);
                int16_t xn = xL + xR;
                snIn[n] = xn;   // 表示用

                //-------------------------------------------------------
                // 信号処理実行
                int16_t yn = (int16_t)func[menuNum]->Execute((float)xn);
                //-------------------------------------------------------

                mySai.Output(yn, yn);   // 左右チャンネルに同じ信号を出力
                snOut[n] = yn;  // 表示用
            }

            displayIn->Execute(snIn);   // 入力波形の表示
            displayOut->Execute(snOut); // 出力波形の表示
        }
        // １ブロック分の信号処理はここまで
        //---------------------------------------------

        reset.DoIfTouched();    // リセットボタンがタッチされればメニューに戻る
    }
}
#endif  // REVERB_FRSHIFTER_HPP
