JavaSound MIDI Playback

The playback of MIDi files has been possible by saving the file and using any MIDI player, or byusing the QuickTime player. Version 1.3 of Java comes with the JavaSound libraies that inlcude MIDI playback. jMusic can nowplayback directly using these libraries thanks to Mark Elston's MidiSynth class.

This tutorial shows how simply you can access this playback option by using the Play.midi() method in the jm.util package.

Click here to view source.

Lets have a closer look.

import jm.JMC;
import jm.util.*;
import jm.music.data.*;
import jm.music.tools.Mod;
import jm.midi.MidiSynth;
 
public final class MidiSynthTest implements JMC{

/**
* Main method where all good Java programs start
*/
public static void main(String[] args){
Score s = new Score();
s.setTempo(130.0);
for(int i=0; i<3;i++) {
Part p = new Part("part",i*5,i);
p.setTempo(120.0 + (double)i * 0.5);
for(int j=0; j<1;j++) {
Phrase phrase = new Phrase();
phrase = makePhrase(0.0, 50);
p.addPhrase(phrase);
}
s.addPart(p);
}
Play.midi(s);
}
Above is the whole file, apart from the composition method (shown below). Starting from thebottom the Play.midi(s); line does all the work of interest to this tutorial. It plays the score "s" via the JavaSound GeneralMIDI sound set - as simple as that.

The rest of the code is dedicated to building a score of 3 parts each with one phrase.

private static Phrase makePhrase(double startTime, int length) {
Phrase phr = new Phrase(startTime);
int pitch = (int)(Math.random()*60+30);
for(int i=0; i < length; i++) {
pitch += (int)(Math.random()*10-5);
Note n = new Note(pitch, CROTCHET,
(int)(Math.random()*70 + 30));
phr.addNote(n);
}
return phr;
}
}
The score to be played is made up of phrases created by the method above.

Update
In jMusic version 1.6.4 an extended method signature for Play.midi() was introduced that overcame a bug where repeated callings of Play.midi(score) would eventually cease playing.

Play.midi(Score, boolean, boolean, int);

Where the Score is a jMusic score, the 2nd argument may close the synthesizer when playback is done (or not), the 3rd argument initiates a wait thread to hold open the program for the length of playback (or not), the fourth argument is the number of synthesizer allocated (this allows overlapping Play calls).
Below is a code example that uses this method signature. A button, when pushed, plays a generated sequence again and again.

import jm.JMC;
import jm.music.data.*;
import jm.util.Play;
import javax.swing.*;
import java.awt.event.*;

class PlaybackTest implements ActionListener, JMC {
    private Score score;
    private int cnt = 1;
   
    public static void main(String[] args) {
        new PlaybackTest();
    }

    public PlaybackTest() {
        JFrame frame = new JFrame();
        JButton button = new JButton("Play");
        button.addActionListener(this);
        frame.add(button);
        frame.pack();
        frame.setVisible(true);
    }
   
    public void playScore() {
        updatePhrase();
        System.out.println("Playing times: " + cnt++);
        // Play.midi() arguments -
         /* @param score The score to be played.
         * @param exit Close playback when done? true or false.
        * @param wait Hold program open for the duration of playback? True or false
        * @param synths The number of the MidiSynths to use - default is 1. */
        // use the third argument as true only if you don't have a GUI to keep the program open during playback.
        // can use 2 as 4th argument to prevent release tails of phrase ends being cut off
        // but this may mean more initalising which distors the timing of the first few notes.
        Play.midi(score, false, false, 2);
   }   
   
    private void updatePhrase() {
        Phrase phr = new Phrase();
        phr.addNote(new Note((int)(Math.random() * 20) + 60, 0.25));
        phr.addNote(new Note((int)(Math.random() * 20) + 60, 0.25));
        phr.addNote(new Note((int)(Math.random() * 20) + 60, 0.5));
        score = new Score(new Part(phr));
    }
   
    public void actionPerformed(ActionEvent e) {
        playScore();
    }
}



jMusic Tutorial Index