Problem Playing WAV files in J2SE 1.5

Dear All,

I’ve included a test program at the end, with a bug which seems
to have appeared in J2SE 1.5 (beta 2).

When I call the program with an ordinary WAV file, most of
the time nothing is played, although the program does wait
for the duration of the audio before exiting.

Compile the program:

javac PlayClip.java

Run:

java PlayClip dog.wav

Any WAV file will do.

  • Andrew

` // PlayClip.java

import java.io.;
import javax.sound.sampled.
;

public class PlayClip implements LineListener
{
private Clip clip = null;

public PlayClip(String fnm)
{
loadClip(fnm);

if (clip != null) {
  System.out.println("Playing...");
  clip.start();   // start playing
}

// wait for the sound to finish playing; guess at 10 mins!
System.out.println("Waiting");
try {
  Thread.sleep(600000);   // 10 mins in ms
}
catch(InterruptedException e)
{ System.out.println("Sleep Interrupted"); }

} // end of PlayClip()

private void loadClip(String fnm)
{
try {
// link an audio stream to the sound clip’s file
AudioInputStream stream = AudioSystem.getAudioInputStream(
getClass().getResource(fnm) );

  AudioFormat format = stream.getFormat();
  DataLine.Info info = new DataLine.Info(Clip.class, format);

  // make sure sound system supports data line
  if (!AudioSystem.isLineSupported(info)) {
    System.out.println("Unsupported Clip File: " + fnm);
    System.exit(0);
  }

  // get clip line resource
  clip = (Clip) AudioSystem.getLine(info);

  // listen to clip for events
  clip.addLineListener(this);

  clip.open(stream);    // open the sound file as a clip
  stream.close(); // we're done with the input stream
} // end of try block

catch (Exception e) {
  System.out.println(e);
  System.exit(0);
}

} // end of loadClip()

public void update(LineEvent lineEvent)
// called when the clip’s line detects open, close, start, stop events
{
// has the clip has reached its end?
if (lineEvent.getType() == LineEvent.Type.STOP) {
System.out.println(“Exiting…”);
clip.stop();
System.exit(0);
}
} // end of update()

// --------------------------------------------------

public static void main(String[] args)
{
if (args.length != 1) {
System.out.println("Usage: java PlayClip ");
System.exit(0);
}
new PlayClip(args[0]);
} // end of main()

} // end of PlayClip.java

`

I’m replying to myself.

The problem is to do with the duration of the sound.

If the WAV file is less than a second long then no
sound is played.

My hacky solution is to obtain the duration of the
sound with:
double duration = clip.getMicrosecondLength()/1000000.0;

Then calculate a count which is used to loop the
sound so it plays for a total of 1 second or more.

  loopCount = (int) (1.0 / duration);


  // clip.start();   // start playing
  clip.loop(loopCount);

This is clearly not so great if the sound is meant to
be brief.

  • Andrew

With Applet’s sound stuff you have a delay each time a sound is played for the first time (they get moved into ram then).

With the sampled package it’s a bit different - Clips are played instantly (because they are already in ram). However, the very first time you try to play a sound a mixer object (the default mixer) is created. Therefore you end up with a small delay, which was in your case big enough for not playing the sound at all.

You can test that easily. Play the sample wait a second, play it again, wait 2 seconds and exit… or make a little test application, which plays the sound if you click a button. You’ll see that there won’t be a delay the second time.

For games it doesn’t really matter. You play lot’s of sounds and most people don’t even notice that the first sound effect was somewhat off.

However, if you really want to fix that… creating a mixer object by yourself should do the trick.

When I load sounds for my game, I’ll create a Clip of the sound as I load it, and call what I need to get the Mixer created, and then just toss it away. Getting the mixer made seems to me to be part of the loading process, so I think that’s a good time to do it.

As I understand it, the clip.open(stream); line will
gather the necessary resources, including a reference
to the default mixer.

If I add a sleep period after that call, the problem
is still present. A call to isOpen() says that the clip
is open.

This problem doesn’t occur when I run the program
from my first posting in J2SE 1.4.2.

  • Andrew

hmm I’d guess that it’s still open because you haven’t played the Clip yet. For mine I just .flush() and .close() it after that first load. I think the only way it’ll do that on its own is if you call .start() to let it run through and thus avoid the permanent open-ness… but you don’t want it to play when you’re loading it because you just want to make the mixer so it won’t sound silly :slight_smile:

Sun has just added this bug to their database, as
Bug Id: 5085008

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5085008

(It may take a day or so to appear in their external
database.)

  • Andrew