Bookmark and Share

Sound and Image Loading

One of the advantages of using Java applets on a web page is the ability to add dynamic sound and images. This article describes the basics of loading audio clips and images from the server so they can be used within an applet.

Audio Clips

Audio clips are relatively easy to use in an applet. You create an AudioClip object using the applet getAudioClip() method, giving it the URL of the sound file located on the server. The clip can then be played using that object's play() or loop() methods. The sound can be shut off with a call to stop().

  try {
    AudioClip myClip = getAudioClip(new URL(getCodeBase(), "clip.au"));
  }
  catch (Exception e) {}

  myClip.play();

The problem is that the sound file is not actually retrieved from the server until the clip is played for the first time, using either play() or loop(). The file download may take some time and the applet will freeze until it is complete or fails.

This becomes especially noticeable with large sound files or when several sound clips are used. If the sounds are meant to be played in response to user actions or under certain conditions (like in games), the applet will freeze at those moments, possibly for quite a while. And the user can do nothing with the applet during this time.

You could load, play and immediately stop each clip at the beginning of the applet to force the files to download during initialization:

  try {
    AudioClip clip1 = getAudioClip(new URL(getCodeBase(), "clip1.au"));
    AudioClip clip2 = getAudioClip(new URL(getCodeBase(), "clip2.au"));
    AudioClip clip3 = getAudioClip(new URL(getCodeBase(), "clip3.au"));
    // ...    
  }
  catch (Exception e) {}

  clip1.play(); clip1.stop();
  clip2.play(); clip2.stop();
  clip3.play(); clip3.stop();
  // ...

but the applet will still freeze, preventing any user interaction and possibly frustrating the user.

See the example image loading applet in action in the demo or view the source code.

Using Threads

As with the animation example, multi threading can be used to correct the problem. The aforementioned technique of calling AudioClip.play(); AudioClip.stop(); to force the downloading of the sound file is used but done in a separate thread.

This allows the main applet thread (and any other threads you initiate) to run concurrently with the sound loading thread. The download will still take some time but the applet can at least perform other tasks while this takes place.

The basics of creating and controlling threads can be found in the discussion on animation. The only new concept is determining when the download of a sound file has completed. This can be done by checking the value of the AudioClip object.

  if (myClip != null)
    myClip.play();

If the value of the AudiClip object is null, the sound file has either not finished downloading or an error has occurred (such as the file not being found at the given URL) and the clip cannot be played. Otherwise it can be played without fear of stopping the applet.

The Sound Loading Example

The example applet downloads three different sound files using a separate thread as described. A button is displayed for each, pressing them will play the individual clip.

The buttons are initially disabled. When the corresponding sound clip, loading in a separate thread, finishes downloading, the button is enabled. Below is a sample of the code run in this tread.

    // Initialize the sound clips.

    try {
      clip1 = getAudioClip(new URL(getCodeBase(), "test1.au"));
      ...
    }
    catch (Exception e) {}

    // Load each sound clip and activate its corresponding button when
    // ready.

    clip1.play(); clip1.stop(); button1.setEnabled(true); repaint();
    soundsLoadThread.yield();

    ...

The calls to repaint() and yield() allow the button display to be updated after each file download.

Images

Image files can also be downloaded for use within an applet. Similar to audio files, an image is obtained by creating an Image object using getImage() with the URL of the image file. As with audio files, this method returns immediately, without downloading the file.

Normally, the download won't start until you first attempt to render the image on the applet display using one of the Graphics image drawing methods. This download is done asynchronously, so there's no need to create a separate thread.

However, the drawing methods will only display as much of the image as is currently available when the command is called, meaning that none or only part of the image may appear on the screen.

Because of this, it's often desirable to force image downloads to start and and wait for them to finish before attempting to render them on the display. A couple of methods, along with the ImageObserver interface, make this possible.