A Swing component that can load and play a sound clip, displaying progress and controls : MIDI « Development Class « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Class
8. Collections Data Structure
9. Data Type
10. Database SQL JDBC
11. Design Pattern
12. Development Class
13. EJB3
14. Email
15. Event
16. File Input Output
17. Game
18. Generics
19. GWT
20. Hibernate
21. I18N
22. J2EE
23. J2ME
24. JDK 6
25. JNDI LDAP
26. JPA
27. JSP
28. JSTL
29. Language Basics
30. Network Protocol
31. PDF RTF
32. Reflection
33. Regular Expressions
34. Scripting
35. Security
36. Servlets
37. Spring
38. Swing Components
39. Swing JFC
40. SWT JFace Eclipse
41. Threads
42. Tiny Application
43. Velocity
44. Web Services SOA
45. XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java » Development Class » MIDIScreenshots 
A Swing component that can load and play a sound clip, displaying progress and controls


/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Track;
import javax.sound.midi.Transmitter;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * This class is a Swing component that can load and play a sound clip,
 * displaying progress and controls. The main() method is a test program. This
 * component can play sampled audio or MIDI files, but handles them differently.
 * For sampled audio, time is reported in microseconds, tracked in milliseconds
 * and displayed in seconds and tenths of seconds. For midi files time is
 * reported, tracked, and displayed in MIDI "ticks". This program does no
 * transcoding, so it can only play sound files that use the PCM encoding.
 */
public class SoundPlayer extends JComponent {
  boolean midi; // Are we playing a midi file or a sampled one?

  Sequence sequence; // The contents of a MIDI file

  Sequencer sequencer; // We play MIDI Sequences with a Sequencer

  Clip clip; // Contents of a sampled audio file

  boolean playing = false// whether the sound is current playing

  // Length and position of the sound are measured in milliseconds for
  // sampled sounds and MIDI "ticks" for MIDI sounds
  int audioLength; // Length of the sound.

  int audioPosition = 0// Current position within the sound

  // The following fields are for the GUI
  JButton play; // The Play/Stop button

  JSlider progress; // Shows and sets current position in sound

  JLabel time; // Displays audioPosition as a number

  Timer timer; // Updates slider every 100 milliseconds

  // The main method just creates an SoundPlayer in a Frame and displays it
  public static void main(String[] argsthrows IOException, UnsupportedAudioFileException,
      LineUnavailableException, MidiUnavailableException, InvalidMidiDataException {
    SoundPlayer player;

    File file = new File(args[0])// This is the file we'll be playing
    // Determine whether it is midi or sampled audio
    boolean ismidi;
    try {
      // We discard the return value of this method; we just need to know
      // whether it returns successfully or throws an exception
      MidiSystem.getMidiFileFormat(file);
      ismidi = true;
    catch (InvalidMidiDataException e) {
      ismidi = false;
    }

    // Create a SoundPlayer object to play the sound.
    player = new SoundPlayer(file, ismidi);

    // Put it in a window and play it
    JFrame f = new JFrame("SoundPlayer");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(player, "Center");
    f.pack();
    f.setVisible(true);
  }

  // Create an SoundPlayer component for the specified file.
  public SoundPlayer(File f, boolean isMidithrows IOException, UnsupportedAudioFileException,
      LineUnavailableException, MidiUnavailableException, InvalidMidiDataException {
    if (isMidi) { // The file is a MIDI file
      midi = true;
      // First, get a Sequencer to play sequences of MIDI events
      // That is, to send events to a Synthesizer at the right time.
      sequencer = MidiSystem.getSequencer()// Used to play sequences
      sequencer.open()// Turn it on.

      // Get a Synthesizer for the Sequencer to send notes to
      Synthesizer synth = MidiSystem.getSynthesizer();
      synth.open()// acquire whatever resources it needs

      // The Sequencer obtained above may be connected to a Synthesizer
      // by default, or it may not. Therefore, we explicitly connect it.
      Transmitter transmitter = sequencer.getTransmitter();
      Receiver receiver = synth.getReceiver();
      transmitter.setReceiver(receiver);

      // Read the sequence from the file and tell the sequencer about it
      sequence = MidiSystem.getSequence(f);
      sequencer.setSequence(sequence);
      audioLength = (intsequence.getTickLength()// Get sequence length
    else // The file is sampled audio
      midi = false;
      // Getting a Clip object for a file of sampled audio data is kind
      // of cumbersome. The following lines do what we need.
      AudioInputStream ain = AudioSystem.getAudioInputStream(f);
      try {
        DataLine.Info info = new DataLine.Info(Clip.class, ain.getFormat());
        clip = (ClipAudioSystem.getLine(info);
        clip.open(ain);
      finally // We're done with the input stream.
        ain.close();
      }
      // Get the clip length in microseconds and convert to milliseconds
      audioLength = (int) (clip.getMicrosecondLength() 1000);
    }

    // Now create the basic GUI
    play = new JButton("Play")// Play/stop button
    progress = new JSlider(0, audioLength, 0)// Shows position in sound
    time = new JLabel("0")// Shows position as a #

    // When clicked, start or stop playing the sound
    play.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (playing)
          stop();
        else
          play();
      }
    });

    // Whenever the slider value changes, first update the time label.
    // Next, if we're not already at the new position, skip to it.
    progress.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        int value = progress.getValue();
        // Update the time label
        if (midi)
          time.setText(value + "");
        else
          time.setText(value / 1000 "." (value % 1000100);
        // If we're not already there, skip there.
        if (value != audioPosition)
          skip(value);
      }
    });

    // This timer calls the tick() method 10 times a second to keep
    // our slider in sync with the music.
    timer = new javax.swing.Timer(100new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        tick();
      }
    });

    // put those controls in a row
    Box row = Box.createHorizontalBox();
    row.add(play);
    row.add(progress);
    row.add(time);

    // And add them to this component.
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    this.add(row);

    // Now add additional controls based on the type of the sound
    if (midi)
      addMidiControls();
    else
      addSampledControls();
  }

  /** Start playing the sound at the current position */
  public void play() {
    if (midi)
      sequencer.start();
    else
      clip.start();
    timer.start();
    play.setText("Stop");
    playing = true;
  }

  /** Stop playing the sound, but retain the current position */
  public void stop() {
    timer.stop();
    if (midi)
      sequencer.stop();
    else
      clip.stop();
    play.setText("Play");
    playing = false;
  }

  /** Stop playing the sound and reset the position to 0 */
  public void reset() {
    stop();
    if (midi)
      sequencer.setTickPosition(0);
    else
      clip.setMicrosecondPosition(0);
    audioPosition = 0;
    progress.setValue(0);
  }

  /** Skip to the specified position */
  public void skip(int position) { // Called when user drags the slider
    if (position < || position > audioLength)
      return;
    audioPosition = position;
    if (midi)
      sequencer.setTickPosition(position);
    else
      clip.setMicrosecondPosition(position * 1000);
    progress.setValue(position)// in case skip() is called from outside
  }

  /** Return the length of the sound in ms or ticks */
  public int getLength() {
    return audioLength;
  }

  // An internal method that updates the progress bar.
  // The Timer object calls it 10 times a second.
  // If the sound has finished, it resets to the beginning
  void tick() {
    if (midi && sequencer.isRunning()) {
      audioPosition = (intsequencer.getTickPosition();
      progress.setValue(audioPosition);
    else if (!midi && clip.isActive()) {
      audioPosition = (int) (clip.getMicrosecondPosition() 1000);
      progress.setValue(audioPosition);
    else
      reset();
  }

  // For sampled sounds, add sliders to control volume and balance
  void addSampledControls() {
    try {
      FloatControl gainControl = (FloatControlclip.getControl(FloatControl.Type.MASTER_GAIN);
      if (gainControl != null)
        this.add(createSlider(gainControl));
    catch (IllegalArgumentException e) {
      // If MASTER_GAIN volume control is unsupported, just skip it
    }

    try {
      // FloatControl.Type.BALANCE is probably the correct control to
      // use here, but it doesn't work for me, so I use PAN instead.
      FloatControl panControl = (FloatControlclip.getControl(FloatControl.Type.PAN);
      if (panControl != null)
        this.add(createSlider(panControl));
    catch (IllegalArgumentException e) {
    }
  }

  // Return a JSlider component to manipulate the supplied FloatControl
  // for sampled audio.
  JSlider createSlider(final FloatControl c) {
    if (c == null)
      return null;
    final JSlider s = new JSlider(01000);
    final float min = c.getMinimum();
    final float max = c.getMaximum();
    final float width = max - min;
    float fval = c.getValue();
    s.setValue((int) ((fval - min/ width * 1000));

    java.util.Hashtable labels = new java.util.Hashtable(3);
    labels.put(new Integer(0)new JLabel(c.getMinLabel()));
    labels.put(new Integer(500)new JLabel(c.getMidLabel()));
    labels.put(new Integer(1000)new JLabel(c.getMaxLabel()));
    s.setLabelTable(labels);
    s.setPaintLabels(true);

    s.setBorder(new TitledBorder(c.getType().toString() " " + c.getUnits()));

    s.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        int i = s.getValue();
        float f = min + (i * width / 1000.0f);
        c.setValue(f);
      }
    });
    return s;
  }

  // For Midi files, create a JSlider to control the tempo,
  // and create JCheckBoxes to mute or solo each MIDI track.
  void addMidiControls() {
    // Add a slider to control the tempo
    final JSlider tempo = new JSlider(50200);
    tempo.setValue((int) (sequencer.getTempoFactor() 100));
    tempo.setBorder(new TitledBorder("Tempo Adjustment (%)"));
    java.util.Hashtable labels = new java.util.Hashtable();
    labels.put(new Integer(50)new JLabel("50%"));
    labels.put(new Integer(100)new JLabel("100%"));
    labels.put(new Integer(200)new JLabel("200%"));
    tempo.setLabelTable(labels);
    tempo.setPaintLabels(true);
    // The event listener actually changes the tmpo
    tempo.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sequencer.setTempoFactor(tempo.getValue() 100.0f);
      }
    });

    this.add(tempo);

    // Create rows of solo and checkboxes for each track
    Track[] tracks = sequence.getTracks();
    for (int i = 0; i < tracks.length; i++) {
      final int tracknum = i;
      // Two checkboxes per track
      final JCheckBox solo = new JCheckBox("solo");
      final JCheckBox mute = new JCheckBox("mute");
      // The listeners solo or mute the track
      solo.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          sequencer.setTrackSolo(tracknum, solo.isSelected());
        }
      });
      mute.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          sequencer.setTrackMute(tracknum, mute.isSelected());
        }
      });

      // Build up a row
      Box box = Box.createHorizontalBox();
      box.add(new JLabel("Track " + tracknum));
      box.add(Box.createHorizontalStrut(10));
      box.add(solo);
      box.add(Box.createHorizontalStrut(10));
      box.add(mute);
      box.add(Box.createHorizontalGlue());
      // And add it to this component
      this.add(box);
    }
  }
}

 
Related examples in the same category
1. Play Piano
2. Plays sounds streaming from a URL
3. Program the MIDI percussion channel with a Swing window
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.