The Midi Sequences Loader


Storing Clip Information

A ClipInfo object is responsible for loading a clip and plays, pauses, resumes, stops, and loops that clip when requested by ClipsLoader. Additionally, an object implementing the SoundsWatcher interface (a watcher) can be notified when the clip loops or stops.

Much of the manipulation carried out by ClipInfo, such as clip loading, is almost identical to that found in PlayClip.java in Chapter 7. Perhaps the largest difference is that PlayClip exits when it encounters a problem, and ClipInfo prints an error message and soldiers on.

loadClip( ) is similar to PlayClip's loadClip( ), so certain parts have been commented away in the code below to simplify matters:

     // global     private Clip clip = null;     private void loadClip(String fnm)     {       try {         // 1. access the audio file as a stream         AudioInputStream stream = AudioSystem.getAudioInputStream(                             getClass( ).getResource(fnm) );         // 2. Get the audio format for the data in the stream         AudioFormat format = stream.getFormat( );         // convert ULAW/ALAW formats to PCM format...         // several lines, which update stream and format         // 3. Gather information for line creation         DataLine.Info info = new DataLine.Info(Clip.class, format);         // make sure the sound system supports the data line         if (!AudioSystem.isLineSupported(info)) {           System.out.println("Unsupported Clip File: " + fnm);           return;         }         // 4. create an empty clip using the line information         clip = (Clip) AudioSystem.getLine(info);         // 5. Start monitoring the clip's line events         clip.addLineListener(this);         // 6. Open the audio stream as a clip; now it's ready to play         clip.open(stream);         stream.close( ); // I'm done with the input stream              checkDuration( );       } // end of try block       // several catch blocks go here ...     } // end of loadClip( )

checkDuration( ) checks the length of this clip and issues a warning if it's one second or less. This warning is due to the WAV file bug in Java Sound in J2SE 5.0, first mentioned in Chapter 7 when I coded PlayClip.java.

If a clip is too short, it'll fail to play and often affects the playing of other clips in LoadersTests, even those longer than one second.


play( ) starts the loop playing:

     public void play(boolean toLoop)     { if (clip != null) {         isLooping = toLoop;    // store playing mode         clip.start( ); // start playing from where stopped       }     }

The Clip class has a loop( ) method, which is not used by my play( ) method when toLoop is true. Instead, the looping mode is stored in the isLooping global and is utilized later in update( ). This allows the loader to execute a callback method in a watcher at the end of each iteration.

Clip's start( ) method is asynchronous, so the play( ) method will not suspend. This makes it possible for a user to start multiple clips playing at the same time.

If play( ) is called again for a playing clip, start( ) will have no effect.


Stopping Clips

The stop( ) method stops the clip and resets it to the beginning, ready for future playing:

     public void stop( )     { if (clip != null) {         isLooping = false;         clip.stop( );         clip.setFramePosition(0);       }     }

Clip.setFramePosition( ) can set the playing position anywhere inside the clip.

Pausing and Resuming Clips

The pause( ) and resume( ) methods are similar to stop( ) and play( ):

     public void pause( )     // stop the clip at its current playing position     { if (clip != null)         clip.stop( );     }     public void resume( )     { if (clip != null)         clip.start( );     }

The big difference between pause( ) and stop( ) is that pause( ) doesn't reset the clip's playing position. Consequently, resume( ) will start playing the clip from the point where the sound was suspended.

Handing Line Events

ClipInfo implements the LineListener interface, so it is notified when the clip generates line events. Audio lines, such as clips, fire events when they're opened, started, stopped, or closed. update( ) only deals with STOP line events:

     public void update(LineEvent lineEvent)     {       // when clip is stopped / reaches its end       if (lineEvent.getType( ) == LineEvent.Type.STOP) {         clip.stop( );         clip.setFramePosition(0);         if (!isLooping) {  // it isn't looping           if (watcher != null)             watcher.atSequenceEnd(name, SoundsWatcher.STOPPED);         }         else {      // else play it again           clip.start( );           if (watcher != null)             watcher.atSequenceEnd(name, SoundsWatcher.REPLAYED);         }       }     }

A STOP event is triggered in two different situations: when the clip reaches its end and when the clip is stopped with Clip.stop( ).

When the clip reaches its end, it may have been set to loop. This isn't implemented by using Clip's loop( ) method but by examining the value of the global isLooping Boolean. If isLooping is false, then the watcher (if one exists) is told the clip has stopped. If isLooping is TRue then the clip will start again, and the watcher is told that the clip is playing again. This explicit restarting of a looping clip, instead of calling loop( ), allows me to insert additional processing (e.g., watcher notification) between the clip's finishing and restarting.



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net