This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


How It's Done

minddone@microsoft.com        Download the code (10KB)

Michael Hyman

The Hills are Alive...

I
recently got back from the Internet World trade show in New York. Like all trade shows, it has progressed from a small show focused on technology to one mostly filled with hype. I stopped by an HTML authoring tool demo and asked whether the tool created HTML. "That's a technical question," responded the booth staffer. "Let me take your name down and someone can get back to you." I must say I miss the days when you could speak with someone remotely connected to the technology. Despite my disappointment, I was inspired to create a Web site that emulated all of the glitz and glory of the trade show. Naturally, that meant adding sound to otherwise quiet pages.

Nonstop Rock
      With Microsoft® Internet Explorer 3.0 and later, you can add background sounds to a page. The sound starts as soon as the page loads; you can have it either play once or loop indefinitely. Adding sound to a page provides background ambience. You can play MIDI files or WAV files (MIDI files are small) with the sound quality depending on the type of sound card that you have. With cheap cards, MIDI files sound like a toy organ; with better cards, the sound is very close to CD quality. WAV files are actual samples of sounds, and thus consume much more bandwidth than MIDI files. But WAV files are the only way to get recorded sounds, such as voices or special effects, to play back on a page.
      You play sounds using the <BGSOUND> tag, as shown in the following page:


 <HTML>
 <BODY>
 	<BGSOUND SRC="snd1.mid">
 	Welcome to the page of sound.
 </BODY>
 </HTML>
This page plays a MIDI file once, as soon as the page is loaded. Using the LOOP parameter, you can make the sound play more often. For example, the following will play the MIDI track three times:

 <HTML>
 <BODY>
 <BGSOUND SRC="snd1.mid" LOOP=3>
 Welcome to the page of sound.
 </BODY>
 </HTML>
To make the track play the entire time that the page is visible, set LOOP to INFINITE. Of course, doing so can certainly cause anyone looking at your page to go nuts.

Music on Demand
      It's fun to play background music, but playing sounds in response to user actions is far more interesting. For example, you can play a sound when the user clicks on a link or mouses over an image hot spot. There are two basic ways to play music in response to events: you can use the <BGSOUND> tag or the ActiveMovie™ control.
      I'll begin with the <BGSOUND> tag, which is similar to using it for adding background music. I'll give the <BGSOUND> an ID, and leave the SRC blank. Then I'll set the SRC parameter through a script run in response to an event. For example, the following page will play a sound when you mouse over certain words on the page:


 <HTML>
 <HEAD>
 <BGSOUND id=snd1>
 </HEAD>
 <BODY>
 The page of <FONT COLOR=blue onmouseover="snd1.src='snd1.wav'">sound</FONT>
 will play <FONT COLOR=blue onmouseover="snd1.src='snd2.wav'">noises</FONT>
 for you.
 </BODY>
 </HTML>
In the browser, the words with sounds attached are highlighted in blue so that you can see them more easily. When you mouse over a word, such as "sound," the script sets the SRC for the <BGSOUND> tag. This causes the sound to play.
      You can also make several sounds play at once. For example, the following page will play a background MIDI track, and then mix in the WAV file when the user mouses over one of the blue-colored words:

 <HTML>
 <HEAD>
 <BGSOUND id=snd1>
 <BGSOUND SRC="snd1.mid">
 </HEAD>
 <BODY>
 The page of <FONT COLOR=blue
 onmouseover="snd1.src='snd1.wav'">sound</FONT> will play <FONT COLOR=blue
 onmouseover="snd1.src='snd2.wav'">noises</FONT> for you.
 </BODY>
 </HTML>
       If you want to make sure that a sound is available as soon as the user mouses over it, you can preload it into the cache. A simple way is to add a tag for the sound file and set its volume to a level that can't be heard, like -10000.

Active Sounds with ActiveMovie
      <BGSOUND> is simple, but it won't work for all your needs. There are three disadvantages to using <BGSOUND>. First, you have no way of knowing when a sound has downloaded. If you need to play a fairly large sound and you want to synchronize it with some other actions, such as moving elements across the page, you won't be able to guarantee that the sound will start when the element starts moving. Second, there can be a pause between loops. If you have a small sound that you loop frequently—say for a drum track—you might get an annoying hiccup between repetitions. Third, and perhaps most significantly, you can't stop the sound once you start it. This is particularly troublesome when you are playing a looping sound. Although you can change the SRC to "", it will stop when it feels like stopping, not when you tell it to. One way to work around this is to cut the volume as soon as you want the sound to stop. It will keep on playing, but you won't hear it.
      ActiveMovie, on the other hand, provides very little pause between loops. It will load a WAV file and set a property value as soon as the file is ready to play. Another property tracks the status of the sound, including indicating when the file has completed playing. Also, you can easily stop and restart sounds.
      ActiveMovie has its downsides too. It is much more complex than <BGSOUND>, and you need to include an ActiveX® control in your page. ActiveMovie doesn't stream, at least not with Internet Explorer 4.0, so you'll need to wait until the entire sound file is downloaded before it will play. Also, ActiveMovie doesn't read from the cache, so even if you've already downloaded a page, the next time you visit it you'll need to download the entire set of sounds again.
      You need to figure out which sound solution makes sense for your needs. If you need to provide exact coordination of sound with an animation, or you need to start and stop sounds, use ActiveMovie. If streaming and reading from the cache are more important, use <BGSOUND>.
      To use the ActiveMovie control, you first need to add the control to your page:

 <OBJECT id=snd1 CLASSID="CLSID:05589FA1-C356-11CE-BF01-00AA0055595A"
 style="visibility:hidden">
 <PARAM NAME="FileName" VALUE="snd1.wav">
 </OBJECT>
Then you can play the sound by calling the Run method on the control. Make sure that there is a sound card in the client machine; if there is no sound card, you will get an unfriendly script error message. Next, you need to make sure that enough of the sound has downloaded so that it can be played. Once again, if you don't check, you will get an obscure error message. You can see how to perform these checks with the following code, which will play a sound once it is downloaded:

 if (snd1.issoundcardenabled()) {    //Is there a sound card?
         if (snd1.readyState >= 3)   //Has enough downloaded that it can play?
         snd1.Run();
 }
The only trick is that detecting the sound card doesn't work if you are running NetShow™. Figure 1 shows a complete page that uses ActiveMovie to play a sound.

Is it Safe Yet?
      As I mentioned earlier, you can use ActiveMovie to detect when a sound has downloaded and is ready to play. For example, you might do this to make sure that all sounds are loaded before you begin playing an animation. Likewise, you can also determine when a sound has stopped playing. This is useful when you want to play sounds back to back, or if you want to start an animation or other sequence of events as soon as a particular sound stops playing.
      To determine if enough of the WAV file has downloaded, trap the readystatechange event. This event is passed one parameter, which contains a value of 3 or higher as soon as enough of the sound file has downloaded.
      You can determine when a sound file has stopped playing by trapping the statechange event. This is passed two parameters. The first contains the previous state and the second contains the current state. The value 0 means that the sound file has stopped playing.
      The code in Figure 2 traps the readystatechange event to determine when a sound file has downloaded and is ready to play. It also traps the statechange event to determine when a sound has stopped playing. You can easily modify it so that instead of displaying alerts, it triggers additional sounds or activity based upon the state of the sound files.


From the March 1998 issue of Microsoft Interactive Developer.