package fft; import java.awt.*; import java.awt.event.*; import java.applet.*; /** *

タイトル:

*

説明:

*

著作権: Copyright (c) 2003

*

会社名:

* @author 未入力 * @version 1.0 */ public class Applet1 extends Applet implements ItemListener, AdjustmentListener { private boolean isStandalone = false; private Scrollbar scr1, scr2, scr3, scr4; private CheckboxGroup cgC; private Checkbox [] cbCh; private CheckboxGroup cgD; private Checkbox cboxO, cboxF; private Choice w_choice, s_choice; //引数値の取得 public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } //アプレットのビルド public Applet1() { } //アプレットの初期化 public void init() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } finit(); } //コンポーネントの初期化 private void jbInit() throws Exception { } //アプレットの情報取得 public String getAppletInfo() { return "アプレット情報"; } //引数情報の取得 public String[][] getParameterInfo() { return null; } int n = 10; // 2^n int N = (int)Math.pow(2,n); // Scale int FO = 2; // 1-fft 2-osc int Csw = 2; // 0-ch1 1-ch2 2-add int Wsw = 0; // 0-sin 1-square 2-harp 3-piano int SP; // striking point double L = 40.0; // string length double Psl; // Math.PI*SP/L double Z; double [] sin_tbl; double [] cos_tbl; double [] b_re; double [] b_im; double [] re; double [] im; double [] dat; final String [] Wave = {"Saw","Square"}; final String [] Samp = {"8","9","10","11"}; final String [] Chan = {"Ch1","Ch2","Add"}; public void finit() { setFont(new Font("SansSerif", Font.PLAIN, 12)); setBackground(Color.lightGray); setLayout(new BorderLayout()); Panel p = new Panel(); Panel q = new Panel(); p.setLayout(new GridLayout(2,4,0,0)); q.setLayout(new FlowLayout()); scr3 = new Scrollbar(Scrollbar.HORIZONTAL,1,2,1,10); // partial p.add(scr3); p.add(new Label("Partial")); scr3.setBlockIncrement(2); scr3.addAdjustmentListener(this); scr1 = new Scrollbar(Scrollbar.HORIZONTAL,10,10,0,100); // Ch1 p.add(scr1); p.add(new Label("Ch 1")); scr1.setBlockIncrement(10); scr1.addAdjustmentListener(this); scr4 = new Scrollbar(Scrollbar.HORIZONTAL,4,1,0,11); // volume p.add(scr4); p.add(new Label("Level")); scr4.setBlockIncrement(2); scr4.addAdjustmentListener(this); scr2 = new Scrollbar(Scrollbar.HORIZONTAL,20,10,0,100); // Ch2 p.add(scr2); p.add(new Label("Ch 2")); scr2.setBlockIncrement(10); scr2.addAdjustmentListener(this); cgC = new CheckboxGroup(); cbCh = new Checkbox[Chan.length]; for (int i = 0; i < Chan.length; i++) { boolean sw = (i == 2) ? true : false; cbCh[i] = new Checkbox(Chan[i], sw, cgC); q.add(cbCh[i]); cbCh[i].addItemListener(this); } //データ数選択メニュー s_choice = new Choice(); for (int i = 0; i < Samp.length; i++) { s_choice.addItem(Samp[i]); } q.add(s_choice); s_choice.select(2); s_choice.addItemListener(this); cgD = new CheckboxGroup(); cboxO = new Checkbox("OSC", true, cgD); cboxF = new Checkbox("FFT", false, cgD); q.add(cboxO); q.add(cboxF); cboxO.addItemListener(this); cboxF.addItemListener(this); //波形メニュー w_choice = new Choice(); for (int i = 0; i < Wave.length; i++) { w_choice.addItem(Wave[i]); } q.add(w_choice); w_choice.addItemListener(this); add(p,"South"); add(q,"North"); } public void start() { ini(); } public void adjustmentValueChanged(AdjustmentEvent e) { repaint(); } //ボタン切り替え処理 public void itemStateChanged(ItemEvent e) { if (cboxF.getState()) // osc/fft切り替え FO = 1; else if (cboxO.getState()) FO = 2; for (int i = 0; i < Chan.length; i++) { // ch1/2/add切り替え if (cbCh[i].getState() ) Csw = i; } if (e.getSource() == s_choice) { // 8/9/10/11 データ数 String st = s_choice.getSelectedItem(); n = Integer.parseInt(st); N = (int)Math.pow(2,n); } if (e.getSource() == w_choice) { // sin/square?? Wsw = w_choice.getSelectedIndex(); } repaint(); } //波形データの生成 private double sinq(double f, int p) { if (Wsw == 0) { // sin wave return(Math.sin(p*f)/(p*Math.PI)); } else if (Wsw == 1) { // square wave 倍音を加えて合成 p--; return((1.0/Math.PI)*Math.sin((2*p+1)*f )/(2*p+1)); } else if (Wsw == 2) { // harp return(Math.sin(p*f)* Math.abs(Z*Math.sin(p*Psl)/Math.pow(p*Math.PI,2))); } else { // piano return(Math.sin(p*f)* Math.abs(2*Math.sin(p*Psl)/(p*Math.PI))); } } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { int sw = getSize().width; int sh = getSize().height; int hw = sw/2; int hh = sh/2; double xd = sw*2.0/N; int s0 = sh-100; int m1; int baion = scr3.getValue(); int scale = scr4.getValue(); int f1 = scr1.getValue(); int f2 = scr2.getValue(); //SP = scr5.getValue(); SP=0; Z = Math.pow(L, 2)/(double)(SP*(L-SP));//Lは弦の長さ ini();//関数表、FFt配列 g.setColor(Color.black); g.fillRect(0, 0, sw, sh); double xi = 2.0*Math.PI/(double)N; Psl = Math.PI*SP/L; for (int i = 0; i < N; i++){ double x1 = xi*i; for (int p = 1; p <= baion; p++) { if (Csw == 0) { // ch1 re[i] += sinq(f1*x1, p);//ch1の波形配列のi番目の値(倍音p) } else if (Csw == 1) { // ch2 re[i] += sinq(f2*x1, p); } else { // add re[i] += (sinq(f1*x1, p) + sinq(f2*x1, p)); } } im[i] = re[i]; } switch(FO) { case 1: //-------- fft double mxd = scale*10.0; int s1 = 2; fft_main(); // fft_bit(); // fft_amp(); // g.setColor(Color.gray); g.drawLine(0, s0+s1, sw, s0+s1); int sx = s0/12; for (int i = 0; i < 12; i++) { int sxi = s0-sx*i; g.setColor(Color.blue); g.drawLine(0, sxi, sw-1, sxi); g.setColor(Color.pink); g.drawString(i+"", sw-18, sxi); } for (int i = 0; i < N/2; i++) { int ixd = (int)(i * xd); //目盛りの表示 g.setColor(Color.orange); m1 = (i%10 == 0) ? 5 : 2; if(i %50==0) m1=10; g.drawLine(ixd, s0+m1, ixd, s0+s1); //FFTの値を表示 g.setColor(Color.green); g.drawLine(ixd, s0-(int)(dat[i]*mxd), ixd, s0); } g.setColor(Color.yellow); g.drawString("Max:"+N/2+"[Hz]",sw-86, s0+22); break; case 2: //-------- osc double hd = sw/(double)N; g.setColor(new Color(0,0,170)); // lines int wn = 20; for (int i = 1; i < wn; i++) { int siw = sh*i/wn; g.drawLine(0, siw, sw, siw); } for (int j = 1; j < wn; j++) { int sjw = sw*j/wn; g.drawLine(sjw, 0, sjw, sh); } double y0 = 0, y1; double x0 = 0, x1; g.setColor(Color.green); for (int x = 0; x < N; x++) { y1 = re[x]*scale*20.0; x1 = x*hd; g.drawLine((int)x0, hh-(int)y0, (int)x1, hh-(int)y1); y0 = y1; x0 = x1; } break; } int s3 = 48; g.setColor(Color.red); g.drawString("Ch1:"+f1+"/Ch2:"+f2, 5, s3); g.drawString("Partial:"+baion, hw-86, s3); g.drawString("Strik-p:"+SP+"/"+L+"="+SP/L, hw-18, s3); g.drawString("Level:"+scale, sw-80, s3); //g.setColor(Color.white); //g.drawString("F F T - S I M U L A T O R v1.5", hw-90, s0+28); } public void ini() { //関数表、fft領域確保 sin_tbl = new double[N]; cos_tbl = new double[N]; b_re = new double[N]; b_im = new double[N]; re = new double[N]; im = new double[N]; dat = new double [N]; double xx = -Math.PI*2.0/(double)N; double arg; for (int i = 0; i < N; i++) { arg = i * xx; sin_tbl[i] = Math.sin(arg); cos_tbl[i] = Math.cos(arg); } } public void fft_main() { int num = 1; int len = N; int tim, w, j1, j2; double xr, xi, yr, yi; for (int i = 0; i < n; i++) { len = len/2; tim = 0; for (int j = 0; j < num; j++) { w = 0; for (int k = 0; k < len; k++) { j1 = tim + k; j2 = j1 + len; xr = re[j1]; xi = im[j1]; yr = re[j2]; yi = im[j2]; re[j1] = xr + yr; im[j1] = xi + yi; xr = xr - yr; xi = xi - yi; re[j2] = xr * cos_tbl[w] - xi * sin_tbl[w]; im[j2] = xr * sin_tbl[w] + xi * cos_tbl[w]; w = w + num; } tim = tim + 2 * len; } num = num * 2; } } public void fft_bit() { int ii, k, bit; for (int i = 0; i < N; i++) { for (k = 0,ii = i, bit = 0; ; bit<<=1, ii>>=1) { bit = (ii & 1) | bit; if (++k == n) break; } b_re[i] = re[bit]; b_im[i] = im[bit]; } for (int i = 0; i < N; i++) { re[i] = b_re[i]; im[i] = b_im[i]; } double nrml = 1.0/Math.sqrt(N); for (int i = 0; i < N; i++) { re[i] = re[i] * nrml; im[i] = im[i] * nrml; } } public void fft_amp() { for (int i = 0; i < N/2; i++) { dat[i] = Math.sqrt( re[i] * re[i] + im[i] * im[i]); } } }//class