//--------------------------------------------------------------
//	リアルタイム・スペクトル・アナライザで使うメソッド
//
//		作成者：三上直樹，2022/02/18 作成，©三上直樹 2022
//--------------------------------------------------------------

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

namespace CQ_FFT_Analyzer
{
	public partial class Form1 : Form
	{
		// 座標軸などの描画
		private void DrawAxis(Graphics gr)
		{
			Font myFont = new Font("Meiryo UI", 9);

			// スペクトル１次元表示の座標軸
			int pBoxH = pictureBox1.Size.Height;
			int pBoxW = pictureBox1.Size.Width;
			gr.TranslateTransform(pictureBox1.Location.X,
								  pictureBox1.Location.Y + pBoxH);

			// 枠の描画
			Rectangle rect = new Rectangle(new Point(0, -pBoxH), pictureBox1.Size);
			gr.FillRectangle(Brushes.White, rect);
			gr.DrawRectangle(new Pen(textColor_), rect);

			Pen penDash = new Pen(Color.Gray) { DashStyle = DashStyle.Dash };
			// 座標軸の描画（横）
			float divX = 10.0f;
			float dx = pBoxW/divX;
			for (int n=1; n<(int)divX; n++)
				gr.DrawLine(penDash, n*dx, 0, n*dx, -pBoxH);
			labels_[0].Text ="0";
			for (int n=1; n<=5; n++)
				labels_[n].Text = ((double)n).ToString("0.0");

			// 座標軸の描画（縦）
			float divY = 8.0f;
			float dy = pBoxH/divY;
			for (int n=1; n<(int)divY; n++)
				gr.DrawLine(penDash, 0, -n*dy, pBoxW, -n*dy);

			SolidBrush myBrush = new SolidBrush(textColor_);
			gr.RotateTransform(-90);
			gr.DrawString("相対強度 [dB]", myFont, myBrush, 80, -44);
			gr.ResetTransform();
		}

		// スペクトル描画のための処理
		private void DrawSpectrum()
		{
			nData_ = rxData_.Length/2;

			// 表示用バッファの更新
			for (int n=0; n<nData_; n++)
				xn_[n] = Decode(rxData_.Substring(2*n, 2));

			if (nAvr_ == 1)		// 平均を行わない場合
				for (int n=0; n<nData_; n++)
				{
					float y = B0_*xn_[n] + A1_*yn_[n];
					if (peakHold_) y = (xn_[n] > yn_[n]) ? xn_[n] : y;
					yn_[n] = y;
					pYn_[n] = new PointF(dx_*n, ToY(y));
				}
			else				// 平均を行う場合
			{
				int m = (index_ - nAvr_) & MASK_;
				for (int k=0; k<nData_; k++)
				{
					yn_[k] = 0.99999f*yn_[k] + xn_[k] - xnM_[k, m];	// 巡回形で計算
					pYn_[k] = new PointF(dx_*k, ToY(yn_[k]/nAvr_));
					xnM_[k, index_] = xn_[k];
				}
				index_ = (++index_) & MASK_;

				if (++count_ > nAvr_) count_ = nAvr_;
				Invoke(() => label14.Text = count_.ToString() );
			}

			pictureBox1.Invalidate();	// スペクトル描画の指令
			if (readOk_) RequestXfer();	// データ転送要求を送信
		}

		// 0 ～ 10,000 の範囲の数を 2 文字で表したコードを float 型に変換する
		// 10,000 を 1.0f に対応させる
		private float Decode(string s)
		{
			uint x = (((uint)s[0] - 0x10) << 7) | ((uint)s[1] - 0x10);
			#if DEBUG
				if (x > 10000) MessageBox.Show(x.ToString());
			#endif
			return x/10000.0f;
		}

		// 表示の際の縦方向の値に変換
		private float ToY(float x)
		{
			float db = (x > 0) ? (float)(20.0*Math.Log10(x) + offset_) : -100;
			return orgY_ - db*yScale_;
		}

		// データの転送を要求する
		private void RequestXfer() => sp_.SendTo("GO");

		// 別のスレッドを使う場合に使用
		private void Invoke(Action action) => base.Invoke(action);
	}
}
