I'm trying to assemble a graphical representation of a MIDI sequence, and I'd like a vertical line to move across the panel horizontally as the sequence plays, reflecting the actual position in the sequence. I know that I should use something like getTickPosition()
to provide the location of the vertical line.
But how do I fire off these events so that the vertical line knows to redraw itself? Do I create a special listener that the ticks somehow trigger?
Establish a Swing Timer
to check and update the tick position every NN milliseconds.
So, there's not any kind of built-in timer in the MidiSystem?
Sure there is. But the point is that all GUI updates should happen on the EDT. By invoking them from a Swing Timer
, they are. Also, the MIDI timer is for the use of MIDI API/System, let it do what it does undisturbed, and report back the relevant information when checked from the Swing Timer
.
Also, given the nature of the UI component, look to a JProgressBar
as seen in the upper right of this GUI.
I adapted the source seen on the Java Sound WIKI into an SSCCE of this approach.
import javax.sound.midi.*;
import javax.swing.*;
import java.awt.event.*;
import java.net.URL;
class PlayMidi {
public static void main(String[] args) throws Exception {
URL url = new URL("http://pscode.org/media/EverLove.mid");
Sequence sequence = MidiSystem.getSequence(url);
final Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.setSequence(sequence);
Runnable r = new Runnable() {
public void run() {
final JProgressBar progress = new JProgressBar(0,(int)sequencer.getMicrosecondLength());
ActionListener updateListener = new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
progress.setValue((int)sequencer.getMicrosecondPosition());
}
};
Timer timer = new Timer(40,updateListener);
sequencer.start();
timer.start();
JOptionPane.showMessageDialog(null, progress);
sequencer.close();
timer.stop();
}
};
SwingUtilities.invokeLater(r);
}
}