<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://www.jexp.ru/index.php?action=history&amp;feed=atom&amp;title=Java%2FDevelopment_Class%2FMIDI</id>
		<title>Java/Development Class/MIDI - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://www.jexp.ru/index.php?action=history&amp;feed=atom&amp;title=Java%2FDevelopment_Class%2FMIDI"/>
		<link rel="alternate" type="text/html" href="http://www.jexp.ru/index.php?title=Java/Development_Class/MIDI&amp;action=history"/>
		<updated>2026-04-22T21:59:07Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://www.jexp.ru/index.php?title=Java/Development_Class/MIDI&amp;diff=8345&amp;oldid=prev</id>
		<title>Admin: 1 версия</title>
		<link rel="alternate" type="text/html" href="http://www.jexp.ru/index.php?title=Java/Development_Class/MIDI&amp;diff=8345&amp;oldid=prev"/>
				<updated>2010-06-01T06:59:33Z</updated>
		
		<summary type="html">&lt;p&gt;1 версия&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr style=&quot;vertical-align: top;&quot; lang=&quot;ru&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;← Предыдущая&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;Версия 06:59, 1 июня 2010&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; style=&quot;text-align: center;&quot; lang=&quot;ru&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(нет различий)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Admin</name></author>	</entry>

	<entry>
		<id>http://www.jexp.ru/index.php?title=Java/Development_Class/MIDI&amp;diff=8344&amp;oldid=prev</id>
		<title> в 18:01, 31 мая 2010</title>
		<link rel="alternate" type="text/html" href="http://www.jexp.ru/index.php?title=Java/Development_Class/MIDI&amp;diff=8344&amp;oldid=prev"/>
				<updated>2010-05-31T18:01:46Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== A Swing component that can load and play a sound clip, displaying progress and controls ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- start source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
    &amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2004 David Flanagan.  All rights reserved.&lt;br /&gt;
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.&lt;br /&gt;
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.&lt;br /&gt;
 * You may study, use, and modify it for any non-commercial purpose,&lt;br /&gt;
 * including teaching and use in open-source projects.&lt;br /&gt;
 * You may distribute it non-commercially as long as you retain this notice.&lt;br /&gt;
 * For a commercial use license, or to purchase the book, &lt;br /&gt;
 * please visit http://www.davidflanagan.ru/javaexamples3.&lt;br /&gt;
 */&lt;br /&gt;
import java.awt.event.ActionEvent;&lt;br /&gt;
import java.awt.event.ActionListener;&lt;br /&gt;
import java.io.File;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
import javax.sound.midi.InvalidMidiDataException;&lt;br /&gt;
import javax.sound.midi.MidiSystem;&lt;br /&gt;
import javax.sound.midi.MidiUnavailableException;&lt;br /&gt;
import javax.sound.midi.Receiver;&lt;br /&gt;
import javax.sound.midi.Sequence;&lt;br /&gt;
import javax.sound.midi.Sequencer;&lt;br /&gt;
import javax.sound.midi.Synthesizer;&lt;br /&gt;
import javax.sound.midi.Track;&lt;br /&gt;
import javax.sound.midi.Transmitter;&lt;br /&gt;
import javax.sound.sampled.AudioInputStream;&lt;br /&gt;
import javax.sound.sampled.AudioSystem;&lt;br /&gt;
import javax.sound.sampled.Clip;&lt;br /&gt;
import javax.sound.sampled.DataLine;&lt;br /&gt;
import javax.sound.sampled.FloatControl;&lt;br /&gt;
import javax.sound.sampled.LineUnavailableException;&lt;br /&gt;
import javax.sound.sampled.UnsupportedAudioFileException;&lt;br /&gt;
import javax.swing.Box;&lt;br /&gt;
import javax.swing.BoxLayout;&lt;br /&gt;
import javax.swing.JButton;&lt;br /&gt;
import javax.swing.JCheckBox;&lt;br /&gt;
import javax.swing.JComponent;&lt;br /&gt;
import javax.swing.JFrame;&lt;br /&gt;
import javax.swing.JLabel;&lt;br /&gt;
import javax.swing.JSlider;&lt;br /&gt;
import javax.swing.Timer;&lt;br /&gt;
import javax.swing.border.TitledBorder;&lt;br /&gt;
import javax.swing.event.ChangeEvent;&lt;br /&gt;
import javax.swing.event.ChangeListener;&lt;br /&gt;
/**&lt;br /&gt;
 * This class is a Swing component that can load and play a sound clip,&lt;br /&gt;
 * displaying progress and controls. The main() method is a test program. This&lt;br /&gt;
 * component can play sampled audio or MIDI files, but handles them differently.&lt;br /&gt;
 * For sampled audio, time is reported in microseconds, tracked in milliseconds&lt;br /&gt;
 * and displayed in seconds and tenths of seconds. For midi files time is&lt;br /&gt;
 * reported, tracked, and displayed in MIDI &amp;quot;ticks&amp;quot;. This program does no&lt;br /&gt;
 * transcoding, so it can only play sound files that use the PCM encoding.&lt;br /&gt;
 */&lt;br /&gt;
public class SoundPlayer extends JComponent {&lt;br /&gt;
  boolean midi; // Are we playing a midi file or a sampled one?&lt;br /&gt;
  Sequence sequence; // The contents of a MIDI file&lt;br /&gt;
  Sequencer sequencer; // We play MIDI Sequences with a Sequencer&lt;br /&gt;
  Clip clip; // Contents of a sampled audio file&lt;br /&gt;
  boolean playing = false; // whether the sound is current playing&lt;br /&gt;
  // Length and position of the sound are measured in milliseconds for&lt;br /&gt;
  // sampled sounds and MIDI &amp;quot;ticks&amp;quot; for MIDI sounds&lt;br /&gt;
  int audioLength; // Length of the sound.&lt;br /&gt;
  int audioPosition = 0; // Current position within the sound&lt;br /&gt;
  // The following fields are for the GUI&lt;br /&gt;
  JButton play; // The Play/Stop button&lt;br /&gt;
  JSlider progress; // Shows and sets current position in sound&lt;br /&gt;
  JLabel time; // Displays audioPosition as a number&lt;br /&gt;
  Timer timer; // Updates slider every 100 milliseconds&lt;br /&gt;
  // The main method just creates an SoundPlayer in a Frame and displays it&lt;br /&gt;
  public static void main(String[] args) throws IOException, UnsupportedAudioFileException,&lt;br /&gt;
      LineUnavailableException, MidiUnavailableException, InvalidMidiDataException {&lt;br /&gt;
    SoundPlayer player;&lt;br /&gt;
    File file = new File(args[0]); // This is the file we&amp;quot;ll be playing&lt;br /&gt;
    // Determine whether it is midi or sampled audio&lt;br /&gt;
    boolean ismidi;&lt;br /&gt;
    try {&lt;br /&gt;
      // We discard the return value of this method; we just need to know&lt;br /&gt;
      // whether it returns successfully or throws an exception&lt;br /&gt;
      MidiSystem.getMidiFileFormat(file);&lt;br /&gt;
      ismidi = true;&lt;br /&gt;
    } catch (InvalidMidiDataException e) {&lt;br /&gt;
      ismidi = false;&lt;br /&gt;
    }&lt;br /&gt;
    // Create a SoundPlayer object to play the sound.&lt;br /&gt;
    player = new SoundPlayer(file, ismidi);&lt;br /&gt;
    // Put it in a window and play it&lt;br /&gt;
    JFrame f = new JFrame(&amp;quot;SoundPlayer&amp;quot;);&lt;br /&gt;
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&lt;br /&gt;
    f.getContentPane().add(player, &amp;quot;Center&amp;quot;);&lt;br /&gt;
    f.pack();&lt;br /&gt;
    f.setVisible(true);&lt;br /&gt;
  }&lt;br /&gt;
  // Create an SoundPlayer component for the specified file.&lt;br /&gt;
  public SoundPlayer(File f, boolean isMidi) throws IOException, UnsupportedAudioFileException,&lt;br /&gt;
      LineUnavailableException, MidiUnavailableException, InvalidMidiDataException {&lt;br /&gt;
    if (isMidi) { // The file is a MIDI file&lt;br /&gt;
      midi = true;&lt;br /&gt;
      // First, get a Sequencer to play sequences of MIDI events&lt;br /&gt;
      // That is, to send events to a Synthesizer at the right time.&lt;br /&gt;
      sequencer = MidiSystem.getSequencer(); // Used to play sequences&lt;br /&gt;
      sequencer.open(); // Turn it on.&lt;br /&gt;
      // Get a Synthesizer for the Sequencer to send notes to&lt;br /&gt;
      Synthesizer synth = MidiSystem.getSynthesizer();&lt;br /&gt;
      synth.open(); // acquire whatever resources it needs&lt;br /&gt;
      // The Sequencer obtained above may be connected to a Synthesizer&lt;br /&gt;
      // by default, or it may not. Therefore, we explicitly connect it.&lt;br /&gt;
      Transmitter transmitter = sequencer.getTransmitter();&lt;br /&gt;
      Receiver receiver = synth.getReceiver();&lt;br /&gt;
      transmitter.setReceiver(receiver);&lt;br /&gt;
      // Read the sequence from the file and tell the sequencer about it&lt;br /&gt;
      sequence = MidiSystem.getSequence(f);&lt;br /&gt;
      sequencer.setSequence(sequence);&lt;br /&gt;
      audioLength = (int) sequence.getTickLength(); // Get sequence length&lt;br /&gt;
    } else { // The file is sampled audio&lt;br /&gt;
      midi = false;&lt;br /&gt;
      // Getting a Clip object for a file of sampled audio data is kind&lt;br /&gt;
      // of cumbersome. The following lines do what we need.&lt;br /&gt;
      AudioInputStream ain = AudioSystem.getAudioInputStream(f);&lt;br /&gt;
      try {&lt;br /&gt;
        DataLine.Info info = new DataLine.Info(Clip.class, ain.getFormat());&lt;br /&gt;
        clip = (Clip) AudioSystem.getLine(info);&lt;br /&gt;
        clip.open(ain);&lt;br /&gt;
      } finally { // We&amp;quot;re done with the input stream.&lt;br /&gt;
        ain.close();&lt;br /&gt;
      }&lt;br /&gt;
      // Get the clip length in microseconds and convert to milliseconds&lt;br /&gt;
      audioLength = (int) (clip.getMicrosecondLength() / 1000);&lt;br /&gt;
    }&lt;br /&gt;
    // Now create the basic GUI&lt;br /&gt;
    play = new JButton(&amp;quot;Play&amp;quot;); // Play/stop button&lt;br /&gt;
    progress = new JSlider(0, audioLength, 0); // Shows position in sound&lt;br /&gt;
    time = new JLabel(&amp;quot;0&amp;quot;); // Shows position as a #&lt;br /&gt;
    // When clicked, start or stop playing the sound&lt;br /&gt;
    play.addActionListener(new ActionListener() {&lt;br /&gt;
      public void actionPerformed(ActionEvent e) {&lt;br /&gt;
        if (playing)&lt;br /&gt;
          stop();&lt;br /&gt;
        else&lt;br /&gt;
          play();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    // Whenever the slider value changes, first update the time label.&lt;br /&gt;
    // Next, if we&amp;quot;re not already at the new position, skip to it.&lt;br /&gt;
    progress.addChangeListener(new ChangeListener() {&lt;br /&gt;
      public void stateChanged(ChangeEvent e) {&lt;br /&gt;
        int value = progress.getValue();&lt;br /&gt;
        // Update the time label&lt;br /&gt;
        if (midi)&lt;br /&gt;
          time.setText(value + &amp;quot;&amp;quot;);&lt;br /&gt;
        else&lt;br /&gt;
          time.setText(value / 1000 + &amp;quot;.&amp;quot; + (value % 1000) / 100);&lt;br /&gt;
        // If we&amp;quot;re not already there, skip there.&lt;br /&gt;
        if (value != audioPosition)&lt;br /&gt;
          skip(value);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    // This timer calls the tick() method 10 times a second to keep&lt;br /&gt;
    // our slider in sync with the music.&lt;br /&gt;
    timer = new javax.swing.Timer(100, new ActionListener() {&lt;br /&gt;
      public void actionPerformed(ActionEvent e) {&lt;br /&gt;
        tick();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    // put those controls in a row&lt;br /&gt;
    Box row = Box.createHorizontalBox();&lt;br /&gt;
    row.add(play);&lt;br /&gt;
    row.add(progress);&lt;br /&gt;
    row.add(time);&lt;br /&gt;
    // And add them to this component.&lt;br /&gt;
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));&lt;br /&gt;
    this.add(row);&lt;br /&gt;
    // Now add additional controls based on the type of the sound&lt;br /&gt;
    if (midi)&lt;br /&gt;
      addMidiControls();&lt;br /&gt;
    else&lt;br /&gt;
      addSampledControls();&lt;br /&gt;
  }&lt;br /&gt;
  /** Start playing the sound at the current position */&lt;br /&gt;
  public void play() {&lt;br /&gt;
    if (midi)&lt;br /&gt;
      sequencer.start();&lt;br /&gt;
    else&lt;br /&gt;
      clip.start();&lt;br /&gt;
    timer.start();&lt;br /&gt;
    play.setText(&amp;quot;Stop&amp;quot;);&lt;br /&gt;
    playing = true;&lt;br /&gt;
  }&lt;br /&gt;
  /** Stop playing the sound, but retain the current position */&lt;br /&gt;
  public void stop() {&lt;br /&gt;
    timer.stop();&lt;br /&gt;
    if (midi)&lt;br /&gt;
      sequencer.stop();&lt;br /&gt;
    else&lt;br /&gt;
      clip.stop();&lt;br /&gt;
    play.setText(&amp;quot;Play&amp;quot;);&lt;br /&gt;
    playing = false;&lt;br /&gt;
  }&lt;br /&gt;
  /** Stop playing the sound and reset the position to 0 */&lt;br /&gt;
  public void reset() {&lt;br /&gt;
    stop();&lt;br /&gt;
    if (midi)&lt;br /&gt;
      sequencer.setTickPosition(0);&lt;br /&gt;
    else&lt;br /&gt;
      clip.setMicrosecondPosition(0);&lt;br /&gt;
    audioPosition = 0;&lt;br /&gt;
    progress.setValue(0);&lt;br /&gt;
  }&lt;br /&gt;
  /** Skip to the specified position */&lt;br /&gt;
  public void skip(int position) { // Called when user drags the slider&lt;br /&gt;
    if (position &amp;lt; 0 || position &amp;gt; audioLength)&lt;br /&gt;
      return;&lt;br /&gt;
    audioPosition = position;&lt;br /&gt;
    if (midi)&lt;br /&gt;
      sequencer.setTickPosition(position);&lt;br /&gt;
    else&lt;br /&gt;
      clip.setMicrosecondPosition(position * 1000);&lt;br /&gt;
    progress.setValue(position); // in case skip() is called from outside&lt;br /&gt;
  }&lt;br /&gt;
  /** Return the length of the sound in ms or ticks */&lt;br /&gt;
  public int getLength() {&lt;br /&gt;
    return audioLength;&lt;br /&gt;
  }&lt;br /&gt;
  // An internal method that updates the progress bar.&lt;br /&gt;
  // The Timer object calls it 10 times a second.&lt;br /&gt;
  // If the sound has finished, it resets to the beginning&lt;br /&gt;
  void tick() {&lt;br /&gt;
    if (midi &amp;amp;&amp;amp; sequencer.isRunning()) {&lt;br /&gt;
      audioPosition = (int) sequencer.getTickPosition();&lt;br /&gt;
      progress.setValue(audioPosition);&lt;br /&gt;
    } else if (!midi &amp;amp;&amp;amp; clip.isActive()) {&lt;br /&gt;
      audioPosition = (int) (clip.getMicrosecondPosition() / 1000);&lt;br /&gt;
      progress.setValue(audioPosition);&lt;br /&gt;
    } else&lt;br /&gt;
      reset();&lt;br /&gt;
  }&lt;br /&gt;
  // For sampled sounds, add sliders to control volume and balance&lt;br /&gt;
  void addSampledControls() {&lt;br /&gt;
    try {&lt;br /&gt;
      FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);&lt;br /&gt;
      if (gainControl != null)&lt;br /&gt;
        this.add(createSlider(gainControl));&lt;br /&gt;
    } catch (IllegalArgumentException e) {&lt;br /&gt;
      // If MASTER_GAIN volume control is unsupported, just skip it&lt;br /&gt;
    }&lt;br /&gt;
    try {&lt;br /&gt;
      // FloatControl.Type.BALANCE is probably the correct control to&lt;br /&gt;
      // use here, but it doesn&amp;quot;t work for me, so I use PAN instead.&lt;br /&gt;
      FloatControl panControl = (FloatControl) clip.getControl(FloatControl.Type.PAN);&lt;br /&gt;
      if (panControl != null)&lt;br /&gt;
        this.add(createSlider(panControl));&lt;br /&gt;
    } catch (IllegalArgumentException e) {&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  // Return a JSlider component to manipulate the supplied FloatControl&lt;br /&gt;
  // for sampled audio.&lt;br /&gt;
  JSlider createSlider(final FloatControl c) {&lt;br /&gt;
    if (c == null)&lt;br /&gt;
      return null;&lt;br /&gt;
    final JSlider s = new JSlider(0, 1000);&lt;br /&gt;
    final float min = c.getMinimum();&lt;br /&gt;
    final float max = c.getMaximum();&lt;br /&gt;
    final float width = max - min;&lt;br /&gt;
    float fval = c.getValue();&lt;br /&gt;
    s.setValue((int) ((fval - min) / width * 1000));&lt;br /&gt;
    java.util.Hashtable labels = new java.util.Hashtable(3);&lt;br /&gt;
    labels.put(new Integer(0), new JLabel(c.getMinLabel()));&lt;br /&gt;
    labels.put(new Integer(500), new JLabel(c.getMidLabel()));&lt;br /&gt;
    labels.put(new Integer(1000), new JLabel(c.getMaxLabel()));&lt;br /&gt;
    s.setLabelTable(labels);&lt;br /&gt;
    s.setPaintLabels(true);&lt;br /&gt;
    s.setBorder(new TitledBorder(c.getType().toString() + &amp;quot; &amp;quot; + c.getUnits()));&lt;br /&gt;
    s.addChangeListener(new ChangeListener() {&lt;br /&gt;
      public void stateChanged(ChangeEvent e) {&lt;br /&gt;
        int i = s.getValue();&lt;br /&gt;
        float f = min + (i * width / 1000.0f);&lt;br /&gt;
        c.setValue(f);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    return s;&lt;br /&gt;
  }&lt;br /&gt;
  // For Midi files, create a JSlider to control the tempo,&lt;br /&gt;
  // and create JCheckBoxes to mute or solo each MIDI track.&lt;br /&gt;
  void addMidiControls() {&lt;br /&gt;
    // Add a slider to control the tempo&lt;br /&gt;
    final JSlider tempo = new JSlider(50, 200);&lt;br /&gt;
    tempo.setValue((int) (sequencer.getTempoFactor() * 100));&lt;br /&gt;
    tempo.setBorder(new TitledBorder(&amp;quot;Tempo Adjustment (%)&amp;quot;));&lt;br /&gt;
    java.util.Hashtable labels = new java.util.Hashtable();&lt;br /&gt;
    labels.put(new Integer(50), new JLabel(&amp;quot;50%&amp;quot;));&lt;br /&gt;
    labels.put(new Integer(100), new JLabel(&amp;quot;100%&amp;quot;));&lt;br /&gt;
    labels.put(new Integer(200), new JLabel(&amp;quot;200%&amp;quot;));&lt;br /&gt;
    tempo.setLabelTable(labels);&lt;br /&gt;
    tempo.setPaintLabels(true);&lt;br /&gt;
    // The event listener actually changes the tmpo&lt;br /&gt;
    tempo.addChangeListener(new ChangeListener() {&lt;br /&gt;
      public void stateChanged(ChangeEvent e) {&lt;br /&gt;
        sequencer.setTempoFactor(tempo.getValue() / 100.0f);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    this.add(tempo);&lt;br /&gt;
    // Create rows of solo and checkboxes for each track&lt;br /&gt;
    Track[] tracks = sequence.getTracks();&lt;br /&gt;
    for (int i = 0; i &amp;lt; tracks.length; i++) {&lt;br /&gt;
      final int tracknum = i;&lt;br /&gt;
      // Two checkboxes per track&lt;br /&gt;
      final JCheckBox solo = new JCheckBox(&amp;quot;solo&amp;quot;);&lt;br /&gt;
      final JCheckBox mute = new JCheckBox(&amp;quot;mute&amp;quot;);&lt;br /&gt;
      // The listeners solo or mute the track&lt;br /&gt;
      solo.addActionListener(new ActionListener() {&lt;br /&gt;
        public void actionPerformed(ActionEvent e) {&lt;br /&gt;
          sequencer.setTrackSolo(tracknum, solo.isSelected());&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
      mute.addActionListener(new ActionListener() {&lt;br /&gt;
        public void actionPerformed(ActionEvent e) {&lt;br /&gt;
          sequencer.setTrackMute(tracknum, mute.isSelected());&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
      // Build up a row&lt;br /&gt;
      Box box = Box.createHorizontalBox();&lt;br /&gt;
      box.add(new JLabel(&amp;quot;Track &amp;quot; + tracknum));&lt;br /&gt;
      box.add(Box.createHorizontalStrut(10));&lt;br /&gt;
      box.add(solo);&lt;br /&gt;
      box.add(Box.createHorizontalStrut(10));&lt;br /&gt;
      box.add(mute);&lt;br /&gt;
      box.add(Box.createHorizontalGlue());&lt;br /&gt;
      // And add it to this component&lt;br /&gt;
      this.add(box);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- end source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Play Piano ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- start source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
    &amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2004 David Flanagan.  All rights reserved.&lt;br /&gt;
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.&lt;br /&gt;
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.&lt;br /&gt;
 * You may study, use, and modify it for any non-commercial purpose,&lt;br /&gt;
 * including teaching and use in open-source projects.&lt;br /&gt;
 * You may distribute it non-commercially as long as you retain this notice.&lt;br /&gt;
 * For a commercial use license, or to purchase the book, &lt;br /&gt;
 * please visit http://www.davidflanagan.ru/javaexamples3.&lt;br /&gt;
 */&lt;br /&gt;
import java.io.File;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
import javax.sound.midi.InvalidMidiDataException;&lt;br /&gt;
import javax.sound.midi.MetaEventListener;&lt;br /&gt;
import javax.sound.midi.MetaMessage;&lt;br /&gt;
import javax.sound.midi.MidiEvent;&lt;br /&gt;
import javax.sound.midi.MidiSystem;&lt;br /&gt;
import javax.sound.midi.MidiUnavailableException;&lt;br /&gt;
import javax.sound.midi.Sequence;&lt;br /&gt;
import javax.sound.midi.Sequencer;&lt;br /&gt;
import javax.sound.midi.ShortMessage;&lt;br /&gt;
import javax.sound.midi.Synthesizer;&lt;br /&gt;
import javax.sound.midi.Track;&lt;br /&gt;
public class PlayerPiano {&lt;br /&gt;
  // These are some MIDI constants from the spec. They aren&amp;quot;t defined&lt;br /&gt;
  // for us in javax.sound.midi.&lt;br /&gt;
  public static final int DAMPER_PEDAL = 64;&lt;br /&gt;
  public static final int DAMPER_ON = 127;&lt;br /&gt;
  public static final int DAMPER_OFF = 0;&lt;br /&gt;
  public static final int END_OF_TRACK = 47;&lt;br /&gt;
  public static void main(String[] args) throws MidiUnavailableException, InvalidMidiDataException,&lt;br /&gt;
      IOException {&lt;br /&gt;
    int instrument = 0;&lt;br /&gt;
    int tempo = 120;&lt;br /&gt;
    String filename = null;&lt;br /&gt;
    // Parse the options&lt;br /&gt;
    // -i &amp;lt;instrument number&amp;gt; default 0, a piano. Allowed values: 0-127&lt;br /&gt;
    // -t &amp;lt;beats per minute&amp;gt; default tempo is 120 quarter notes per minute&lt;br /&gt;
    // -o &amp;lt;filename&amp;gt; save to a midi file instead of playing&lt;br /&gt;
    int a = 0;&lt;br /&gt;
    while (a &amp;lt; args.length) {&lt;br /&gt;
      if (args[a].equals(&amp;quot;-i&amp;quot;)) {&lt;br /&gt;
        instrument = Integer.parseInt(args[a + 1]);&lt;br /&gt;
        a += 2;&lt;br /&gt;
      } else if (args[a].equals(&amp;quot;-t&amp;quot;)) {&lt;br /&gt;
        tempo = Integer.parseInt(args[a + 1]);&lt;br /&gt;
        a += 2;&lt;br /&gt;
      } else if (args[a].equals(&amp;quot;-o&amp;quot;)) {&lt;br /&gt;
        filename = args[a + 1];&lt;br /&gt;
        a += 2;&lt;br /&gt;
      } else&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
    char[] notes = args[a].toCharArray();&lt;br /&gt;
    // 16 ticks per quarter note.&lt;br /&gt;
    Sequence sequence = new Sequence(Sequence.PPQ, 16);&lt;br /&gt;
    // Add the specified notes to the track&lt;br /&gt;
    addTrack(sequence, instrument, tempo, notes);&lt;br /&gt;
    if (filename == null) { // no filename, so play the notes&lt;br /&gt;
      // Set up the Sequencer and Synthesizer objects&lt;br /&gt;
      Sequencer sequencer = MidiSystem.getSequencer();&lt;br /&gt;
      sequencer.open();&lt;br /&gt;
      Synthesizer synthesizer = MidiSystem.getSynthesizer();&lt;br /&gt;
      synthesizer.open();&lt;br /&gt;
      sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());&lt;br /&gt;
      // Specify the sequence to play, and the tempo to play it at&lt;br /&gt;
      sequencer.setSequence(sequence);&lt;br /&gt;
      sequencer.setTempoInBPM(tempo);&lt;br /&gt;
      // Let us know when it is done playing&lt;br /&gt;
      sequencer.addMetaEventListener(new MetaEventListener() {&lt;br /&gt;
        public void meta(MetaMessage m) {&lt;br /&gt;
          // A message of this type is automatically sent&lt;br /&gt;
          // when we reach the end of the track&lt;br /&gt;
          if (m.getType() == END_OF_TRACK)&lt;br /&gt;
            System.exit(0);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
      // And start playing now.&lt;br /&gt;
      sequencer.start();&lt;br /&gt;
    } else { // A file name was specified, so save the notes&lt;br /&gt;
      int[] allowedTypes = MidiSystem.getMidiFileTypes(sequence);&lt;br /&gt;
      if (allowedTypes.length == 0) {&lt;br /&gt;
        System.err.println(&amp;quot;No supported MIDI file types.&amp;quot;);&lt;br /&gt;
      } else {&lt;br /&gt;
        MidiSystem.write(sequence, allowedTypes[0], new File(filename));&lt;br /&gt;
        System.exit(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  static final int[] offsets = { // add these amounts to the base value&lt;br /&gt;
  // A B C D E F G&lt;br /&gt;
      -4, -2, 0, 1, 3, 5, 7 };&lt;br /&gt;
  /*&lt;br /&gt;
   * This method parses the specified char[] of notes into a Track. The musical&lt;br /&gt;
   * notation is the following: A-G: A named note; Add b for flat and # for&lt;br /&gt;
   * sharp. +: Move up one octave. Persists. -: Move down one octave. Persists.&lt;br /&gt;
   * /1: Notes are whole notes. Persists &amp;quot;till changed /2: Half notes /4:&lt;br /&gt;
   * Quarter notes /n: N can also be, 8, 16, 32, 64. s: Toggle sustain pedal on&lt;br /&gt;
   * or off (initially off)&lt;br /&gt;
   *  &amp;gt;: Louder. Persists &amp;lt;: Softer. Persists .: Rest. Length depends on current&lt;br /&gt;
   * length setting Space: Play the previous note or notes; notes not separated&lt;br /&gt;
   * by spaces are played at the same time&lt;br /&gt;
   */&lt;br /&gt;
  public static void addTrack(Sequence s, int instrument, int tempo, char[] notes)&lt;br /&gt;
      throws InvalidMidiDataException {&lt;br /&gt;
    Track track = s.createTrack(); // Begin with a new track&lt;br /&gt;
    // Set the instrument on channel 0&lt;br /&gt;
    ShortMessage sm = new ShortMessage();&lt;br /&gt;
    sm.setMessage(ShortMessage.PROGRAM_CHANGE, 0, instrument, 0);&lt;br /&gt;
    track.add(new MidiEvent(sm, 0));&lt;br /&gt;
    int n = 0; // current character in notes[] array&lt;br /&gt;
    int t = 0; // time in ticks for the composition&lt;br /&gt;
    // These values persist and apply to all notes &amp;quot;till changed&lt;br /&gt;
    int notelength = 16; // default to quarter notes&lt;br /&gt;
    int velocity = 64; // default to middle volume&lt;br /&gt;
    int basekey = 60; // 60 is middle C. Adjusted up and down by octave&lt;br /&gt;
    boolean sustain = false; // is the sustain pedal depressed?&lt;br /&gt;
    int numnotes = 0; // How many notes in current chord?&lt;br /&gt;
    while (n &amp;lt; notes.length) {&lt;br /&gt;
      char c = notes[n++];&lt;br /&gt;
      if (c == &amp;quot;+&amp;quot;)&lt;br /&gt;
        basekey += 12; // increase octave&lt;br /&gt;
      else if (c == &amp;quot;-&amp;quot;)&lt;br /&gt;
        basekey -= 12; // decrease octave&lt;br /&gt;
      else if (c == &amp;quot;&amp;gt;&amp;quot;)&lt;br /&gt;
        velocity += 16; // increase volume;&lt;br /&gt;
      else if (c == &amp;quot;&amp;lt;&amp;quot;)&lt;br /&gt;
        velocity -= 16; // decrease volume;&lt;br /&gt;
      else if (c == &amp;quot;/&amp;quot;) {&lt;br /&gt;
        char d = notes[n++];&lt;br /&gt;
        if (d == &amp;quot;2&amp;quot;)&lt;br /&gt;
          notelength = 32; // half note&lt;br /&gt;
        else if (d == &amp;quot;4&amp;quot;)&lt;br /&gt;
          notelength = 16; // quarter note&lt;br /&gt;
        else if (d == &amp;quot;8&amp;quot;)&lt;br /&gt;
          notelength = 8; // eighth note&lt;br /&gt;
        else if (d == &amp;quot;3&amp;quot; &amp;amp;&amp;amp; notes[n++] == &amp;quot;2&amp;quot;)&lt;br /&gt;
          notelength = 2;&lt;br /&gt;
        else if (d == &amp;quot;6&amp;quot; &amp;amp;&amp;amp; notes[n++] == &amp;quot;4&amp;quot;)&lt;br /&gt;
          notelength = 1;&lt;br /&gt;
        else if (d == &amp;quot;1&amp;quot;) {&lt;br /&gt;
          if (n &amp;lt; notes.length &amp;amp;&amp;amp; notes[n] == &amp;quot;6&amp;quot;)&lt;br /&gt;
            notelength = 4; // 1/16th note&lt;br /&gt;
          else&lt;br /&gt;
            notelength = 64; // whole note&lt;br /&gt;
        }&lt;br /&gt;
      } else if (c == &amp;quot;s&amp;quot;) {&lt;br /&gt;
        sustain = !sustain;&lt;br /&gt;
        // Change the sustain setting for channel 0&lt;br /&gt;
        ShortMessage m = new ShortMessage();&lt;br /&gt;
        m&lt;br /&gt;
            .setMessage(ShortMessage.CONTROL_CHANGE, 0, DAMPER_PEDAL, sustain ? DAMPER_ON&lt;br /&gt;
                : DAMPER_OFF);&lt;br /&gt;
        track.add(new MidiEvent(m, t));&lt;br /&gt;
      } else if (c &amp;gt;= &amp;quot;A&amp;quot; &amp;amp;&amp;amp; c &amp;lt;= &amp;quot;G&amp;quot;) {&lt;br /&gt;
        int key = basekey + offsets[c - &amp;quot;A&amp;quot;];&lt;br /&gt;
        if (n &amp;lt; notes.length) {&lt;br /&gt;
          if (notes[n] == &amp;quot;b&amp;quot;) { // flat&lt;br /&gt;
            key--;&lt;br /&gt;
            n++;&lt;br /&gt;
          } else if (notes[n] == &amp;quot;#&amp;quot;) { // sharp&lt;br /&gt;
            key++;&lt;br /&gt;
            n++;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        addNote(track, t, notelength, key, velocity);&lt;br /&gt;
        numnotes++;&lt;br /&gt;
      } else if (c == &amp;quot; &amp;quot;) {&lt;br /&gt;
        // Spaces separate groups of notes played at the same time.&lt;br /&gt;
        // But we ignore them unless they follow a note or notes.&lt;br /&gt;
        if (numnotes &amp;gt; 0) {&lt;br /&gt;
          t += notelength;&lt;br /&gt;
          numnotes = 0;&lt;br /&gt;
        }&lt;br /&gt;
      } else if (c == &amp;quot;.&amp;quot;) {&lt;br /&gt;
        // Rests are like spaces in that they force any previous&lt;br /&gt;
        // note to be output (since they are never part of chords)&lt;br /&gt;
        if (numnotes &amp;gt; 0) {&lt;br /&gt;
          t += notelength;&lt;br /&gt;
          numnotes = 0;&lt;br /&gt;
        }&lt;br /&gt;
        // Now add additional rest time&lt;br /&gt;
        t += notelength;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  // A convenience method to add a note to the track on channel 0&lt;br /&gt;
  public static void addNote(Track track, int startTick, int tickLength, int key, int velocity)&lt;br /&gt;
      throws InvalidMidiDataException {&lt;br /&gt;
    ShortMessage on = new ShortMessage();&lt;br /&gt;
    on.setMessage(ShortMessage.NOTE_ON, 0, key, velocity);&lt;br /&gt;
    ShortMessage off = new ShortMessage();&lt;br /&gt;
    off.setMessage(ShortMessage.NOTE_OFF, 0, key, velocity);&lt;br /&gt;
    track.add(new MidiEvent(on, startTick));&lt;br /&gt;
    track.add(new MidiEvent(off, startTick + tickLength));&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- end source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Plays sounds streaming from a URL ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- start source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
    &amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2004 David Flanagan.  All rights reserved.&lt;br /&gt;
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.&lt;br /&gt;
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.&lt;br /&gt;
 * You may study, use, and modify it for any non-commercial purpose,&lt;br /&gt;
 * including teaching and use in open-source projects.&lt;br /&gt;
 * You may distribute it non-commercially as long as you retain this notice.&lt;br /&gt;
 * For a commercial use license, or to purchase the book, &lt;br /&gt;
 * please visit http://www.davidflanagan.ru/javaexamples3.&lt;br /&gt;
 */&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
import java.net.URL;&lt;br /&gt;
import javax.sound.midi.InvalidMidiDataException;&lt;br /&gt;
import javax.sound.midi.MetaEventListener;&lt;br /&gt;
import javax.sound.midi.MetaMessage;&lt;br /&gt;
import javax.sound.midi.MidiSystem;&lt;br /&gt;
import javax.sound.midi.MidiUnavailableException;&lt;br /&gt;
import javax.sound.midi.Sequencer;&lt;br /&gt;
import javax.sound.midi.Synthesizer;&lt;br /&gt;
import javax.sound.sampled.AudioFormat;&lt;br /&gt;
import javax.sound.sampled.AudioInputStream;&lt;br /&gt;
import javax.sound.sampled.AudioSystem;&lt;br /&gt;
import javax.sound.sampled.DataLine;&lt;br /&gt;
import javax.sound.sampled.LineUnavailableException;&lt;br /&gt;
import javax.sound.sampled.SourceDataLine;&lt;br /&gt;
import javax.sound.sampled.UnsupportedAudioFileException;&lt;br /&gt;
/**&lt;br /&gt;
 * This class plays sounds streaming from a URL: it does not have to preload the&lt;br /&gt;
 * entire sound into memory before playing it. It is a command-line application&lt;br /&gt;
 * with no gui. It includes code to convert ULAW and ALAW audio formats to PCM&lt;br /&gt;
 * so they can be played. Use the -m command-line option before MIDI files.&lt;br /&gt;
 */&lt;br /&gt;
public class PlaySoundStream {&lt;br /&gt;
  // Create a URL from the command-line argument and pass it to the&lt;br /&gt;
  // right static method depending on the presence of the -m (MIDI) option.&lt;br /&gt;
  public static void main(String[] args) throws Exception {&lt;br /&gt;
    if (args[0].equals(&amp;quot;-m&amp;quot;))&lt;br /&gt;
      streamMidiSequence(new URL(args[1]));&lt;br /&gt;
    else&lt;br /&gt;
      streamSampledAudio(new URL(args[0]));&lt;br /&gt;
    // Exit explicitly.&lt;br /&gt;
    // This is needed because the audio system starts background threads.&lt;br /&gt;
    System.exit(0);&lt;br /&gt;
  }&lt;br /&gt;
  /** Read sampled audio data from the specified URL and play it */&lt;br /&gt;
  public static void streamSampledAudio(URL url) throws IOException, UnsupportedAudioFileException,&lt;br /&gt;
      LineUnavailableException {&lt;br /&gt;
    AudioInputStream ain = null; // We read audio data from here&lt;br /&gt;
    SourceDataLine line = null; // And write it here.&lt;br /&gt;
    try {&lt;br /&gt;
      // Get an audio input stream from the URL&lt;br /&gt;
      ain = AudioSystem.getAudioInputStream(url);&lt;br /&gt;
      // Get information about the format of the stream&lt;br /&gt;
      AudioFormat format = ain.getFormat();&lt;br /&gt;
      DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);&lt;br /&gt;
      // If the format is not supported directly (i.e. if it is not PCM&lt;br /&gt;
      // encoded, then try to transcode it to PCM.&lt;br /&gt;
      if (!AudioSystem.isLineSupported(info)) {&lt;br /&gt;
        // This is the PCM format we want to transcode to.&lt;br /&gt;
        // The parameters here are audio format details that you&lt;br /&gt;
        // shouldn&amp;quot;t need to understand for casual use.&lt;br /&gt;
        AudioFormat pcm = new AudioFormat(format.getSampleRate(), 16, format.getChannels(), true,&lt;br /&gt;
            false);&lt;br /&gt;
        // Get a wrapper stream around the input stream that does the&lt;br /&gt;
        // transcoding for us.&lt;br /&gt;
        ain = AudioSystem.getAudioInputStream(pcm, ain);&lt;br /&gt;
        // Update the format and info variables for the transcoded data&lt;br /&gt;
        format = ain.getFormat();&lt;br /&gt;
        info = new DataLine.Info(SourceDataLine.class, format);&lt;br /&gt;
      }&lt;br /&gt;
      // Open the line through which we&amp;quot;ll play the streaming audio.&lt;br /&gt;
      line = (SourceDataLine) AudioSystem.getLine(info);&lt;br /&gt;
      line.open(format);&lt;br /&gt;
      // Allocate a buffer for reading from the input stream and writing&lt;br /&gt;
      // to the line. Make it large enough to hold 4k audio frames.&lt;br /&gt;
      // Note that the SourceDataLine also has its own internal buffer.&lt;br /&gt;
      int framesize = format.getFrameSize();&lt;br /&gt;
      byte[] buffer = new byte[4 * 1024 * framesize]; // the buffer&lt;br /&gt;
      int numbytes = 0; // how many bytes&lt;br /&gt;
      // We haven&amp;quot;t started the line yet.&lt;br /&gt;
      boolean started = false;&lt;br /&gt;
      for (;;) { // We&amp;quot;ll exit the loop when we reach the end of stream&lt;br /&gt;
        // First, read some bytes from the input stream.&lt;br /&gt;
        int bytesread = ain.read(buffer, numbytes, buffer.length - numbytes);&lt;br /&gt;
        // If there were no more bytes to read, we&amp;quot;re done.&lt;br /&gt;
        if (bytesread == -1)&lt;br /&gt;
          break;&lt;br /&gt;
        numbytes += bytesread;&lt;br /&gt;
        // Now that we&amp;quot;ve got some audio data, to write to the line,&lt;br /&gt;
        // start the line, so it will play that data as we write it.&lt;br /&gt;
        if (!started) {&lt;br /&gt;
          line.start();&lt;br /&gt;
          started = true;&lt;br /&gt;
        }&lt;br /&gt;
        // We must write bytes to the line in an integer multiple of&lt;br /&gt;
        // the framesize. So figure out how many bytes we&amp;quot;ll write.&lt;br /&gt;
        int bytestowrite = (numbytes / framesize) * framesize;&lt;br /&gt;
        // Now write the bytes. The line will buffer them and play&lt;br /&gt;
        // them. This call will block until all bytes are written.&lt;br /&gt;
        line.write(buffer, 0, bytestowrite);&lt;br /&gt;
        // If we didn&amp;quot;t have an integer multiple of the frame size,&lt;br /&gt;
        // then copy the remaining bytes to the start of the buffer.&lt;br /&gt;
        int remaining = numbytes - bytestowrite;&lt;br /&gt;
        if (remaining &amp;gt; 0)&lt;br /&gt;
          System.arraycopy(buffer, bytestowrite, buffer, 0, remaining);&lt;br /&gt;
        numbytes = remaining;&lt;br /&gt;
      }&lt;br /&gt;
      // Now block until all buffered sound finishes playing.&lt;br /&gt;
      line.drain();&lt;br /&gt;
    } finally { // Always relinquish the resources we use&lt;br /&gt;
      if (line != null)&lt;br /&gt;
        line.close();&lt;br /&gt;
      if (ain != null)&lt;br /&gt;
        ain.close();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  // A MIDI protocol constant that isn&amp;quot;t defined by javax.sound.midi&lt;br /&gt;
  public static final int END_OF_TRACK = 47;&lt;br /&gt;
  /* MIDI or RMF data from the specified URL and play it */&lt;br /&gt;
  public static void streamMidiSequence(URL url) throws IOException, InvalidMidiDataException,&lt;br /&gt;
      MidiUnavailableException {&lt;br /&gt;
    Sequencer sequencer = null; // Converts a Sequence to MIDI events&lt;br /&gt;
    Synthesizer synthesizer = null; // Plays notes in response to MIDI events&lt;br /&gt;
    try {&lt;br /&gt;
      // Create, open, and connect a Sequencer and Synthesizer&lt;br /&gt;
      // They are closed in the finally block at the end of this method.&lt;br /&gt;
      sequencer = MidiSystem.getSequencer();&lt;br /&gt;
      sequencer.open();&lt;br /&gt;
      synthesizer = MidiSystem.getSynthesizer();&lt;br /&gt;
      synthesizer.open();&lt;br /&gt;
      sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());&lt;br /&gt;
      // Specify the InputStream to stream the sequence from&lt;br /&gt;
      sequencer.setSequence(url.openStream());&lt;br /&gt;
      // This is an arbitrary object used with wait and notify to&lt;br /&gt;
      // prevent the method from returning before the music finishes&lt;br /&gt;
      final Object lock = new Object();&lt;br /&gt;
      // Register a listener to make the method exit when the stream is&lt;br /&gt;
      // done. See Object.wait() and Object.notify()&lt;br /&gt;
      sequencer.addMetaEventListener(new MetaEventListener() {&lt;br /&gt;
        public void meta(MetaMessage e) {&lt;br /&gt;
          if (e.getType() == END_OF_TRACK) {&lt;br /&gt;
            synchronized (lock) {&lt;br /&gt;
              lock.notify();&lt;br /&gt;
            }&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
      // Start playing the music&lt;br /&gt;
      sequencer.start();&lt;br /&gt;
      // Now block until the listener above notifies us that we&amp;quot;re done.&lt;br /&gt;
      synchronized (lock) {&lt;br /&gt;
        while (sequencer.isRunning()) {&lt;br /&gt;
          try {&lt;br /&gt;
            lock.wait();&lt;br /&gt;
          } catch (InterruptedException e) {&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    } finally {&lt;br /&gt;
      // Always relinquish the sequencer, so others can use it.&lt;br /&gt;
      if (sequencer != null)&lt;br /&gt;
        sequencer.close();&lt;br /&gt;
      if (synthesizer != null)&lt;br /&gt;
        synthesizer.close();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- end source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Program the MIDI percussion channel with a Swing window ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- start source code --&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
    &amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2004 David Flanagan.  All rights reserved.&lt;br /&gt;
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.&lt;br /&gt;
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.&lt;br /&gt;
 * You may study, use, and modify it for any non-commercial purpose,&lt;br /&gt;
 * including teaching and use in open-source projects.&lt;br /&gt;
 * You may distribute it non-commercially as long as you retain this notice.&lt;br /&gt;
 * For a commercial use license, or to purchase the book, &lt;br /&gt;
 * please visit http://www.davidflanagan.ru/javaexamples3.&lt;br /&gt;
 */&lt;br /&gt;
import java.awt.event.KeyAdapter;&lt;br /&gt;
import java.awt.event.KeyEvent;&lt;br /&gt;
import java.awt.event.MouseEvent;&lt;br /&gt;
import java.awt.event.MouseMotionAdapter;&lt;br /&gt;
import javax.sound.midi.MidiChannel;&lt;br /&gt;
import javax.sound.midi.MidiSystem;&lt;br /&gt;
import javax.sound.midi.MidiUnavailableException;&lt;br /&gt;
import javax.sound.midi.Synthesizer;&lt;br /&gt;
import javax.swing.JFrame;&lt;br /&gt;
/**&lt;br /&gt;
 * This program the MIDI percussion channel with a Swing window. It monitors&lt;br /&gt;
 * keystrokes and mouse motion in the window and uses them to create music.&lt;br /&gt;
 * Keycodes between 35 and 81, inclusive, generate different percussive sounds.&lt;br /&gt;
 * See the VK_ constants in java.awt.event.KeyEvent, or just experiment. Mouse&lt;br /&gt;
 * position controls volume: move the mouse to the right of the window to&lt;br /&gt;
 * increase the volume.&lt;br /&gt;
 */&lt;br /&gt;
public class Drums extends JFrame {&lt;br /&gt;
  MidiChannel channel; // The channel we play on: 10 is for percussion&lt;br /&gt;
  int velocity = 64; // Default volume is 50%&lt;br /&gt;
  public static void main(String[] args) throws MidiUnavailableException {&lt;br /&gt;
    // We don&amp;quot;t need a Sequencer in this example, since we send MIDI&lt;br /&gt;
    // events directly to the Synthesizer instead.&lt;br /&gt;
    Synthesizer synthesizer = MidiSystem.getSynthesizer();&lt;br /&gt;
    synthesizer.open();&lt;br /&gt;
    JFrame frame = new Drums(synthesizer);&lt;br /&gt;
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&lt;br /&gt;
    frame.setSize(50, 128); // We use window width as volume control&lt;br /&gt;
    frame.setVisible(true);&lt;br /&gt;
  }&lt;br /&gt;
  public Drums(Synthesizer synth) {&lt;br /&gt;
    super(&amp;quot;Drums&amp;quot;);&lt;br /&gt;
    // Channel 10 is the GeneralMidi percussion channel. In Java code, we&lt;br /&gt;
    // number channels from 0 and use channel 9 instead.&lt;br /&gt;
    channel = synth.getChannels()[9];&lt;br /&gt;
    addKeyListener(new KeyAdapter() {&lt;br /&gt;
      public void keyPressed(KeyEvent e) {&lt;br /&gt;
        int key = e.getKeyCode();&lt;br /&gt;
        if (key &amp;gt;= 35 &amp;amp;&amp;amp; key &amp;lt;= 81) {&lt;br /&gt;
          channel.noteOn(key, velocity);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      public void keyReleased(KeyEvent e) {&lt;br /&gt;
        int key = e.getKeyCode();&lt;br /&gt;
        if (key &amp;gt;= 35 &amp;amp;&amp;amp; key &amp;lt;= 81)&lt;br /&gt;
          channel.noteOff(key);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    addMouseMotionListener(new MouseMotionAdapter() {&lt;br /&gt;
      public void mouseMoved(MouseEvent e) {&lt;br /&gt;
        velocity = e.getX();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &amp;lt;/source&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
   &lt;br /&gt;
  &amp;lt;!-- end source code --&amp;gt;&lt;/div&gt;</summary>
			</entry>

	</feed>