import java.awt.*; import java.applet.*; import sun.audio.*; import graph.*; // @(#)fourier.java 1.15 96/07/15 /* * Copyright (c) 1996 Manfred Thole * thole@nst.ing.tu-bs.de * * Modified by Tom Huber, huber@gac.edu * Revision Date: 20-Sep-96 * This requires the graph2d package from Leigh Brookshaw * http://www.sci.usq.edu.au/staff/leighb/graph * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * * */ /** Fourier synthesis. @author Manfred Thole, thole@nst.ing.tu-bs.de @version 96/07/15 @ @ Modified by Tom Huber, huber@gac.edu @ version 20-Sep-96 @ To Compile, this requires the graph2d package from Leigh Brookshaw @ http://www.sci.usq.edu.au/staff/leighb/graph @ */ public class fourier extends Applet { // Max. |ak|,|bk| final static int MAX_AB = 50; // "k_max" final static int MAX_ANZ = 14; // a_k = a[k]/INT_MULT final static double INT_MULT = 50.0; // time base final static double TIM_MULT = 40.0/Math.PI; // Audio?? final static boolean AUDIO = true; // Maximum Number of Waves final static int MAX_WAVES = 3; private double acoeff [][] = new double[MAX_WAVES][MAX_ANZ]; private double bcoeff [][] = new double[MAX_WAVES][MAX_ANZ]; private Button la_a [] = new Button[MAX_ANZ]; private Button la_b [] = new Button[MAX_ANZ]; private TextField ta_a [] = new TextField[MAX_ANZ]; private TextField ta_b [] = new TextField[MAX_ANZ]; private TextField CosExpr = new TextField(); private TextField SinExpr = new TextField(); private Scrollbar s_a [] = new Scrollbar[MAX_ANZ]; private Scrollbar s_b [] = new Scrollbar[MAX_ANZ]; Panel panel1, panel2 ; // Sub-containers for all this stuff. GridBagLayout gridbag = new GridBagLayout(); private CheckboxGroup WaveNumber; private Checkbox Wave1; private Checkbox Wave2; private Checkbox Wave3; private CheckboxGroup AudioGroup; private Checkbox AudioOn; private Checkbox AudioOff; private Image bg; private Graphics bgg; private String sin_name; private String cos_name; private byte sound[] = new byte[40]; private java.io.InputStream soundStream; private boolean soundOn; private int iy[] = new int[81]; private int Wnum=0; // Wave Number int height,width; public void init() { width = size().width; height = size().height; setBackground(Color.lightGray); resize(width,height); sin_name = "Sin: "; cos_name = "Cos: "; panel1 = new Panel(); panel1.setLayout(gridbag); CosExpr = new TextField(13); SinExpr = new TextField(13); CosExpr.setForeground(Color.blue); CosExpr.setBackground(Color.white); SinExpr.setForeground(Color.blue); SinExpr.setBackground(Color.white); constrain(panel1, new Label(cos_name), 0, 0, 1, 1); constrain(panel1, new Label(sin_name), 3, 0, 1, 1); constrain(panel1, CosExpr, 1,0,2,1); constrain(panel1, SinExpr, 4,0,2,1); for (int i=0; i < MAX_ANZ; i++) { if (i<10) la_a[i] = new Button("a" + i + ": "); else la_a[i] = new Button("a" + i + ":"); ta_a[i] = new TextField(10); ta_a[i].setText(""+acoeff[Wnum][i]); ta_a[i].setForeground(Color.blue); ta_a[i].setBackground(Color.white); ta_a[i].setEditable(true); s_a[i] = new Scrollbar(Scrollbar.HORIZONTAL,(int)(acoeff[Wnum][i]*INT_MULT),1,-MAX_AB,MAX_AB); s_a[i].setBackground(Color.white); constrain(panel1, la_a[i], 0, i+1, 1, 1); constrain(panel1, ta_a[i], 1, i+1, 1, 1); constrain(panel1, s_a[i], 2, i+1, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTHWEST, 1.0, 0.0, 0, 0, 0, 10, 40, 0); if ( i == 0 ) { constrain(panel1, new Label(""), 3, 1, 1, 1); } else { if (i<10) la_b[i] = new Button("b" + i + ": "); else la_b[i] = new Button("b" + i + ":"); ta_b[i] = new TextField(10); ta_b[i].setText(""+bcoeff[Wnum][i]); ta_b[i].setForeground(Color.blue); ta_b[i].setBackground(Color.white); ta_b[i].setEditable(true); s_b[i] = new Scrollbar(Scrollbar.HORIZONTAL,(int)(bcoeff[Wnum][i]*INT_MULT),1,-MAX_AB,MAX_AB); s_b[i].setBackground(Color.white); constrain(panel1, la_b[i], 3, i+1, 1, 1); constrain(panel1, ta_b[i], 4, i+1, 1, 1); constrain(panel1, s_b[i], 5, i+1, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.NORTHWEST, 1.0, 0.0, 0, 0, 0, 10, 40, 0); // constrain(panel1, s_b[i], 5, i+1, 1, 1,0,5,0,5); } } WaveNumber = new CheckboxGroup(); add(Wave1 = new Checkbox("Wave1",WaveNumber,true)); add(Wave2 = new Checkbox("Wave2",WaveNumber,false)); add(Wave3 = new Checkbox("Wave3",WaveNumber,false)); AudioGroup = new CheckboxGroup(); add(AudioOn = new Checkbox("Audio On",AudioGroup,true)); add(AudioOff = new Checkbox("Audio Off",AudioGroup,false)); panel2 = new Panel(); panel2.setLayout(gridbag); // // Create a Panel to contain all the components along the // left hand side of the window. Use a GridBagLayout for it. constrain(panel2,Wave1,0,0,1,1); constrain(panel2,Wave2,0,1,1,1); constrain(panel2,Wave3,0,2,1,1); constrain(panel2, new Label(""), 0, 3, 1, 1); constrain(panel2,AudioOn,0,4,1,1); constrain(panel2,AudioOff,0,5,1,1); // constrain(panel2, new Label(" Sample:"), 0, 6, 1, 1); // constrain(panel2, new Label(" (-1^(x-1))/x"), 0, 7, 1, 1); // Finally, use a GridBagLayout to arrange the panels themselves this.setLayout(gridbag); // And add the panels to the toplevel window constrain(this, panel1, 0, 0, 1, 1, GridBagConstraints.NONE, GridBagConstraints.NORTHWEST, 0.0, 0.0, 205, 10, 0, 0); constrain(this, panel2, 0, 0, 1, 1, GridBagConstraints.NONE, GridBagConstraints.NORTHWEST, 0.0, 0.0, 10, 380, 0, 0); // bg = this.createImage(320,200); bg = this.createImage(width,height); bgg = bg.getGraphics(); bgg.setColor(Color.lightGray); bgg.fillRect(0, 0, width, height); bgg.setColor(Color.black); bgg.fillRect(0, 0, 320, 200); bgg.setColor( new Color(0, 75, 0) ); for (int i = 0; i < 320; i+=20) bgg.drawLine(i, 0, i, 200); for (int i = 100; i < 200; i+=30) bgg.drawLine(0, i, 320, i); for (int i = 100; i > 0; i-=30) bgg.drawLine(0, i, 320, i); bgg.setColor(Color.green); bgg.drawLine(0, 100, 320, 100); bgg.drawLine(160, 0, 160, 200); CalculatePlot(); if ( AUDIO ) { soundStream = new ContinuousAudioDataStream(new AudioData(sound)); soundOn = true; } } private final void CalculatePlot() { if ( AUDIO && soundOn ) AudioPlayer.player.stop(soundStream); // One period, TIM_MULT dependent! This needs clean up... for (int i = 0; i < 80; i++) { double y = 0; y += acoeff[Wnum][0]/2.0; for (int j = 1; j < MAX_ANZ; j++) { y += acoeff[Wnum][j]*Math.cos(j*i/TIM_MULT); y += bcoeff[Wnum][j]*Math.sin(j*i/TIM_MULT); } iy[i] = (int) (100-y*30); if ( AUDIO && ( i % 2 != 0 ) ) sound[i/2] = int2ulaw((int)(y*2000)); } // for (i... iy[80] = iy[0]; if ( AUDIO && soundOn ) AudioPlayer.player.start(soundStream); } public boolean handleEvent(Event e) { // this.showStatus("ID: "+e.id+" Event: " + e.target); switch (e.id) { // See pg 114 of Java in a Nutshell for other event types case Event.ACTION_EVENT: if (e.target instanceof TextField) { for (int i=0; i < MAX_ANZ; i++) { if ( e.target.equals(ta_a[i]) ) { ParseFunction function = new ParseFunction( ((TextField)e.target).getText() ); if(!function.parse()) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); return true; } try { double value = function.getResult(); acoeff[Wnum][i] = value; acoeff[Wnum][i] = Math.min(acoeff[Wnum][i],1.0); acoeff[Wnum][i] = Math.max(acoeff[Wnum][i],-1.0); } catch(Exception err) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); acoeff[Wnum][i] = 0.0; } CosExpr.setText(""); SinExpr.setText(""); ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); break; } // if ( e.target.equals(ta_a[i]) ) else if ( e.target.equals(ta_b[i]) ) { ParseFunction function = new ParseFunction( ((TextField)e.target).getText() ); if(!function.parse()) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); return true; } try { double value = function.getResult(); bcoeff[Wnum][i] = value; bcoeff[Wnum][i] = Math.min(bcoeff[Wnum][i],1.0); bcoeff[Wnum][i] = Math.max(bcoeff[Wnum][i],-1.0); } catch(Exception err) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); bcoeff[Wnum][i] = 0.0; } CosExpr.setText(""); SinExpr.setText(""); ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); break; } // else if ( e.target.equals(ta_b[i]) ) } // for (int i=0; i < MAX_ANZ; i++) if (e.target.equals(CosExpr)) { ParseFunction function = new ParseFunction( ((TextField)e.target).getText() ); if(!function.parse()) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); return true; } for (int i=0; i < MAX_ANZ; i++) { try { double X = (double)(i); double value = function.getResult(X); acoeff[Wnum][i] = value; acoeff[Wnum][i] = Math.min(acoeff[Wnum][i],1.0); acoeff[Wnum][i] = Math.max(acoeff[Wnum][i],-1.0); } catch(Exception err) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); acoeff[Wnum][i] = 0.0; } ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); } } else if (e.target.equals(SinExpr)) { ParseFunction function = new ParseFunction( ((TextField)e.target).getText() ); if(!function.parse()) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); return true; } for (int i=1; i < MAX_ANZ; i++) { try { double X = (double)(i); double value = function.getResult(X); bcoeff[Wnum][i] = value; bcoeff[Wnum][i] = Math.min(bcoeff[Wnum][i],1.0); bcoeff[Wnum][i] = Math.max(bcoeff[Wnum][i],-1.0); } catch(Exception err) { this.showStatus("Failed to parse function!"); System.out.println("Failed to parse function!"); bcoeff[Wnum][i] = 0.0; } ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); } } repaint(); return true; } // if (e.target instanceof TextField) if (e.target instanceof Button) { for (int i=0; i < MAX_ANZ; i++) { if ( e.target.equals(la_a[i]) ) { // this.showStatus("Zeroing "+e.target); acoeff[Wnum][i] = 0.0; CosExpr.setText(""); SinExpr.setText(""); ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); repaint(); return true; } // if ( e.target.equals(ta_a[i]) ) else if ( e.target.equals(la_b[i]) ) { if (i > 0) { // this.showStatus("Zeroing "+e.target); bcoeff[Wnum][i] = 0.0; CosExpr.setText(""); SinExpr.setText(""); ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); repaint(); return true; } // if (i > 0) } // else if ( e.target.equals(ta_b[i]) ) } // for (int i=0; i < MAX_ANZ; i++) } // if (e.target instanceof Button) else if (e.target.equals(Wave1)) { Wnum = 0; CosExpr.setText(""); SinExpr.setText(""); this.showStatus("Using Wave Number 1"); for (int i=0; i < MAX_ANZ; i++) { ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); if (i > 0) { ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); } } repaint(); return true; } else if (e.target.equals(Wave2)) { Wnum = 1; CosExpr.setText(""); SinExpr.setText(""); this.showStatus("Using Wave Number 2"); for (int i=0; i < MAX_ANZ; i++) { ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); if (i > 0) { ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); } } repaint(); return true; } else if (e.target.equals(Wave3)) { Wnum = 2; CosExpr.setText(""); SinExpr.setText(""); this.showStatus("Using Wave Number 3"); for (int i=0; i < MAX_ANZ; i++) { ta_a[i].setText(""+acoeff[Wnum][i]); s_a[i].setValue( (int)(acoeff[Wnum][i]*INT_MULT) ); if (i > 0) { ta_b[i].setText(""+bcoeff[Wnum][i]); s_b[i].setValue( (int)(bcoeff[Wnum][i]*INT_MULT) ); } } repaint(); return true; } else if (e.target.equals(AudioOff)) { if ( soundOn ) { AudioPlayer.player.stop(soundStream); showStatus("Audio OFF"); soundOn = false; } return true; } else if (e.target.equals(AudioOn)) { if ( !soundOn ) { AudioPlayer.player.start(soundStream); showStatus("Audio ON"); soundOn = true; } return true; } case Event.SCROLL_ABSOLUTE: case Event.SCROLL_LINE_UP: case Event.SCROLL_PAGE_UP: case Event.SCROLL_LINE_DOWN: case Event.SCROLL_PAGE_DOWN: for (int i=0; i < MAX_ANZ; i++) { if ( e.target.equals(s_a[i]) ) { CosExpr.setText(""); SinExpr.setText(""); int value = ((Scrollbar)e.target).getValue(); acoeff[Wnum][i] = (double)(value) / INT_MULT; ta_a[i].setText(""+acoeff[Wnum][i]); break; } else if ( ( i != 0 ) && ( e.target.equals(s_b[i]) ) ) { CosExpr.setText(""); SinExpr.setText(""); int value = ((Scrollbar)e.target).getValue(); bcoeff[Wnum][i] = (double)(value) / INT_MULT; ta_b[i].setText(""+bcoeff[Wnum][i]); break; } } // for (int i=0... repaint(); return true; case Event.WINDOW_DESTROY: destroy(); return true; default: return super.handleEvent(e); } // switch ... } public void paint(Graphics g) { CalculatePlot(); g.drawImage(bg, 0, 0, null); g.clipRect(0, 0, 320, 200); // Keeps drawing out of area g.setColor(Color.red); for (int i = 0; i < 320; i+=80) { for (int j = 0; j < 80; j++) { g.drawLine(i+j, iy[j], i+j+1, iy[j+1]); } } } public void stop() { if ( AUDIO && soundOn ) AudioPlayer.player.stop(soundStream); } public void start() { if ( AUDIO && soundOn ) AudioPlayer.player.start(soundStream); } public void destroy() { if ( AUDIO ) AudioPlayer.player.stop(soundStream); for (int i=0; i < MAX_ANZ; i++) { for (int j=0; j 0) c.insets = new Insets(top, left, bottom, right); ((GridBagLayout)container.getLayout()).setConstraints(component, c); container.add(component); } public void constrain(Container container, Component component, int grid_x, int grid_y, int grid_width, int grid_height, int fill, int anchor, double weight_x, double weight_y, int top, int left, int bottom, int right) { constrain(container, component, grid_x, grid_y, grid_width, grid_height, fill, anchor, weight_x, weight_y, top, left, bottom, right, 0, 0); } public void constrain(Container container, Component component, int grid_x, int grid_y, int grid_width, int grid_height) { constrain(container, component, grid_x, grid_y, grid_width, grid_height, GridBagConstraints.NONE, GridBagConstraints.NORTHWEST, 0.0, 0.0, 0, 0, 0, 0, 0, 0); } public void constrain(Container container, Component component, int grid_x, int grid_y, int grid_width, int grid_height, int top, int left, int bottom, int right) { constrain(container, component, grid_x, grid_y, grid_width, grid_height, GridBagConstraints.NONE, GridBagConstraints.NORTHWEST, 0.0, 0.0, top, left, bottom, right, 0, 0); } }