Wednesday, January 12, 2011

AS3 Sound

Exercise Files:
Sound.fla
CheerfulSong.mp3

In this lesson, we're going to learn how to control sound in Flash using ActionScript 3. We're going to learn:
  • how to load an external sound file into a Flash movie
  • how to play and stop the sound
  • how to detect when the sound clip has reached the end

Exercise files accompany this article - we have a Flash document named Sound.fla and an mp3 document named CheerfulSong.mp3. Please make sure to save them both inside the same folder. In the first part of this tutorial, we'll learn how to load CheerfulSong.mp3 into our Flash movie using ActionScript. Instead of importing CheerfulSong.mp3 into Sound.fla's library, both files will remain separate from each other, but we will use ActionScript so that we will be able to play the sound from within the Flash movie.

Let's begin.

Loading and Controlling an External Sound File

How do you control sound using ActionScript 3?
To control sound in your Flash movie using code, create a Sound object using the the AS3 Sound class to control the sound .

A Sound object can be used to do the ff:
  • load an external sound file into a Flash movie
  • start the playback of that loaded sound file

NOTE: You can NOT use a Sound object to stop playing sound. The Sound class does not have a method for that. If you want to stop a sound clip's playback, you'll have to use a different class - the AS3 SoundChannel class - which we will talk about later. 

STEP 1

Open the Sound.fla file. You'll see that there are two buttons on the stage - play_btn and stop_btn. But let's ignore those buttons for now. First, let's write some code that will load and play the sound right away. Select frame 1 of the Actions layer, then go to the Actions Panel and type in the following lines:
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");
The first line (var mySound:Sound = new Sound();) creates an instance of the Sound class. I've named it mySound. We will use this to load and play the external sound file named CheerfulSong.mp3.

The second line (var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");) creates a URLRequest object. This is used to specify the path to the external file that we want to load.

STEP 2

So now that we've created those two objects, we can now load the external sound file. Use the load() method of the Sound class and pass to it the URLRequest object:

Sound.load(URLRequest);

So in our example, we would write:

mySound.load(myURL);

This instructs our mySound object to load the file specified in myURL (which is CheerfulSong.mp3). So go back to the code and add the following line highlighted in bold:
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");

mySound.load(myURL);

NOTE: When using the load() method of the Sound class, the external sound file must be in the mp3 format. And if you want to load more than one sound file, then create another Sound object for each succeeding sound file that you'd like to load, even if you're reloading the same sound file.

STEP 3

If you test the movie at this point, you won't hear the sound just yet. That's because we just told Flash to load the sound. We haven't given the instruction to start playing the sound yet. To make the sound start playing, we use the play() method of the Sound class:
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");

mySound.load(myURL);
mySound.play();
So if you test the movie now, you should hear the sound playing.

The play() method of the Sound class has 2 optional parameters:
  1. startTime - this lets you specify the point (in milliseconds) where the sound playback should start
  2. loops - this lets you specify how many times the sound should repeat playback
For example, lets pass values to these 2 parameters like so:

mySound.play(25000, 2);

The first value refers to the startTime parameter. Here, we've specified a value of 25000 milliseconds (or 25 seconds). This means that when the sound begins playing, it will start playing at the sound's 25-second mark, instead of starting at the beginning. So it will skip the first 24 seconds of the song when the playback starts.

The second value refers to the loops parameter. We've specified a value of 2. This means that the sound will play 2 times. When it plays the first time and then reaches the end, it will loop back to the startTime and play one more time.

Test the movie in order to verify, and then change the play statement back to mySound.play(); (without any parameters), and let's continue.

STEP 4

If we want the sound to play only after the play button (named play_btn) has been clicked, then we'll have to create a mouse click event listener for the play button, and we'll transfer the play sound statement inside that event listener:
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");

mySound.load(myURL);
// Make sure that you remove the play sound statement
// that was here, and transfer it into the mouse click
// event listener function

play_btn.addEventListener(MouseEvent.CLICK, playSound);

function playSound(e:MouseEvent):void
{
     mySound.play();
}
Here, we've created a mouse click event listener function named playSound, and we've transferred the mySound.play() statement into that event listener function. So now, when we test the movie, the sound is only going to play when the play button is clicked.

STEP 5

So now that we can play the sound, how do we stop it?
You can NOT stop the sound using the Sound class (e.g. Sound.stop() will not work). Another class is used for that - the SoundChannel class - which has a stop() method that will let you stop a sound's playback.

Let's go ahead and create an instance of the SoundChannel class. I'm going to name it mySoundChannel.
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");
var mySoundChannel:SoundChannel = new SoundChannel();

mySound.load(myURL);
We now have a SoundChannel object named mySoundChannel.

STEP 6

Think of the SoundChannel as the object that houses or contains your sound. In order to place a sound inside a SoundChannel, you assign the play sound statement to a SoundChannel like so:

SoundChannel = Sound.play();

So in our example, we would write:

mySoundChannel = mySound.play();

This assigns mySound.play() to mySoundChannel, so that the sound is going to play inside mySoundChannel. Let's go ahead and assign mySound.play() to mySoundChannel in our code:
var mySound:Sound = new Sound();
var myURL:URLRequest = new URLRequest("CheerfulSong.mp3");
var mySoundChannel:SoundChannel = new SoundChannel();

mySound.load(myURL);

play_btn.addEventListener(MouseEvent.CLICK, playSound);

function playSound(e:MouseEvent):void
{
     mySoundChannel = mySound.play();
}

STEP 7

So we've now assigned our sound to a channel. In order to stop the sound, then we'll have to stop the SoundChannel that contains the sound. We will use the stop() method of the SoundChannel class like so:

mySoundChannel.stop();

This will stop whatever sound that is playing inside the mySoundChannel object.

Let's put this stop statement inside a mouse click event handler for the stop button (stop_btn) so that our sound will stop playing when the user clicks on the stop button:
play_btn.addEventListener(MouseEvent.CLICK, playSound);
stop_btn.addEventListener(MouseEvent.CLICK, stopSound);

function playSound(e:MouseEvent):void
{
     mySoundChannel = mySound.play();
}

function stopSound(e:MouseEvent):void
{
     mySoundChannel.stop();
}
Here, we've created a mouse click event listener function named stopSound() for the stop button. This event listener function contains the mySoundChannel.stop(); statement. So now, the user can click on the stop button in order to stop the sound's playback.

NOTE: If you want to be able to play multiple sounds simultaneously and still be able to individually stop each sound, then you will need to create one SoundChannel for each sound.

And that concludes the first part of this tutorial. But don't close your Sound.fla document just yet. In the next part, we'll learn how to write some code that will enable Flash to detect when the sound has reached the end. This is useful if you want your Flash movie to do something once a sound clip has completed playback.

Detecting when a Sound has Reached the End

In some cases, you might want to enable Flash to detect when a sound clip has reached the end. Let's say, for example, you have a song that's playing in the background, and you'd like Flash to display an image or a message only when the song has completed playing. To be able to detect when a sound file has reached the end, you can use the Event.SOUND_COMPLETE event of the SoundChannel class. This event gets dispatched once a sound file completes playback.

STEP 1

Let's go ahead and add an Event.SOUND_COMPLETE listener to our code. I'm first going to create the event listener function, which I will name endOfSound.
function playSound(e:MouseEvent):void
{
     mySoundChannel = mySound.play();
}

function stopSound(e:MouseEvent):void
{
     mySoundChannel.stop();
}

function endOfSound(e:Event):void
{
     trace("Sound playback is complete.")
}
Here, we have an event listener function named endOfSound. When this function gets called, it's going to trace a message to the Output window.

STEP 2

Now that we have this event listener function, we then need to add the event listener to our SoundChannel object. When you're adding an Event.SOUND_COMPLETE listener, the event listener must only be added AFTER the line where the play sound statement has been assigned to the SoundChannel (i.e. after the SoundChannel = Sound.play() statement). In our example, this line would be:

mySoundChannel = mySound.play();

And in our code, this line can be found inside the playSound event listener function. So we must add the event listener for Event.SOUND_COMPLETE right AFTER that line:
function playSound(e:MouseEvent):void
{
     mySoundChannel = mySound.play();
     mySoundChannel.addEventListener(Event.SOUND_COMPLETE, endOfSound);
}

function stopSound(e:MouseEvent):void
{
     mySoundChannel.stop();
}

function endOfSound(e:Event):void
{
     trace("Sound playback is complete.")
}
Now that the event listener has been added, Flash can now detect when the sound has reached the end. If you test the movie now and play the song, the trace statement will output the message once the song reaches the end. So whatever other instructions you'd like to tell Flash to do once the song has reached the end (e.g. play another song, stop the animation, go to the next frame, display an image) should be placed inside the Event.SOUND_COMPLETE event listener function.

Lastly, let's learn how to stop playing multiple sound clips all at once.

Stopping All Sounds at Once

In our example, we're only playing one sound file. But what if you have multiple sound clips playing all at the same time and you'd like to stop all of them at once? You can do that by using the stopAll() method of the SoundMixer class. In the example below, we have some code that stops all the sound clips that are currently playing, when a button is clicked:
// Assume that stopAll_btn is a button 
// that already exists on the stage
stopAll_btn.addEventListener(MouseEvent.CLICK, beQuiet);

function beQuiet(e:MouseEvent):void
{
     SoundMixer.stopAll();
}
Here, we've created a mouse click event handler that will enable the user to stop all sound clips that are currently playing by clicking on the button.

And those are the basics of how you can use the AS3 Sound class and the AS3 SoundChannel class in order to work with sound in Flash. And with that, this tutorial is now concluded.

3 comments:

  1. How can we play all sound ate the same time (simultaneously), we have drums, bass, guitar, voice, and we want to play them at the same to get right song.
    I have try to that but sounds are delaying they just don't play simultaneously.
    Explanation that I get was "it sounds like a Flash Player / CPU issue with playing/decoding that many MP3s together simultaneously."
    http://forums.greensock.com/viewtopic.php?f=6&t=4516&start=10

    ReplyDelete
  2. This is great, but I want the sound to automatically start playing, then just use one button to first pause the sound, then toggle to stop the sound.

    ReplyDelete
  3. Excellent step by step tutorial...many thanks for sharing!

    ReplyDelete