Skip to main content

Home

Daniel C. Fergus

Artist & Educator

VCB-331 Rich Media 1

Using Sound Objects (Flash AS3)

Introduction

In Flash AS2 sounds could be controlled with a simple sound object class. In AS3 things are a bit more complicated; there are several different classes that divide the functionality of the old sound class: the Sound class, the SoundMixer class, the SoundChannel class and the SoundTransform class. Each has its own properties and methods; for example, the SoundChannel class is used to control playback (stopping and starting) while the SoundTransform class handles volume and panning. This division actually gives us greater control and the ability to micro manage sounds, but it is more complicated. In this exercise we'll explore some of the basics of using the various sound related classes.

The basics

  1. You'll need a sound of some sort (obviously). AIFFs, WAVs and mp3s work quite will with Flash. If you don't have a sound handy you can download this zipped file (it contains two songs by Kevin MacLeod from his royalty free music Web site ).
  2. Open a new Flash file and save it as mySoundTest1.fla.
  3. Import "Tech Talk" (or other sound) into the library.
  4. Now things get a bit tricky; in order to make sure that the SWF file has access to the sound file we need to export the sound for ActionScript and create a new class at the same time. It's essentially the same procedure we use whenever we're using library items rather than instances on stage (see Adding Children).

    Right-click (ctrl-click) on the name of a sound object in the library window to open its contextual menu. Select Properties, then check the "Export for ActionScript" option in the dialog box that appears. In the same dialog box you will need to give the sound an class name—a name that we use to refer to the class we are creating. By default the class name will likely be the file name; however, you can change it. Identifiers can not start with a number or special character and must be unique. I'm going to call mine Sound1. (Note that I capitalized the name of the class; that's considered best practice in the Flash world). When you click OK you will get a warning letting you no that a class with that name does not exist and that Flash will create one for us; that's what we want.

  5. Add a new layer and call it Actions. Click on the keyframe in frame 1 and open the script window.
  6. Define your sound object. Sound objects can be defined on the main timeline or within movie clips. In general it's usually best to define all of your sounds at the root level (which makes calling them with the code very easy, no long complicated URLs pointing down to the movie clip that contains the sound). Add this code:
    var mySound:Sound1 = new Sound1();
    mySound.play();    

    The first line of code creates an instance of our Sound1 class that I've named mySound. This is an arbitrary name that I gave it; you could call it whatever you like (as long as you use standard naming conventions and don't use a word/term that's already part of ActionScript). The second line uses the play() method of the Sound class to get the sound playing. You can specify where the sound starts by adding a number (in milliseconds) inside the parenthesis. Try this:

    var mySound:Sound1 = new Sound1();
    mySound.play(200);    

    You can also specify the number of times a sound will play like this:

    var mySound:Sound1 = new Sound1();
    mySound.play(0, 5);    

    Now it starts at the beginning (the zero), but plays through five times.

User control

  1. Okay that's cool, but what if we wanted to give the user the ability to start and stop the sound (always a good thing). Create a couple of buttons to control the sound—an "on" and "off" button. Place them both on stage. Give the "on" button the instance name start_btn, and the "off" button the instance name stop_btn.
  2. Next we'll make the buttons work. Strangely enough, the Sound class does not have a method for stopping a sound. Instead, we need to make use of the SoundChannel class. Fortunately, we can also use this class to start sounds. So let's modify our code a bit. Add the new code:
    var mySound:Sound1 = new Sound1();
    var myChannel:SoundChannel = new SoundChannel();
    myChannel=mySound.play(0,5);    

    If you run this the sound will play just as it did before. But now we can get our buttons working since we have a SoundChannel for them to control.

  3. Create two listeners for the buttons:
    start_btn.addEventListener(MouseEvent.CLICK, startSound1);    
    stop_btn.addEventListener(MouseEvent.CLICK, stopSound1);  

    Each button calls its own function, which we will write next:

  4. Now the functions:
    function startSound1(myEvent:MouseEvent):void { 
        myChannel=mySound.play(0,5);    
    }    
    function stopSound1(myEvent:MouseEvent):void { 
        myChannel.stop();    
    }  

    Pretty straightforward; one function uses the play() method to start the sound, the other uses the stop() method. Try it again. You should be able to stop the sound and start it again. It works pretty well...unless you hit the start button more than once consecutively. If you do, another occurrence of the sound plays on top of the first. Repeated pushes on the start button creates a nasty din. And worse still, the stop button only stops the first sound! AAIIIEEEE! MAKE IT STOP!

    We need to add a conditional that checks to see if the sound is playing already, and if so prevents the start button from working...

  5. First we need to create a new variable (we'll call it "isPlaying"). Put it at the top of your code:
    var isPlaying:Boolean = true;  
  6. And now add the new code to your button functions:
    function startSound1(myEvent:MouseEvent):void {
        if (!isPlaying) { 
            myChannel=mySound.play(0,5); 
            isPlaying = true;
        }      
    }    
    function stopSound1(myEvent:MouseEvent):void { 
        myChannel.stop(); 
        isPlaying = false;    
    }  
    The conditional statement checks to see the status of the playing variable. If it is true, it ignores the command to start. However, if it is false (!isPlaying), it starts the sound and then switches the variable's value to true.

Pausing sounds

Okay, we can start and stop the sound, but there's still a small problem: every time you start the sound it starts playing from the beginning, not where you stopped it. Let's turn the stop button into a pause button instead.

Now you'd think this would be easy, just call a pause() method, right? Well unfortunately the folks at Adobe haven't gotten around to adding that functionality to the Sound objects, so we're going to have to do it ourselves. To do this we'll make use of the SoundChannel's position property.

  1. First let's create another new variable to store the position of the playhead when the sound stops. We'll call it "lastPosition" and you should put this line of code at the top of your script (right below where you declared the "isPlaying" variable):
    var lastPosition:Number = 0;
  2. Now we need to add a new line to the stopSound1 function and a new argument (property) to the startSound1 function:
    function startSound1(myEvent:MouseEvent):void {
        if (!isPlaying) { 
            myChannel=mySound.play(lastPosition,5); 
            isPlaying = true;
        }      
    }    
    function stopSound1(myEvent:MouseEvent):void { 
        lastPosition = myChannel.position;
        myChannel.stop(); 
        isPlaying = false;    
    }  
    The position property of the soundChannel class records the position of the playhead within the sound. In the stop function we make a note of that position and store it in the lastPosition variable. Then we drop that variable in place of the zero in the play method, ensuring that the sound will always play from the spot where it left off. Try it.

Controlling the volume

To control the volume of a sound file requires yet another class, the soundTransform class. The soundTransform class is actually a property of the soundChannel class.

  1. Drag two more instances of your on and off buttons on to the stage; we'll use these for volume-up and volume-down buttons (or, if you prefer, you can make new buttons. An up and a down arrow work well for volume controls).
  2. Give these buttons the instance names volUp_btn and volDown_btn.
  3. Now we need to create an instance of the soundTransform class. Insert this line after the line in which you create the myChannel instance:
    var mySound:Sound1 = new Sound1();
    var myChannel:SoundChannel = new SoundChannel();
    var myTransform:SoundTransform = new SoundTransform();
    myChannel=mySound.play(0,5);    
  4. Next we need to set a starting volume. The volume property can contain a value from 0 to 1 with 1 being the maximum, at least in theory; in practice the volume will continue to climb well past 1 if you don't limit it in some way. Let's start it at .5; add the following lines right after the line added above:
    var mySound:Sound1 = new Sound1();
    var myChannel:SoundChannel = new SoundChannel();
    var myTransform:SoundTransform = new SoundTransform();
    myTransform.volume = 0.5;
    myChannel.soundTransform = myTransform;
    myChannel=mySound.play(0,5);    
  5. We need to add two new listeners to the up and down volume buttons (put these with the other listeners):
    volUp_btn.addEventListener(MouseEvent.CLICK, onVolUpClick);    
    volDown_btn.addEventListener(MouseEvent.CLICK, onVolDownClick);
  6. And the two new functions:
    function onVolUpClick(event:MouseEvent):void { 
        myTransform.volume=myTransform.volume+0.2; 
        myChannel.soundTransform=myTransform;
        trace(myTransform.volume);     
    }   
     function onVolDownClick(event:MouseEvent):void { 
        myTransform.volume=myTransform.volume-0.2; 
        myChannel.soundTransform=myTransform; 
        trace(myTransform.volume);    
    }  

    The first function (onVolUpClick) increases the volume by .2 with every click. I've also added a trace command so that you can see the value of the volume setting when you click the button. Similarly the onVolDownClick subtracts .2 with every click and also traces the result.

    Run it and start clicking away. You should note a few interesting things happening. First is the fact that Flash seem to have a hard time adding and subtracting .2; you get a lot of long decimals like .1999999999, etc. Second, the increasing volume can go well past 1, to 2, 3, 4, and beyond. Also, it can drop below 0. And even odder, negative numbers act like positive ones, so as the volume value decreases below zero, the actual volume increases. You may also notice that every time you stop and start the sound it starts playing it at .5, but then jumps up or down to the level of the volume control's last value when you click on them. Okay, let's fix these bugs (well, the ones we can fix...)

  7. First, we'll fix the on button so that it always plays the sound at the correct volume. Modify the startSound1 function by adding the new line:
    function startSound1(myEvent:MouseEvent):void {
        if (!isPlaying) { 
            myChannel=mySound.play(lastPosition,5); 
            isPlaying = true;
            myChannel.soundTransform = myTransform;
        }      
    }    
  8. Now let's set limits on the volume controls, a minimum of zero and a maximum of 1. We'll do this with a couple of conditionals. Add the new bits:
    function onVolUpClick(event:MouseEvent):void { 
        myTransform.volume=myTransform.volume+0.2; 
        if (myTransform.volume>=1) {
            myTransform.volume=1; 
        }
        myChannel.soundTransform=myTransform;
        trace(myTransform.volume);     
    }   
     function onVolDownClick(event:MouseEvent):void { 
        myTransform.volume=myTransform.volume-0.2;
        if (myTransform.volume<=0) { 
            myTransform.volume=0; 
        }  
        myChannel.soundTransform=myTransform; 
        trace(myTransform.volume);    
    }  
  9. The one thing we can't fix is the long weird decimals; that's a Flash thing. It doesn't hurt us at all. Go ahead and remove the two trace commands; we no longer need them.

Stopping multiple sounds

It's not uncommon to have a situation where several sounds are playing in different sound channels. Having the ability to silence them all with one command is a great value. We can accomplish this with the SoundMixer() class.

  1. Save your Flash file as mySoundTest2.fla; this way we can make some significant changes to the code without wiping out all of the work you did.
  2. Add a second sound to the mix. You can use the other song you downloaded earlier, or another sound of your choosing. Import it into your library. Go into the sound's properties and once again choose "Export for ActionScript." Finally, give it the class name Sound2.
  3. Add a new button to your stage called start2_btn.
  4. Remove the volume controls (we don't need them for this demo so let's just get rid of them.
  5. Next let's modify the ActionScript Below is a simplified version of the code with the volume controls removed. I've also removed the pause function. And it doesn't play automatically—you have to press the play button to hear the sound. Copy and paste this into your ActionScript, replacing the code that is currently there.
    var isPlaying:Boolean = false; 
    var mySound:Sound1 = new Sound1(); var myChannel:SoundChannel = new SoundChannel(); start_btn.addEventListener(MouseEvent.CLICK, startSound1); stop_btn.addEventListener(MouseEvent.CLICK, stopSound1); function startSound1(myEvent:MouseEvent):void { if (!isPlaying) { myChannel=mySound.play(0,5); isPlaying = true; } } function stopSound1(myEvent:MouseEvent):void { myChannel.stop(); isPlaying = false; }
    The start and stop buttons should work for the first sound.
  6. Now let's get the second sound working. Since we want to hear (and control) two or more sounds at the same time we'll create a second soundChannel in addition to our second sound. We'll also create a second boolean variable to keep track of whether the second sound is playing. And of course we have to wire up our second play button. Modify the code as follows:
    var isPlaying:Boolean = false;
    var isPlaying2:Boolean = false; 
    var mySound:Sound1 = new Sound1(); var mySound2:Sound2 = new Sound2(); var myChannel:SoundChannel = new SoundChannel(); var myChannel2:SoundChannel = new SoundChannel(); start_btn.addEventListener(MouseEvent.CLICK, startSound1); start2_btn.addEventListener(MouseEvent.CLICK, startSound2); stop_btn.addEventListener(MouseEvent.CLICK, stopSound1); function startSound1(myEvent:MouseEvent):void { if (!isPlaying) { myChannel=mySound.play(0,5); isPlaying = true; } } function startSound2(myEvent:MouseEvent):void {
    if (!isPlaying2) {
    myChannel2=mySound2.play(0,5);
    isPlaying2 = true; }
    }
    function stopSound1(myEvent:MouseEvent):void { myChannel.stop(); isPlaying = false; }
    If you try it now you'll find that the first sound starts and stops as before, and the second sound starts, but doesn't stop. That's because the stopSound1() function is stopping myChannel, and not myChannel2. To fix this we're going to modify the stop function a tiny bit; we're going to add the soundMixer() class which has a stopAll() method:
  7. function stopSound1(myEvent:MouseEvent):void { 
        //myChannel.stop(); 
        SoundMixer.stopAll();
        isPlaying2 = false;
        isPlaying = false;    
    }
    Try it now.

Other sound tutorials

 

decorative thumbnail

All text, images, and multimedia pieces (unless otherwise specified) copyright 2005–2011 Daniel C. Fergus. All rights reserved. No reproduction without permission.