//
/* ----------------------------------------------------------------------------------------------
    pcm.java	パルス符号変調								ver. 1.00 (JDK 1.02)
    														ueyama@infonet.co.jp  1998.12.12
---------------------------------------------------------------------------------------------- */

import java.applet.Applet;
import java.awt.*;
import java.lang.Math;
import java.util.*;

public class pcm extends Applet implements Runnable
{
	int			i,j;
	int			Wait=1024;
	int			Ww,Wh;										// applet の幅と高さ
	int			Ebdx=260,Ebdy=260,Ebdh=30;					// Encode の2進数表示位置、サイズ
	int			Step=0;										// PCM Step
	int			Pitch=16;									// サンプリングピッチ(単位:Pixel)
	int			Q_bit=16;									// 量子化ビット数    (単位:Pixel)
	int			Fn=5;										// 2進数桁数
	int 		Ac=100;										// double を int で 1/100 まで表示
	int			Qp=4;										// Pitch / 4
	int			R1=0,R2=0;									// mouse で select された 角度(r)
	int			Q0=0;										// 標本化値
	int			Dr=0;										// 符号化の表示角度
	int			Cx=32;										// コメント表示 X 座標値
	boolean		Run=false;									// t: 符号化  f: その他
	boolean		Rf=true;									// t: random wave   f: sin wave
	int			Mx=0;										// マウス X 座標の Pitch 整数倍値
	int			Wf[]=new int[361];
	double		Wa[]=new double[16];
	Color		col[]={new Color(170,170,96),/*波形色*/   new Color(224,192,128),/*標本化色*/
					   new Color(144,112,48),/*量子化色*/ new Color(192,160,96), /*標本化選択色*/
					   new Color(96,64,16),  /*量子化選択色*/};
	Button		bt_h_fine, bt_h_rough, bt_v_fine, bt_v_rough, bt_sin, bt_random, bt_clear, bt_step;
	Button		bt_slow, bt_fast;
	Graphics	gr;
	Image		Comm;										// 文字表示用  (pcm.gif)
	Thread		th=null;
	
	public void start()
	{
		if(th==null)
		{
			th=new Thread(this);
			th.start();
		}
	}
	
	public void init()
	{
		Ww=size().width; Wh=size().height;
		setBackground(new Color(247,255,247));					// 背景色
		gr=getGraphics();
		
		MediaTracker mt=new MediaTracker(this);
		Comm=getImage(getCodeBase(),"pcm.gif");
		mt.addImage(Comm, 0);
		try
		{
			mt.waitForID(0);
		}
		catch(InterruptedException e){};
		
		Panel p=new Panel();
		p.add(bt_slow	=new Button("<<"));
		p.add(bt_fast	=new Button(">>"));
		p.add(bt_h_rough=new Button("H Rough"));
		p.add(bt_h_fine	=new Button("H Fine"));
		p.add(bt_v_rough=new Button("V Rough"));
		p.add(bt_v_fine	=new Button("V Fine"));
		p.add(bt_sin	=new Button("SIN Wave"));
		p.add(bt_random	=new Button("RND Wave"));
		p.add(bt_clear	=new Button("CLEAR"));
		p.add(bt_step	=new Button("STEP"));
		setLayout(new BorderLayout());
		add("South",p);
		Wa[0]=1.0;
		new_wave();
	}
	
	public void new_wave()										// 新規波形の発生
	{
		int		max=0;
		double	a,e,s,v;
		Random	r=new Random();
		
		e=(Rf)?0.333:0.0;										// SIN 波形の場合は高調波振幅=0
		for(i=1;i<16;i++)										// 高調波の振幅比を乱数で決める
		{
			s =r.nextDouble();
			Wa[i]=r.nextDouble()*e;
			Wa[i]*=(s<0.5)?1.0:-1.0;
			e*=0.81;
		}
		for(i=0;i<360;i++)										// 各角度の振幅値を計算する
		{
			a=(double)i*3.14159/180; v=0.0;
			for(j=0;j<16;j++) v+=Wa[j]*Math.sin(a*(double)(j+1))*128*Ac;
			Wf[i]=(int)v;
			if(Wf[i]>max) max=Wf[i];
		}
		for(i=0;i<360;i++) {Wf[i]*=120*Ac; Wf[i]/=max; Wf[i]+=128*Ac;}
	}
	
	public void draw_wave()											// 波形表示
	{
		int r;
		gr.setColor(col[0]);
		for(r=0;r<720-1;r++)
		{
			if(Step>0)  gr.drawLine(r,256-py(r),r+1,256-py(r+1));
			else
			{
				for(i=-1;i<2;i++) for(j=-1;j<2;j++) gr.drawLine(r+i,256-py(r)+j,r+1+i,256-py(r+1)+j);
			}
		}
	}
	
	public int py(int a)											// 角度 a における y 座標値
	{
		return Wf[a%360]/Ac;
	}
	
	public void dsp_comm(int x, int n, int l)						// コメントの表示
	{													// n=0:原波形 1:標本化 2:量子化 3:符号化
		Graphics	gx=gr.create();
		gx.clipRect(x,262,23*l,22);
		gx.clearRect(x,262,23*l,22);
		gx.drawImage(Comm,x-n*92,262,this);
		gx.dispose();
	}
	
	public void dsp_n(int n)										// 数値の表示
	{
		Graphics	gx=gr.create();
		gx.clipRect(Cx,262,18,22);
		gx.clearRect(Cx,262,18,22);
		gx.drawImage(Comm,Cx-(368+n*18),262,this);
		gx.dispose();
		Cx+=(n==10)? 8:18;
	}
	
	public int dsp_bq(int r, int c)									// 量子化グラフの表示
	{
		int	p=(py(r)%Q_bit+Q_bit/2)/Q_bit*Q_bit;
		int	q=py(r)/Q_bit*Q_bit+p;
		gr.setColor(col[c]);
		gr.fillRect(r-Qp,256-q, Qp*2+1,q);
		return q;
	}
	
	public void dsp_b(int x, int y, int c, boolean f)				// 棒グラフの表示
	{
		gr.setColor(col[c]);
		if(f) gr.fillRect(x-Qp,256-y, Qp*2+1,y);
	}
	
	public void paint(Graphics g)
	{
		int		p,q,r,x,y;
		
		g.clearRect(0,0,Ww,Wh);
		g.setColor(new Color(224,224,192));							// 格子を描く
		for(i=1;i<=256/Q_bit;i++) g.drawLine(0,i*Q_bit, Ww,i*Q_bit);
		for(r=0;r<720;r+=Pitch)   g.drawLine(r,256, r,0);
		if(Step>0) for(r=0;r<720;r+=Pitch) dsp_b(r,py(r),1,true);	// 標本化
		if(Step>1) for(r=0;r<720;r+=Pitch) dsp_bq(r,2);			// 量子化
		if(Step<3) dsp_comm(32,Step,3);
		draw_wave();
	}
	
	public void run()
	{
		while(th!=null)
		{
			if(Run) dsp_e();
			try
			{
				th.sleep(Wait);
			}
			catch (InterruptedException e){}
			if(Run)
			{
				Dr+=Pitch;
				if(Dr>=720) Dr=0;
			}
		}
	}
	
	public void dsp_s(int n)										// 標本化値表示
	{
		int r,y;
		String	rm;
		
		y=Wf[n%360]; y*=100; y/=256;
		rm=y/Ac+"."+((y%Ac<10)?"0":"")+y%Ac;
		dsp_comm(32,1,4);
		for(Cx=140,r=0; r0) draw_wave();
			}
			Mx=r;
		}
		return true;
	}
	
	public boolean action(Event e, Object o)
	{
		boolean rpf=true;
		
		if(e.target==bt_slow)
		{
			Wait*=2; bt_fast.enable(); rpf=false;
			if(Wait==8192) bt_slow.disable();
			showStatus("wait: "+(float)Wait/1024.0+"sec.");
		}
		else if(e.target==bt_fast)
		{
			Wait/=2; bt_slow.enable(); rpf=false;
			if(Wait==32) bt_fast.disable();
			showStatus("wait: "+(float)Wait/1024.0+"sec.");
		}
		else if(e.target==bt_h_rough)
		{
			Pitch*=2; bt_h_fine.enable();
			if(Pitch==64) bt_h_rough.disable();
		}
		else if(e.target==bt_h_fine && Pitch>4)
		{
			Pitch/=2; bt_h_rough.enable();
			if(Pitch==4) bt_h_fine.disable();
		}
		else if(e.target==bt_v_rough)
		{
			Q_bit*=2; Fn--; bt_v_fine.enable();
			if(Q_bit==64) bt_v_rough.disable();
		}
		else if(e.target==bt_v_fine)
		{
			Q_bit/=2; Fn++;  bt_v_rough.enable();
			if(Q_bit==4) bt_v_fine.disable();
		}
		else if(e.target==bt_sin)
		{
			Rf=false; Dr=0; new_wave();
		}
		else if(e.target==bt_random)
		{
			Rf=true; Dr=0; new_wave();
		}
		else if(e.target==bt_clear)
		{
			Step=0; Dr=0; bt_step.enable(); Run=false; R1=0; R2=0;
		}
		else if(e.target==bt_step)
		{
			Step++;
			if(Step==3)
			{
				Run=true;
				bt_step.disable();
			}
			else
			{
				gr.clearRect(0,Ebdy,Ww,Ebdh);
				dsp_comm(32,Step,3);
			}
		}
		Qp=Pitch/4;
		if(rpf) repaint();
		return true;
	}
	
	public void stop()
	{
		if(th!=null)
		{
			th.stop();
			th=null;
		}
	}
}
//
戻る