//---------------------------------------------------------------------
//	グラフィック･イコライザ
//
//	マイコン側のプログラム： 	DSP_GraphicEqualizer
//		ボーレート：9600 baud
//
//		作成者：三上直樹，2022/12/17 作成，©三上直樹 2022
//---------------------------------------------------------------------

using System;
using System.Drawing;
using System.Windows.Forms;

using System.IO.Ports;

using Mikami.Application;

namespace グラフィックイコライザ
{
	public partial class Form1 : Form
	{
		private const float F_LOWEST_  = 50.0f;		// 遮断周波数の最小値
		private const float F_HIGHEST_ = 20000.0f;	// 遮断周波数の最大値
		private const float	SAMPLING_FRQ_ = 44100;	// 標本化周波数, 44.1 kHz
		private const int	BANDS_ = 9;				// フィルタ数
		private const double F0_MIN_ = 62.5;		// 中心周波数の最小値
		private const double Q_VAL_ = 1.0/1.414214;	// 1.0/Sqrt(2);

		private readonly BiquadGrEq[] filters_ = new BiquadGrEq[BANDS_];
		private readonly TrackBar[] bar_ = new TrackBar[BANDS_];

		// シリアルポートと関連して使うクラスのオブジェクト
		private readonly MySerialPort sp_;
		// COM ポートの自動選択で使うクラスのオブジェクト
		private readonly AutoSelect comAuto_;
		// 周波数特性を描画するクラスのオブジェクト
		private readonly FrqResponsePlotter plotter_;

		private bool paintOk_ = false;

		public Form1()
		{
			InitializeComponent();

			sp_ = new MySerialPort(serialPort1);
			comAuto_ = new AutoSelect("GrEq", sp_, toolStripLabel1);

			GrEqDefinition();	// グラフィック･イコライザで使うフィルタの定義
			TrackBarGerator();	// TrackBar 生成

			plotter_ = new FrqResponsePlotter(
						   pictureBox1,		// 表示される PictureBox
						   F_LOWEST_,		// 100 Hz から表示
						   F_HIGHEST_,		// 20 kHz まで表示
						   -24,				// -24 dB から表示
						   24,				// 24 dB まで表示
						   SAMPLING_FRQ_);	// 標本化周波数

			panel1.Enabled = false;
		}

		// フラットな周波数特性に戻す
		private void button1_Click(object sender, EventArgs e)
		{
			for (int n=0; n<BANDS_; n++)
				filters_[n].SetCoefficients(0.0);
			pictureBox1.Invalidate();
			for (int n=0; n<BANDS_; n++) bar_[n].Value = 0;
			sp_.SendTo("FLAT");
		}

		// フィルタ処理を有効/無効にする
		private void radioButton1_Click(object sender, EventArgs e)
		{
			if ((RadioButton)sender == radioButton1) sp_.SendTo("ACTIVE");
			else									 sp_.SendTo("THROUGH");
		}

		// 目盛値，軸のタイトルの描画
		private void Form1_Paint(object sender, PaintEventArgs e)
		{
			plotter_.DrawCharacters(e.Graphics);
		}

		// 周波数特性のカーブ，グラフの目盛線などの描画
		private void pictureBox1_Paint(object sender, PaintEventArgs e)
		{
			plotter_.DrawAxis(e.Graphics);	// 目盛線の描画
			if (!paintOk_) return;

			plotter_.DrawCurve(e.Graphics, Pens.Blue, GetResponseAll);
		}

		// データ受信イベントに対応するハンドラ
		private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
		{
			if (!sp_.IsOpen) return;

			string data = sp_.ReadLine();
			if (data == "ACK")
			{
				comAuto_.StopTimer();
				toolStripLabel1.Text = "マイコン側の準備ができました．";
				toolStripLabel2.Text = " " + sp_.PortName + " ";
				Invoke(() => panel1.Enabled = true);
				foreach(var tb in bar_) Invoke(() => tb.Enabled = true);
				Invoke(() => radioButton1.Checked = true);
				paintOk_ = true;
				Invoke(() => pictureBox1.Invalidate());
				sp_.SendTo("ACTIVE");		// フィルタ処理を有効にする指令
			}
		}

		// 終了時の確認
		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			ClosingCancel.Ok(sp_, e);
		}
	}
}
