Sunday, November 25, 2007

How to play music (mp3, ogg, wav) in Java

The simplest way to play music in our java application is by using Java Sound and a few extension libraries.

In this example we shall use “Tritonus”, a free Java Sound implementation which is capable to work well with Windows, Linux or Mac, and MP3SPI, which is an mp3 plug-in for JavaSound (you can play Ogg Vorbis by using VorbisSPI).we are going to use BasicPlayer, which provides a high level API, to simplify the use of the Java Sound API.
My advice: Download jlGui and use the jars you will find inside the lib directory.

In this example we are going to create two classes, Player and Test. Player will control BasicPlayer and Test will order things to Player. For this example we shall not have concurrency or errors like those to look after.

In Player class, we should have a variable of BasicPlayer type that we shall in the builder to work with the API, just like this:
private BasicPlayer basicPlayer;
public Reproductor() {
basicPlayer = new BasicPlayer();
}
And we have to implement the methods "Play", "Stop", "Pause" y "Resume". All of them will have the same structure:

 public void play() {
try {
basicPlayer.play();
} catch (BasicPlayerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
We should also have an open method to load files into BasicPlayer:

 public void loadFile(String ruta) throws BasicPlayerException {
basicPlayer.open(new File(ruta));
}
The test class only has to create an instance of Player and invoke the methods we want, nothing more.
Wait a moment... what happens if we want to know the state of the playing, for example, the seconds played? We must implement BasicPlayerListener. I will implement the interface in Player class, so:
public class Player implements BasicPlayerListener {
Now, we have to implement the unimplemented methods but, first, I will subscribe the Player class to our BasicPlayer instance. Remember, for this example we supposed we only shall have an unique instance of BasicPlayer (yes, Player could be Singleton) but it is possible to have many of them.

 public Player() {
basicPlayer = new BasicPlayer();
// I will subscribe Player to this BasicPlayer to get their events.
basicPlayer.addBasicPlayerListener(this);
}
One of the methods we have to implement, is “opened”. This method is called every time we load a file into BasicPlayer. We shall use it to get the size of the file in bytes. Why? Because we shall get the progress of the play as bytes played.

public void opened(Object arg0, Map arg1) {
if (arg1.containsKey("audio.length.bytes")) {
bytesLength = Double.parseDouble(arg1.get("audio.length.bytes")
.toString());
}
}
Another method we need to touch is “progress”, which is called by BasicPlayer many times per second during the playing. We shall use it to get the progress of the play. This can be helpful if we want to build a swing application and we want to use a jSlider to seek trough the file.

public void progress(int bytesread, long microseconds, byte[] pcmdata,  Map properties) {
float progressUpdate = (float) (bytesread * 1.0f / bytesLength * 1.0f);
int progressNow = (int) (bytesLength * progressUpdate);
// Uncomment next line to see the progress
// System.out.println(" -> " + progressNow);
}
If you wanted to use a jSlider, its max valule would be bytesLenth and its current value would be progressNow ;)
Like I said in my first post, my english is very bad. If you find any mistake (I know, you will find hundreds of them) please, leave a message and I will try to fix it. The same if you have any doubt about this topic.