Ultrashock Tutorials > Flash5 > Sound Object - Part II  
 
by: Allan Kennedy, zinc Roe design


Source File

 
Sound Object - Part II Multiplicity
 

Dispelling the Myths

There has been a considerable amount of confusion surrounding the programmatic use of multiple sounds. Controlling the playback of a single sound in the Flash player is easy, but controlling multiple sounds independently has caused the woes of many.

This confusion exists due to the way that the sound object is instantiated with its constructor function and corresponding parameter value. One would think that simply referring to the sound object's constructor function with two separate variables would allow independent control of both the sounds respectively attached (as seen below). This, however, is not the case.

function soundInit(){
    sound1= new Sound(); // global sound object
    sound2= new Sound(); // another global sound object
    sound1.attachSound("soundId1");
    sound2.attachSound("soundId2");
    sound1.start(0,500);
    sound2.start(0,500);
    sound1.stop();
}

The first invocation of the stop method in this case would also terminate playback of both sounds - not just 'sound1.' The stop() method refers to a global sound object (sound1 is attached to the _root timeline and highest in the chain of command), and controls all sounds in the player- even those placed within nested timelines and set to a stream or event sync. Why? When the sound object is attached to the _root timeline (which is what occurs by default- without a parameter value) we create a global sound object that can control all sound in nested timelines. The stop method in this case refers to a global sound object. Once you wrap your head around the fact that simply assigning different variable names to instances of the sound object is not always going to give you the independent control you seek, you will be one big step closer to controlling multiple sounds.

Breaking Away

Let's take a closer look at some of the parameters for the methods of the sound object that would allow us to pinpoint individual sounds.

new Sound(target);

The constructor function for the sound object can receive an optional target parameter (a valid movie clip reference) which is essential in dealing with multiple sounds. It is this parameter value that allows us to break away from a tyrannical global sound object that controls all the sounds in our player. Think of it as a chain of command: the closer the instantiated object is to the _root timeline, the more authority it has. Our next source file will demonstrate how to use this parameter.

sound1.stop("soundId1");

The stop method can be used to pinpoint and stop individual sounds that exist in the same timeline. This is achieved by using the linkage identifier (used to force export of the sound) as a parameter value for the stop() method.

Three for Dinner

The source file (soundObj_04.fla) demonstrates a simple way of utilizing and individually controlling multiple sounds in your flash movie. This is done by creating three movie clip instances. Each of these contains two sliders- one for volume and the other for pan control. Each sound object is instantiated within these movie clips allowing us to control individual sounds or control them all at once with the larger buttons to the right. Let's look at the code attached to each clip:

onClipEvent (load) {
    sComponent = new Sound(this);
    sComponent.attachSound(this._name);
    var loops = 500;
    var secondOffset = 0;
    var volume = 100;
    var pan = 0;
    var playing = false;
}
onClipEvent (enterFrame) {
    sComponent.setVolume(volume);
    sComponent.setPan(pan);
}

Notice in the above code that the sound object is instantiated with our new Sound constructor function using 'this' as a parameter value. The this keyword is a reference to the movie clip instance - and associates each sound object with a unique timeline. Once the new sound object is referenced through the variable sComponent (notice all three movie clip symbols use the same variable name for the sound object- we can do this since they all exist within different timelines), we can attach one of the three sounds by passing their identifier to the attachSound() method. I have found it convenient to match my clips' instance names to the identifier string used in linkage properties. In this case s1, s2, and s3 were used for each clip.

The variable statements that follow are declaring and initializing values that will be needed later by our start(), setVolume(), and setPan() methods. In the enterFrame clipevent we are checking for any change in our volume and pan values.

We control each sound object (starting, stopping, use of sliders) in the same as in part one (please see part I of this tutorial if this is unclear). You should now have three sounds that can be controlled independently via the sliders and buttons!

Good, but Now All Together

So what if we want to give up all that independence and start all the sounds together? Well, we can use a simple little script to check which ones are not currently playing (so that we don't begin playback of two instances of the same sound) and then tell each of them to begin.

on (release) {
    var tempMc;
    for (var i=1; i<=3; i++) {
         tempMc = _root["s"+i];
         if (!tempMc.playing) {
         tempMc.sComponent.start(tempMc.secondOffset, tempMc.loops);
         tempMc.playing = true;
        }
    }
}

We can use the array access operator to dynamically generate the names of each symbol containing the sound and then conveniently access the same variable within each scope that refers to that sound object. We also have to set each instance playing value to true.

To stop all the sounds together we use a similar approach, yet a little simpler, since we don't need to know what is currently playing. We can just stop them all.

on (release) {
     var tempMc;
     for (var i=1; i<=3; i++) {
     tempMc = _root["s"+i];
     tempMc.sComponent.stop();
     tempMc.playing = false;
    }
}

All Buffed Up

Great! We have three sounds with independent and general controls. In this tutorial we have three sounds, only one of which has a strong beat. What if we had three sounds that all contained strong rhythmic activity at the same bpm (beats per minute) and they all needed to be synchronized during playback. This is where it gets a little strange and a bit more complicated. Since these sounds are attached at runtime as event synch sounds they do not have the built-in 5 second (of playback time) buffer that stream synch sounds have. This is needed to synch the beats in these types of loops. To do this we have to use a little trick to simulate a buffer for each sound. Remember, this is only important when all three sounds contain corresponding rhythms/bpm. So, all we have to do is start each sound at zero volume- stop them all- and finally restart them at the desired volume level. We could use something similar to the previous code sequence.

function reSynch () {
var tempMc;
for (var i=3; i>0; i--) {
     tempMc = _root["s"+i];
     tempMc.playing = true;
     tempMc.sComponent.setVolume(0);
     tempMc.sComponent.start();
     tempMc.sComponent.stop();
     tempMc.sComponent.start(0, 500);
     tempMc.sComponent.setVolume(100);
    }
}

Final Issues

There are a few concerns that you should be aware of when dealing with multiple sounds. These include preloading on another level and the maximum number of sounds.

Since multiple sound files can easily escalate the file size of your project it is always a good idea to use some type of preload system. Just one problem- since sounds exported using linkage properties are downloaded before the first frame is rendered- before anything else happens- this can be very difficult. The end user wouldn't even be able to see a piece of text until all the sounds have been downloaded- which defeats the whole idea of having a preloader! So it is a good idea to use a preload system that does the getBytesLoaded() and getBytesTotal() checking from one level and loads the swf with the sounds set for forced export into a level above it. Alternatively, you could load the sound into a movieclip instance on the parent level. Either scenario should resolve this problem.

Another point you should be aware of before jumping into a sound project is the maximum number of sounds that can safely be controlled via the sound object. I have heard many different point of views on this matter (some say four others insist on six). Ultimately, this is dependent on the capabilities of your sound card- some low-end cards can only play eight individual sounds simultaneously. I would recommend limiting this to no more than eight sounds (which is what I have safely worked with to date). Synchronizing multiple sounds, however, is a strange dark world that could be an article unto itself. The reSynch function above will safely synchronize the tempo three sounds. It is possible, however, to extend the power of this resynch function.

One final point to be aware of, especially with multiple sound usage, is end-user resources. Since the sound object can be mildly taxing on a user's resources it is a good idea to delete the variable that refers to the object when it is no longer required. One word of warning: do not forget to stop the sound before deleting it. If it is not stopped before deletion- it develops a mind of its own and you loose control of that object.

I hope that this sheds a little more light on controlling multiple sounds and that sound continues to brighten the world of interactivity and animation!

 
©2001 Ultrashock.com Inc. - All rights reserved