★ wanayoo — archive 1999 http://java.sun.com/developer/technicalArticles/Media/JavaSoundAPI/code.htmlNouvelle recherche | Portail wanayoo
Skip Masthead Links developers.sun.com   » search tips  |  Search:     
The Source for Developers
A Sun Developer Network Site
Products and Technologies
Technical Topics
Sun Microsystems
 
 
Article
The Science of Java Sound
 

Articles Index

Sound
Code Samples

ToySynth.java listing

This application brings up a graphical representation of a typical synthesizer keyboard. Clicking on the keys with the mouse, plays the notes. You can adjust voice settings and other options to vary the sounds produced. Have fun!

import java.awt.*;
import java.awt.event.*;
  
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
  
import java.net.URL;
import java.net.MalformedURLException;
  
import javax.media.sound.midi.*;
  
public class ToySynth extends Frame 
    implements MouseListener {
  
  static int  VOLUME_CONTROLLER    = 7;
  static int  PAN_CONTROLLER      = 10;
  static int  EXPRESSION_CONTROLLER  = 11;
  static int  SUSTAIN_CONTROLLER    = 64;
  static int  REVERB_CONTROLLER    = 90;
  static int  REVERB_LEVEL_CONTROLLER = 91;
  
  Synthesizer synth = null;
  Soundbank soundbank = null;
  MidiChannel midiChannels[]; 
  Instrument instruments[];
        
  int transpose = 24;
  int pan = 64;
  int programNumber = 5;
  int  lastKeyNumber = 0;
  int channelNumber = 0;
  int velocity = 64;
  
  Button setChannelButton = new Button("Set Channel");
  
  Label instrumentLabel = new Label("                 ");
  Label velocityLabel = new Label("64   ");
  Label pressureLabel = new Label("64   ");
  Label bendLabel = new Label("64   ");
  Label volLabel = new Label("100  ");
  Label panLabel = new Label("64   ");
  Label revLabel = new Label("64   ");
  
  Scrollbar velocityScrollbar = null;
  Scrollbar pressureScrollbar = null;
  Scrollbar bendScrollbar = null;
  Scrollbar volScrollbar = null;
  Scrollbar panScrollbar = null;
  Scrollbar revScrollbar = null;
  
  Checkbox muteCheckbox = null;
  Checkbox monoCheckbox = null;
  Checkbox soloCheckbox = null;
  Checkbox sustainCheckbox = null;
  
  Button soundOffButton = null;
  Button quitButton = null;
  Button statusButton = null;
    
  static Choice []instr = new Choice [8];
  static Choice channelChoice;
  
  Panel instrumentsPanel = new Panel();
  Panel instrumentsPanel1 = new Panel();
  Panel instrumentsPanel2 = new Panel();
  Panel instrumentsPanel3 = new Panel();
  
  Panel keyboardPanel = new Panel();
  
  boolean singleNoteMode = true;
  
  
  public ToySynth() {
  
    // -----------------------------------------------
    // create the Synthesizer and get our MidiChannels
    // -----------------------------------------------
  
    synth = MidiSystem.getSynthesizer(null);
    if( synth == null ) {
      System.out.println(
        "Could not get default synthesizer");
      System.exit(1);
    }
  
    // load the soundbank
  
    try{
      soundbank = synth.getDefaultSoundbank();
    } catch (Exception e) {
      System.out.println(
        "Exception getting soundbank url: " + e);
      System.exit(1);
    }
  
    // populate the instrument choice boxes
    instruments = soundbank.getInstruments();
    int index = 0;
    for(int i=0; i<8; i++) {
      instr[i] = new Choice();
      for(int j=0; j<16; j++) {
        instr[i].add( instruments[index].getName() );
        index++;
      }
    }
  
    // load the first instrument
    synth.loadInstrument( instruments[0] );
  
    midiChannels = synth.getChannels();
    channelNumber = 0;
      
    instrumentLabel.setText ( "Instrument: " + 
      instruments[midiChannels[
      channelNumber].getProgram()].getName() );
      
    // Make sure we can release our resources and 
    // exit cleanly.
  
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
  
    // --------------
    // set up the GUI
    // --------------
  
    setLayout(new GridLayout(4, 1));
    setBackground(Color.lightGray);
    
    // keyboard panel
  
    keyboardPanel.setLayout(null);  
    // absolutely no layout
  
    // create the 6 octaves
    for (int i = 0; i < 6; i++) {
      // black key first
      for (int j = 0; j < 6; j++) {
        if (j == 2)
          continue; // there's no E# in black
        int keyOffset = 1;
        switch(j) {
          case 0:
            keyOffset = 1; break;
          case 1:
            keyOffset = 3; break;
          case 2:
            System.out.println(
            "Something's very Wrong!");
          System.exit(1);
          case 3:
            keyOffset = 6; break;
          case 4:
            keyOffset = 8; break;
          case 5:
            keyOffset = 10; break;
        }
        pianoKey k = 
          new pianoKey(i*12 + keyOffset, false);
        k.setBounds(X(i*28 + j*4 + 3), 
          Y(0), D(2), D(11));
        k.addMouseListener(this);
        keyboardPanel.add(k);
      }
  
      for (int j = 0; j < 7; j++) {
        int keyOffset = 1;
        switch(j) {
          case 0:
            keyOffset = 0; break;
          case 1:
            keyOffset = 2; break;
          case 2:
            keyOffset = 4; break;
          case 3:
            keyOffset = 5; break;
          case 4:
            keyOffset = 7; break;
          case 5:
            keyOffset = 9; break;
          case 6:
            keyOffset = 11; break;
        }
        int keyNumber = i*12 + keyOffset;
        pianoKey k = 
          new pianoKey(i*12 + keyOffset, true);
        k.setBounds(X(i*28 + j*4), Y(0), D(4), D(20));
        k.addMouseListener(this);
        keyboardPanel.add(k);
      }
    }
  
    add(keyboardPanel);
  
    // instruments panel
  
    instrumentsPanel = new Panel(new GridLayout(3,1));
  
    instrumentsPanel1 = new Panel(new FlowLayout());
    instrumentsPanel2 = new Panel(new GridLayout(1,4));
    instrumentsPanel3 = new Panel(new GridLayout(1,4));
  
    for(int i=0; i<8; i++) {
      instr[i].addItemListener(new programChange(this));
    }
  
    channelChoice = new Choice();
    for(int i=0;i<16;i++) {
      channelChoice.add(Integer.toString(i+1));
    }
    channelChoice.addItemListener(
      new channelChange(this));
  
    instrumentsPanel1.add(instrumentLabel);
    instrumentsPanel1.add(new Label("Channel: "));
    instrumentsPanel1.add(channelChoice);
  
    instrumentsPanel2.add(instr[0]);
    instrumentsPanel2.add(instr[1]);
    instrumentsPanel2.add(instr[2]);
    instrumentsPanel2.add(instr[3]);
    instrumentsPanel3.add(instr[4]);
    instrumentsPanel3.add(instr[5]);
    instrumentsPanel3.add(instr[6]);
    instrumentsPanel3.add(instr[7]);
  
    instrumentsPanel.add(instrumentsPanel1);
    instrumentsPanel.add(instrumentsPanel2);
    instrumentsPanel.add(instrumentsPanel3);
  
    instrumentsPanel.validate();
    
    add(instrumentsPanel);
  
    
  /////////////////////////////////////////////////////
  
    Panel p = new Panel(new FlowLayout());
    Panel p1 = new Panel(new FlowLayout());
  
    velocityScrollbar = 
      new Scrollbar(Scrollbar.VERTICAL, -64, 1, -127, 0);
    velocityScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
    
        velocity = 
          -((Scrollbar)e.getSource()).getValue ();
        velocityLabel.setText(
          Integer.toString(velocity) );
      }
    });
  
    pressureScrollbar = 
      new Scrollbar(Scrollbar.VERTICAL, -64, 1, -127, 0);
    pressureScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
        int pressure = 
          -((Scrollbar)e.getSource()).getValue ();
        pressureLabel.setText( 
          Integer.toString(pressure) );
        
        midiChannels[channelNumber].setChannelPressure(
          pressure);
      }
    });
  
    bendScrollbar = 
      new Scrollbar(Scrollbar.VERTICAL, -64, 1, -127, 0);
    bendScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
        int bend = 
          -((Scrollbar)e.getSource()).getValue ();
        bendLabel.setText( Integer.toString(bend) );
        midiChannels[channelNumber].setPitchBend(bend);
      }
    });
  
    volScrollbar = new Scrollbar(
      Scrollbar.VERTICAL, -100, 1, -127, 0);
    volScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
        int vol = 
          -((Scrollbar)e.getSource()).getValue ();
        volLabel.setText( Integer.toString(vol) );
        
        midiChannels[channelNumber].controlChange(
          VOLUME_CONTROLLER,vol);
      }
    });
  
    panScrollbar = 
      new Scrollbar(Scrollbar.VERTICAL, -64, 1, -127, 0);
    panScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
        int pan = 
          -((Scrollbar)e.getSource()).getValue ();
        panLabel.setText( Integer.toString(pan) );
        
        midiChannels[channelNumber].controlChange(
          PAN_CONTROLLER,pan);
      }
    });
  
    revScrollbar = 
      new Scrollbar(Scrollbar.VERTICAL, -64, 1, -127, 0);
    revScrollbar.addAdjustmentListener (
        new AdjustmentListener() {
      public void adjustmentValueChanged (
          AdjustmentEvent e) {
        int rev = 
          -((Scrollbar)e.getSource()).getValue ();
        revLabel.setText( Integer.toString(rev) );
        
        midiChannels[channelNumber].controlChange(
          REVERB_LEVEL_CONTROLLER, rev);
      }
    });
  
    muteCheckbox = new Checkbox ("Mute", false);
    muteCheckbox.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        if (muteCheckbox.getState()) {
  
          midiChannels[channelNumber].setMute(true);
          
        } else {
          
          midiChannels[channelNumber].setMute(false);
            
        }
      }
    });
      
    monoCheckbox = new Checkbox ("Mono", false);
    monoCheckbox.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        if (monoCheckbox.getState()) {
  
          midiChannels[channelNumber].setMono(true);
          
        } else {
          
          midiChannels[channelNumber].setMono(false);
            
        }
      }
    });
      
    soloCheckbox = new Checkbox ("Solo", false);
    soloCheckbox.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        if (soloCheckbox.getState()) {
  
          midiChannels[channelNumber].setSolo(true);
          
        } else {
          
          midiChannels[channelNumber].setSolo(false);
            
        }
      }
    });
  
    sustainCheckbox = new Checkbox ("Sustain", false);
    sustainCheckbox.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        if (sustainCheckbox.getState())
              
          midiChannels[channelNumber].controlChange(
          SUSTAIN_CONTROLLER,127);
        else
              
          midiChannels[channelNumber].controlChange(
          SUSTAIN_CONTROLLER,0);
      }
    });
    
    soundOffButton = new Button("Sound OFF");
    soundOffButton.setBackground(Color.yellow);
    soundOffButton.addActionListener(
        new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        for(int i=0;i<16;i++) 
          midiChannels[i].allNotesOff();
      }
    });
    
    quitButton = new Button("QUIT");
    quitButton.setBackground(Color.red);
    quitButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    });
    
      
    statusButton = new Button("Status");
    statusButton.setBackground(Color.lightGray);
    statusButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        printStatus();
      }
    });
    
    p.add(new Label("Ch Vol:"));
    p.add(volScrollbar);
    p.add(volLabel);
    p.add(new Label("Ch Pan:"));
    p.add(panScrollbar);
    p.add(panLabel);
    p.add(new Label("Ch Rev:"));
    p.add(revScrollbar);
    p.add(revLabel);
    p.add(new Label("Ch Bend:"));
    p.add(bendScrollbar);
    p.add(bendLabel);
    p.add(new Label("Vel:"));
    p.add(velocityScrollbar);
    p.add(velocityLabel);
    p.add(new Label("Press:"));
    p.add(pressureScrollbar);
    p.add(pressureLabel);
    
    p1.add(sustainCheckbox);
    p1.add(muteCheckbox);
    p1.add(monoCheckbox);
    p1.add(soloCheckbox);
    p1.add(statusButton);
    p1.add(soundOffButton);
    p1.add(quitButton);
    
    add(p);
    add(p1);
      
    setTitle("General MIDI");
    setSize(800, 400);
    setVisible(true);
  
    pack();
    show();
  
    updateGUIStatus();
  
  } // end ToySynth()
  
  final int xOffset = 40;
  final int yOffset = 10;
  
  int X (int x) {
    return (x*4 + xOffset);
  }
  
  int Y (int x) {
    return (x*4 + yOffset);
  }
  
  int D (int x) {
    return (x*4);
  }
  
  public void updateGUIStatus() {
  
    // update all the GUI fields to reflect the status 
    // of the current channel
    // NOTE: THIS IS NOT FUNCTIONAL IN JAVA SOUND 
    // 0.85 EA RELEASE
  
    //int temp;
      
    //// volume
    //temp = 
    midiChannels[channelNumber].getController(
      VOLUME_CONTROLLER);
    //volScrollbar.setValue( - temp );
    //volLabel.setText( Integer.toString( temp ));
    //// pan
    //temp = 
    midiChannels[channelNumber].getController(
      PAN_CONTROLLER);
    //panScrollbar.setValue( - temp );
    //panLabel.setText( Integer.toString( temp ));
    //// pitch bend
    //temp = midiChannels[channelNumber].getPitchBend();
    //bendScrollbar.setValue( - temp );
    //bendLabel.setText( Integer.toString( temp ));
    //// reverb
    //temp = 
    midiChannels[channelNumber].getController(
      REVERB_LEVEL_CONTROLLER);
    //revScrollbar.setValue( - temp );
    //revLabel.setText( Integer.toString( temp ));
    //// pressure
    //temp = 
    //midiChannels[channelNumber].getChannelPressure();
    //pressureScrollbar.setValue( - temp );
    //pressureLabel.setText( Integer.toString( temp ));
    //// mute
    //muteCheckbox.setState( 
    midiChannels[channelNumber].getMute() );
    //// sustain
    //sustainCheckbox.setState( 
    midiChannels[channelNumber].getController(
      SUSTAIN_CONTROLLER)==0 ? false : true  );
    //// mono
    //monoCheckbox.setState( 
    midiChannels[channelNumber].getMono() );
    //// solo
    //soloCheckbox.setState( 
    midiChannels[channelNumber].getSolo() );
  
  }
  
  public void printStatus() {
  
    System.out.println(
      "CURRENT STATUS - note that some 
      functionality here is not");
    System.out.println(
      "                 implemented in Java 
      Sound 0.86");
    System.out.println("  Current channel     : " + 
      channelNumber);
    System.out.println("  Program             : " + 
      midiChannels[channelNumber].getProgram() );
    System.out.println("  Channel volume      : " + 
      midiChannels[channelNumber].getController(
      VOLUME_CONTROLLER) );
    System.out.println("  Channel pan         : " + 
    midiChannels[channelNumber].getController(
      PAN_CONTROLLER) );
    System.out.println("  Channel bend        : " + 
      midiChannels[channelNumber].getPitchBend() );
    System.out.println("  Channel pressure    : " + 
      midiChannels[channelNumber].getChannelPressure() );
    System.out.println("  Channel reverb      : " + 
      midiChannels[channelNumber].getController(
      REVERB_CONTROLLER) );
    System.out.println("  Channel reverb level: " + 
      midiChannels[channelNumber].getController(
      REVERB_LEVEL_CONTROLLER) );
    System.out.println("  Channel sustain     : " + 
      midiChannels[channelNumber].getController(
      SUSTAIN_CONTROLLER) );
    System.out.println("  Channel mute        : " + 
      midiChannels[channelNumber].getMute() );
    System.out.println("  Channel mono        : " + 
      midiChannels[channelNumber].getMono() );
    System.out.println("  Channel solo        : " + 
      midiChannels[channelNumber].getSolo() );
  
  }
  
  public void mouseClicked(MouseEvent e) {
    
  }

  public void mousePressed(MouseEvent e) {
  
    Component component = e.getComponent();    
    if ( ! (component instanceof Label) )
      return;
  
    int keyNumber = 
      ((pianoKey) component).keyNumber + transpose;
  
    if (singleNoteMode) {
      lastKeyNumber = keyNumber;
      midiChannels[channelNumber].noteOn( 
        keyNumber, velocity);
      return;
    }
  }
  
  public void mouseReleased(MouseEvent e) {
  
    Component component = e.getComponent();    
    if ( ! (component instanceof Label) )
      return;
  
    if (singleNoteMode) {
      midiChannels[channelNumber].noteOff( 
        lastKeyNumber, velocity);
      return;
    }
  }
  
  public void mouseEntered(MouseEvent e) {
      
    //System.out.println(
    //  "mouseEntered event handler...");
  }
  
  public void mouseExited(MouseEvent e) {
  
    //System.out.println("mouseExited event handler...");
  }
  
  // -------------------
  // class programChange
  // -------------------
  
  class programChange implements ItemListener {
  
    ToySynth ts = null;
  
    public programChange( ToySynth ts ) {
      this.ts = ts;
    }
    public void itemStateChanged(ItemEvent e) {
  
      Object component = e.getSource();
      if( ! (component instanceof Choice) ) return;
  
      Choice c = (Choice)component;
      int index=0;
  
      if (c.equals(instr[0]))
        index = 0 + c.getSelectedIndex();
      else if (c.equals(instr[1]))      
        index = 16 + c.getSelectedIndex();
      else if (c.equals(instr[2]))
        index = 32 + c.getSelectedIndex();
      else if (c.equals(instr[3]))
        index = 48 + c.getSelectedIndex();
      else if (c.equals(instr[4]))
        index = 64 + c.getSelectedIndex();
      else if (c.equals(instr[5]))
        index = 80 + c.getSelectedIndex();
      else if (c.equals(instr[6]))
        index = 96 + c.getSelectedIndex();
      else if (c.equals(instr[7]))
        index = 112 + c.getSelectedIndex();
            
  
      synth.loadInstrument( instruments[index] );
      midiChannels[channelNumber].programChange(index);
        
        
      instrumentLabel.setText ( "Instrument: " + 
        instruments[index].getName() );
  
      ts.validate();
    }
  }
  
  class channelChange implements ItemListener {
  
    ToySynth ts;
  
    public channelChange( ToySynth ts ) {
      this.ts = ts;
    }
    public void itemStateChanged(ItemEvent e) {
  
      Object component = e.getSource();
      if( ! (component instanceof Choice) ) return;
      Choice c = (Choice)component;
      int newchannel = c.getSelectedIndex();
  
      // update the channel
      channelNumber = newchannel;
        
      // update GUI fields for status of this channel
      instrumentLabel.setText ( "Instrument: " +  
        instruments[midiChannels[
        channelNumber].getProgram()].getName() );
  
      ts.updateGUIStatus();
      ts.validate();
    }
  }
  
  // --------------
  // class pianoKey
  // --------------
  
  class pianoKey extends Label {
    public int keyNumber;
  
    pianoKey(int keyNumber, boolean white) {
      this.keyNumber = keyNumber;
      if (white) {
        setBackground(Color.white);
      }
      else
        setBackground(Color.black);
    }
    public void paint (Graphics g) {
      g.drawRect(0, 0, getSize().width - 1, 
        getSize().height -1 );
    }
    public void middleC(Graphics g) {
      Graphics2D g2 = (Graphics2D) g;
      int x = getSize().width / 2;
      int y = getSize().height - getSize().height / 4;
      g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(Color.blue);
      g2.fillOval(x, y, 3, 3);
    }
  } 
  
  // ----
  // MAIN
  // ----
  
  public static void main( String[] args) {           
    ToySynth ts = new ToySynth();
  }
}
  
  /*
   * "@(#)ToySynth.java  1.6 99/04/22
   *
   * Copyright (c) 1999 Sun Microsystems, Inc. All 
   * Rights Reserved.
   *
   * Sun grants you ("Licensee") a non-exclusive, 
   * royalty free, license to use, modify and 
   * redistribute this software in source and binary 
   * code form, provided that i) this copyright notice 
   * and license appear on all copies of the software; 
   * and ii) Licensee does not utilize the software in 
   * a manner which is disparaging to Sun.
   *
   * This software is provided "AS IS," without a 
   * warranty of any kind. ALL EXPRESS OR IMPLIED 
   * CONDITIONS, REPRESENTATIONS AND WARRANTIES, 
   * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
   * FITNESS FOR A PARTICULAR PURPOSE OR
   * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS 
   * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES 
   * SUFFERED BY LICENSEE AS A RESULT OF USING, 
   * MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS 
   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS 
   * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR 
   * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
   * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED 
   * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING 
   * OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, 
   * EVEN IF SUN HAS BEEN ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGES.
   *
   * This software is not designed or intended for use 
   * in on-line control of aircraft, air traffic, 
   * aircraft navigation or aircraft communications; or 
   * in the design, construction, operation or 
   * maintenance of any nuclear facility. Licensee 
   * represents and warrants that it will not use or
   * redistribute the Software for such purposes.
   */