/Users/lyon/j4p/src/sound/soundDemo/MidiSynth.java

1    package sound.soundDemo; 
2     
3    /* 
4     * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 
5     * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
6     */ 
7     
8     
9    import javax.sound.midi.*; 
10   import javax.swing.*; 
11   import javax.swing.border.*; 
12   import javax.swing.event.*; 
13   import javax.swing.table.AbstractTableModel; 
14   import javax.swing.table.TableColumn; 
15   import javax.swing.table.TableModel; 
16   import java.awt.*; 
17   import java.awt.event.*; 
18   import java.io.File; 
19   import java.io.IOException; 
20   import java.util.Vector; 
21    
22   /** 
23    * Illustrates general MIDI melody instruments and MIDI controllers. 
24    * 
25    * @version @(#)MidiSynth.java  1.16 02/02/06 
26    * @author Brian Lichtenwalter 
27    */ 
28   public class MidiSynth extends JPanel implements ControlContext { 
29    
30       final int PROGRAM = 192; 
31       final int NOTEON = 144; 
32       final int NOTEOFF = 128; 
33       final int SUSTAIN = 64; 
34       final int REVERB = 91; 
35       final int ON = 0, OFF = 1; 
36       final Color jfcBlue = new Color(204, 204, 255); 
37       final Color pink = new Color(255, 175, 175); 
38       Sequencer sequencer; 
39       Sequence sequence; 
40       Synthesizer synthesizer; 
41       Instrument instruments[]; 
42       ChannelData channels[]; 
43       ChannelData cc;    // current channel 
44       JCheckBox mouseOverCB = new JCheckBox("mouseOver", true); 
45       JSlider veloS, presS, bendS, revbS; 
46       JCheckBox soloCB, monoCB, muteCB, sustCB; 
47       Vector keys = new Vector(); 
48       Vector whiteKeys = new Vector(); 
49       JTable table; 
50       OuterPiano piano; 
51       boolean record; 
52       Track track; 
53       long startTime; 
54       RecordFrame recordFrame; 
55       Controls controls; 
56    
57    
58    
59       public MidiSynth() { 
60           setLayout(new BorderLayout()); 
61    
62           JPanel p = new JPanel(); 
63           p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 
64           EmptyBorder eb = new EmptyBorder(5, 5, 5, 5); 
65           BevelBorder bb = new BevelBorder(BevelBorder.LOWERED); 
66           CompoundBorder cb = new CompoundBorder(eb, bb); 
67           p.setBorder(new CompoundBorder(cb, eb)); 
68           JPanel pp = new JPanel(new BorderLayout()); 
69           pp.setBorder(new EmptyBorder(10, 20, 10, 5)); 
70           pp.add(piano = new OuterPiano(this)); 
71           p.add(pp); 
72           p.add(controls = new Controls()); 
73           p.add(new InstrumentsTable()); 
74    
75           add(p); 
76       } 
77    
78    
79       public void open() { 
80           try { 
81               if (synthesizer == null) { 
82                   if ((synthesizer = MidiSystem.getSynthesizer()) == null) { 
83                       System.out.println("getSynthesizer() failed!"); 
84                       return; 
85                   } 
86               } 
87               synthesizer.open(); 
88               sequencer = MidiSystem.getSequencer(); 
89               sequence = new Sequence(Sequence.PPQ, 10); 
90           } catch (Exception ex) { 
91               ex.printStackTrace(); 
92               return; 
93           } 
94    
95           Soundbank sb = synthesizer.getDefaultSoundbank(); 
96           if (sb != null) { 
97               instruments = synthesizer.getDefaultSoundbank().getInstruments(); 
98               synthesizer.loadInstrument(instruments[0]); 
99           } 
100          MidiChannel midiChannels[] = synthesizer.getChannels(); 
101          channels = new ChannelData[midiChannels.length]; 
102          for (int i = 0; i < channels.length; i++) { 
103              channels[i] = new ChannelData(midiChannels[i], i); 
104          } 
105          cc = channels[0]; 
106   
107          ListSelectionModel lsm = table.getSelectionModel(); 
108          lsm.setSelectionInterval(0, 0); 
109          lsm = table.getColumnModel().getSelectionModel(); 
110          lsm.setSelectionInterval(0, 0); 
111      } 
112   
113   
114      public void close() { 
115          if (synthesizer != null) { 
116              synthesizer.close(); 
117          } 
118          if (sequencer != null) { 
119              sequencer.close(); 
120          } 
121          sequencer = null; 
122          synthesizer = null; 
123          instruments = null; 
124          channels = null; 
125          if (recordFrame != null) { 
126              recordFrame.dispose(); 
127              recordFrame = null; 
128          } 
129      } 
130   
131   
132      /** 
133       * given 120 bpm: 
134       *   (120 bpm) / (60 seconds per minute) = 2 beats per second 
135       *   2 / 1000 beats per millisecond 
136       *   (2 * resolution) ticks per second 
137       *   (2 * resolution)/1000 ticks per millisecond, or 
138       *      (resolution / 500) ticks per millisecond 
139       *   ticks = milliseconds * resolution / 500 
140       */ 
141      public void createShortEvent(int type, int num) { 
142          ShortMessage message = new ShortMessage(); 
143          try { 
144              long millis = System.currentTimeMillis() - startTime; 
145              long tick = millis * sequence.getResolution() / 500; 
146              message.setMessage(type + cc.num, num, cc.velocity); 
147              MidiEvent event = new MidiEvent(message, tick); 
148              track.add(event); 
149          } catch (Exception ex) { 
150              ex.printStackTrace(); 
151          } 
152      } 
153   
154   
155      /** 
156       * Black and white keys or notes on the piano. 
157       */ 
158      public Key getKey(int x, int y, int w, int h, int num){ 
159          return new Key(this, x,y,w,h,num); 
160      } 
161   
162   
163      /** 
164       * Stores MidiChannel information. 
165       */ 
166      class ChannelData { 
167   
168          MidiChannel channel; 
169          boolean solo, mono, mute, sustain; 
170          int velocity, pressure, bend, reverb; 
171          int row, col, num; 
172   
173          public ChannelData(MidiChannel channel, int num) { 
174              this.channel = channel; 
175              this.num = num; 
176              velocity = pressure = bend = reverb = 64; 
177          } 
178   
179          public void setComponentStates() { 
180              table.setRowSelectionInterval(row, row); 
181              table.setColumnSelectionInterval(col, col); 
182   
183              soloCB.setSelected(solo); 
184              monoCB.setSelected(mono); 
185              muteCB.setSelected(mute); 
186              //sustCB.setSelected(sustain); 
187   
188              JSlider slider[] = {veloS, presS, bendS, revbS}; 
189              int v[] = {velocity, pressure, bend, reverb}; 
190              for (int i = 0; i < slider.length; i++) { 
191                  TitledBorder tb = (TitledBorder) slider[i].getBorder(); 
192                  String s = tb.getTitle(); 
193                  tb.setTitle(s.substring(0, s.indexOf('=') + 1) + s.valueOf(v[i])); 
194                  slider[i].repaint(); 
195              } 
196          } 
197      } // End class ChannelData 
198   
199   
200      /** 
201       * Table for 128 general MIDI melody instuments. 
202       */ 
203      class InstrumentsTable extends JPanel { 
204   
205          private String names[] = { 
206              "Piano", "Chromatic Perc.", "Organ", "Guitar", 
207              "Bass", "Strings", "Ensemble", "Brass", 
208              "Reed", "Pipe", "Synth Lead", "Synth Pad", 
209              "Synth Effects", "Ethnic", "Percussive", "Sound Effects"}; 
210          private int nRows = 8; 
211          private int nCols = names.length; // just show 128 instruments 
212   
213          public InstrumentsTable() { 
214              setLayout(new BorderLayout()); 
215   
216              TableModel dataModel = new AbstractTableModel() { 
217                  public int getColumnCount() { 
218                      return nCols; 
219                  } 
220   
221                  public int getRowCount() { 
222                      return nRows; 
223                  } 
224   
225                  public Object getValueAt(int r, int c) { 
226                      if (instruments != null) { 
227                          return instruments[c * nRows + r].getName(); 
228                      } else { 
229                          return Integer.toString(c * nRows + r); 
230                      } 
231                  } 
232   
233                  public String getColumnName(int c) { 
234                      return names[c]; 
235                  } 
236   
237                  public Class getColumnClass(int c) { 
238                      return getValueAt(0, c).getClass(); 
239                  } 
240   
241                  public boolean isCellEditable(int r, int c) { 
242                      return false; 
243                  } 
244   
245                  public void setValueAt(Object obj, int r, int c) { 
246                  } 
247              }; 
248   
249              table = new JTable(dataModel); 
250              table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
251   
252              // Listener for row changes 
253              ListSelectionModel lsm = table.getSelectionModel(); 
254              lsm.addListSelectionListener(new ListSelectionListener() { 
255                  public void valueChanged(ListSelectionEvent e) { 
256                      ListSelectionModel sm = (ListSelectionModel) e.getSource(); 
257                      if (!sm.isSelectionEmpty()) { 
258                          cc.row = sm.getMinSelectionIndex(); 
259                      } 
260                      programChange(cc.col * nRows + cc.row); 
261                  } 
262              }); 
263   
264              // Listener for column changes 
265              lsm = table.getColumnModel().getSelectionModel(); 
266              lsm.addListSelectionListener(new ListSelectionListener() { 
267                  public void valueChanged(ListSelectionEvent e) { 
268                      ListSelectionModel sm = (ListSelectionModel) e.getSource(); 
269                      if (!sm.isSelectionEmpty()) { 
270                          cc.col = sm.getMinSelectionIndex(); 
271                      } 
272                      programChange(cc.col * nRows + cc.row); 
273                  } 
274              }); 
275   
276              table.setPreferredScrollableViewportSize(new Dimension(nCols * 110, 200)); 
277              table.setCellSelectionEnabled(true); 
278              table.setColumnSelectionAllowed(true); 
279              for (int i = 0; i < names.length; i++) { 
280                  TableColumn column = table.getColumn(names[i]); 
281                  column.setPreferredWidth(110); 
282              } 
283              table.setAutoResizeMode(table.AUTO_RESIZE_OFF); 
284   
285              JScrollPane sp = new JScrollPane(table); 
286              sp.setVerticalScrollBarPolicy(sp.VERTICAL_SCROLLBAR_NEVER); 
287              sp.setHorizontalScrollBarPolicy(sp.HORIZONTAL_SCROLLBAR_ALWAYS); 
288              add(sp); 
289          } 
290   
291          public Dimension getPreferredSize() { 
292              return new Dimension(800, 170); 
293          } 
294   
295          public Dimension getMaximumSize() { 
296              return new Dimension(800, 170); 
297          } 
298   
299          private void programChange(int program) { 
300              if (instruments != null) { 
301                  synthesizer.loadInstrument(instruments[program]); 
302              } 
303              cc.channel.programChange(program); 
304              if (record) { 
305                  createShortEvent(PROGRAM, program); 
306              } 
307          } 
308      } 
309   
310   
311      /** 
312       * A collection of MIDI controllers. 
313       */ 
314      class Controls extends JPanel implements ActionListener, ChangeListener, ItemListener { 
315   
316          public JButton recordB; 
317          JMenu menu; 
318          int fileNum = 0; 
319   
320          public Controls() { 
321              setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 
322              setBorder(new EmptyBorder(5, 10, 5, 10)); 
323   
324              JPanel p = new JPanel(); 
325              p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 
326   
327              veloS = createSlider("Velocity", p); 
328              presS = createSlider("Pressure", p); 
329              revbS = createSlider("Reverb", p); 
330   
331              // create a slider with a 14-bit range of values for pitch-bend 
332              bendS = create14BitSlider("Bend", p); 
333   
334              p.add(Box.createHorizontalStrut(10)); 
335              add(p); 
336   
337              p = new JPanel(); 
338              p.setBorder(new EmptyBorder(10, 0, 10, 0)); 
339              p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 
340   
341              JComboBox combo = new JComboBox(); 
342              combo.setPreferredSize(new Dimension(120, 25)); 
343              combo.setMaximumSize(new Dimension(120, 25)); 
344              for (int i = 1; i <= 16; i++) { 
345                  combo.addItem("Channel " + String.valueOf(i)); 
346              } 
347              combo.addItemListener(this); 
348              p.add(combo); 
349              p.add(Box.createHorizontalStrut(20)); 
350   
351              muteCB = createCheckBox("Mute", p); 
352              soloCB = createCheckBox("Solo", p); 
353              monoCB = createCheckBox("Mono", p); 
354              //sustCB = createCheckBox("Sustain", p); 
355   
356              createButton("All Notes Off", p); 
357              p.add(Box.createHorizontalStrut(10)); 
358              p.add(mouseOverCB); 
359              p.add(Box.createHorizontalStrut(10)); 
360              recordB = createButton("Record...", p); 
361              add(p); 
362          } 
363   
364          public JButton createButton(String name, JPanel p) { 
365              JButton b = new JButton(name); 
366              b.addActionListener(this); 
367              p.add(b); 
368              return b; 
369          } 
370   
371          private JCheckBox createCheckBox(String name, JPanel p) { 
372              JCheckBox cb = new JCheckBox(name); 
373              cb.addItemListener(this); 
374              p.add(cb); 
375              return cb; 
376          } 
377   
378          private JSlider createSlider(String name, JPanel p) { 
379              JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 127, 64); 
380              slider.addChangeListener(this); 
381              TitledBorder tb = new TitledBorder(new EtchedBorder()); 
382              tb.setTitle(name + " = 64"); 
383              slider.setBorder(tb); 
384              p.add(slider); 
385              p.add(Box.createHorizontalStrut(5)); 
386              return slider; 
387          } 
388   
389          private JSlider create14BitSlider(String name, JPanel p) { 
390              JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 16383, 8192); 
391              slider.addChangeListener(this); 
392              TitledBorder tb = new TitledBorder(new EtchedBorder()); 
393              tb.setTitle(name + " = 8192"); 
394              slider.setBorder(tb); 
395              p.add(slider); 
396              p.add(Box.createHorizontalStrut(5)); 
397              return slider; 
398          } 
399   
400          public void stateChanged(ChangeEvent e) { 
401              JSlider slider = (JSlider) e.getSource(); 
402              int value = slider.getValue(); 
403              TitledBorder tb = (TitledBorder) slider.getBorder(); 
404              String s = tb.getTitle(); 
405              tb.setTitle(s.substring(0, s.indexOf('=') + 1) + s.valueOf(value)); 
406              if (s.startsWith("Velocity")) { 
407                  cc.velocity = value; 
408              } else if (s.startsWith("Pressure")) { 
409                  cc.channel.setChannelPressure(cc.pressure = value); 
410              } else if (s.startsWith("Bend")) { 
411                  cc.channel.setPitchBend(cc.bend = value); 
412              } else if (s.startsWith("Reverb")) { 
413                  cc.channel.controlChange(REVERB, cc.reverb = value); 
414              } 
415              slider.repaint(); 
416          } 
417   
418          public void itemStateChanged(ItemEvent e) { 
419              if (e.getSource() instanceof JComboBox) { 
420                  JComboBox combo = (JComboBox) e.getSource(); 
421                  cc = channels[combo.getSelectedIndex()]; 
422                  cc.setComponentStates(); 
423              } else { 
424                  JCheckBox cb = (JCheckBox) e.getSource(); 
425                  String name = cb.getText(); 
426                  if (name.startsWith("Mute")) { 
427                      cc.channel.setMute(cc.mute = cb.isSelected()); 
428                  } else if (name.startsWith("Solo")) { 
429                      cc.channel.setSolo(cc.solo = cb.isSelected()); 
430                  } else if (name.startsWith("Mono")) { 
431                      cc.channel.setMono(cc.mono = cb.isSelected()); 
432                  } else if (name.startsWith("Sustain")) { 
433                      cc.sustain = cb.isSelected(); 
434                      cc.channel.controlChange(SUSTAIN, cc.sustain ? 127 : 0); 
435                  } 
436              } 
437          } 
438   
439          public void actionPerformed(ActionEvent e) { 
440              JButton button = (JButton) e.getSource(); 
441              if (button.getText().startsWith("All")) { 
442                  for (int i = 0; i < channels.length; i++) { 
443                      channels[i].channel.allNotesOff(); 
444                  } 
445                  for (int i = 0; i < keys.size(); i++) { 
446                      ((Key) keys.get(i)).setNoteState(OFF); 
447                  } 
448              } else if (button.getText().startsWith("Record")) { 
449                  if (recordFrame != null) { 
450                      recordFrame.toFront(); 
451                  } else { 
452                      recordFrame = new RecordFrame(); 
453                  } 
454              } 
455          } 
456      } // End class Controls 
457   
458   
459      /** 
460       * A frame that allows for midi capture & saving the captured data. 
461       */ 
462      class RecordFrame extends JFrame implements ActionListener, MetaEventListener { 
463   
464          public JButton recordB, playB, saveB; 
465          Vector tracks = new Vector(); 
466          DefaultListModel listModel = new DefaultListModel(); 
467          TableModel dataModel; 
468          JTable table; 
469   
470   
471          public RecordFrame() { 
472              super("Midi Capture"); 
473              addWindowListener(new WindowAdapter() { 
474                  public void windowClosing(WindowEvent e) { 
475                      recordFrame = null; 
476                  } 
477              }); 
478   
479              sequencer.addMetaEventListener(this); 
480              try { 
481                  sequence = new Sequence(Sequence.PPQ, 10); 
482              } catch (Exception ex) { 
483                  ex.printStackTrace(); 
484              } 
485   
486              //JPanel p1 = new JPanel(new BorderLayout()); 
487   
488              JPanel p2 = new JPanel(); 
489              p2.setBorder(new EmptyBorder(5, 5, 5, 5)); 
490              p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS)); 
491   
492              recordB = createButton("Record", p2, true); 
493              playB = createButton("Play", p2, false); 
494              saveB = createButton("Save...", p2, false); 
495   
496              getContentPane().add("North", p2); 
497              p2.setVisible(false); 
498   
499              final String[] names = {"Channel #", "Instrument"}; 
500   
501              dataModel = new AbstractTableModel() { 
502                  public int getColumnCount() { 
503                      return names.length; 
504                  } 
505   
506                  public int getRowCount() { 
507                      return tracks.size(); 
508                  } 
509   
510                  public Object getValueAt(int row, int col) { 
511                      if (col == 0) { 
512                          return ((TrackData) tracks.get(row)).chanNum; 
513                      } else if (col == 1) { 
514                          return ((TrackData) tracks.get(row)).name; 
515                      } 
516                      return null; 
517                  } 
518   
519                  public String getColumnName(int col) { 
520                      return names[col]; 
521                  } 
522   
523                  public Class getColumnClass(int c) { 
524                      return getValueAt(0, c).getClass(); 
525                  } 
526   
527                  public boolean isCellEditable(int row, int col) { 
528                      return false; 
529                  } 
530   
531                  public void setValueAt(Object val, int row, int col) { 
532                      if (col == 0) { 
533                          ((TrackData) tracks.get(row)).chanNum = (Integer) val; 
534                      } else if (col == 1) { 
535                          ((TrackData) tracks.get(row)).name = (String) val; 
536                      } 
537                  } 
538              }; 
539   
540              table = new JTable(dataModel); 
541              TableColumn col = table.getColumn("Channel #"); 
542              col.setMaxWidth(65); 
543              table.sizeColumnsToFit(0); 
544   
545              JScrollPane scrollPane = new JScrollPane(table); 
546              EmptyBorder eb = new EmptyBorder(0, 5, 5, 5); 
547              scrollPane.setBorder(new CompoundBorder(eb, new EtchedBorder())); 
548   
549              getContentPane().add("Center", scrollPane); 
550              pack(); 
551              Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 
552              int w = 210; 
553              int h = 160; 
554              setLocation(d.width / 2 - w / 2, d.height / 2 - h / 2); 
555              setSize(w, h); 
556              setVisible(true); 
557          } 
558   
559   
560          public JButton createButton(String name, JPanel p, boolean state) { 
561              JButton b = new JButton(name); 
562              b.setFont(new Font("serif", Font.PLAIN, 10)); 
563              b.setEnabled(state); 
564              b.addActionListener(this); 
565              p.add(b); 
566              return b; 
567          } 
568   
569   
570          public void actionPerformed(ActionEvent e) { 
571              JButton button = (JButton) e.getSource(); 
572              if (button.equals(recordB)) { 
573                  record = recordB.getText().startsWith("Record"); 
574                  if (record) { 
575                      track = sequence.createTrack(); 
576                      startTime = System.currentTimeMillis(); 
577   
578                      // add a program change right at the beginning of 
579                      // the track for the current instrument 
580                      createShortEvent(PROGRAM, cc.col * 8 + cc.row); 
581   
582                      recordB.setText("Stop"); 
583                      playB.setEnabled(false); 
584                      saveB.setEnabled(false); 
585                  } else { 
586                      String name = null; 
587                      if (instruments != null) { 
588                          name = instruments[cc.col * 8 + cc.row].getName(); 
589                      } else { 
590                          name = Integer.toString(cc.col * 8 + cc.row); 
591                      } 
592                      tracks.add(new TrackData(cc.num + 1, name, track)); 
593                      table.tableChanged(new TableModelEvent(dataModel)); 
594                      recordB.setText("Record"); 
595                      playB.setEnabled(true); 
596                      saveB.setEnabled(true); 
597                  } 
598              } else if (button.equals(playB)) { 
599                  if (playB.getText().startsWith("Play")) { 
600                      try { 
601                          sequencer.open(); 
602                          sequencer.setSequence(sequence); 
603                      } catch (Exception ex) { 
604                          ex.printStackTrace(); 
605                      } 
606                      sequencer.start(); 
607                      playB.setText("Stop"); 
608                      recordB.setEnabled(false); 
609                  } else { 
610                      sequencer.stop(); 
611                      playB.setText("Play"); 
612                      recordB.setEnabled(true); 
613                  } 
614              } else if (button.equals(saveB)) { 
615                  try { 
616                      File file = new File(System.getProperty("user.dir")); 
617                      JFileChooser fc = new JFileChooser(file); 
618                      fc.setFileFilter(new javax.swing.filechooser.FileFilter() { 
619                          public boolean accept(File f) { 
620                              if (f.isDirectory()) { 
621                                  return true; 
622                              } 
623                              return false; 
624                          } 
625   
626                          public String getDescription() { 
627                              return "Save as .mid file."; 
628                          } 
629                      }); 
630                      if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { 
631                          saveMidiFile(fc.getSelectedFile()); 
632                      } 
633                  } catch (SecurityException ex) { 
634                      JavaSound.showInfoDialog(); 
635                      ex.printStackTrace(); 
636                  } catch (Exception ex) { 
637                      ex.printStackTrace(); 
638                  } 
639              } 
640          } 
641   
642   
643          public void meta(MetaMessage message) { 
644              if (message.getType() == 47) {  // 47 is end of track 
645                  playB.setText("Play"); 
646                  recordB.setEnabled(true); 
647              } 
648          } 
649   
650   
651          public void saveMidiFile(File file) { 
652              try { 
653                  int[] fileTypes = MidiSystem.getMidiFileTypes(sequence); 
654                  if (fileTypes.length == 0) { 
655                      System.out.println("Can't save sequence"); 
656                  } else { 
657                      if (MidiSystem.write(sequence, fileTypes[0], file) == -1) { 
658                          throw new IOException("Problems writing to file"); 
659                      } 
660                  } 
661              } catch (SecurityException ex) { 
662                  JavaSound.showInfoDialog(); 
663              } catch (Exception ex) { 
664                  ex.printStackTrace(); 
665              } 
666          } 
667   
668   
669          class TrackData extends Object { 
670              Integer chanNum; 
671              String name; 
672              Track track; 
673   
674              public TrackData(int chanNum, String name, Track track) { 
675                  this.chanNum = new Integer(chanNum); 
676                  this.name = name; 
677                  this.track = track; 
678              } 
679          } // End class TrackData 
680      } // End class RecordFrame 
681   
682   
683      public static void main(String args[]) { 
684          final MidiSynth midiSynth = new MidiSynth(); 
685          midiSynth.open(); 
686          JFrame f = new JFrame("Midi Synthesizer"); 
687          f.addWindowListener(new WindowAdapter() { 
688              public void windowClosing(WindowEvent e) { 
689                  System.exit(0); 
690              } 
691          }); 
692          f.getContentPane().add("Center", midiSynth); 
693          f.pack(); 
694          Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
695          int w = 760; 
696          int h = 470; 
697          f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h / 2); 
698          f.setSize(w, h); 
699          f.setVisible(true); 
700      } 
701  } 
702