Article

The Flash Anthology: Cool Effects & Practical ActionScript - Chapter 5: Sound Effects

Page: 1 2 3 4 5 Next

Dynamic Panning Control

In this example, we animate an object across the screen and alter the panning of sound in accordance with the object's location. Panning involves the movement of a sound in stereo, which can add dynamism to even a single continuous tone. This builds on the previous example to increase your skills with the Sound class using a new method: setPan.

By default, the panning of a sound is set to 0, but we can use setPan to alter that between the limits of -100 (all sound to the left channel) and +100 (all sound to the right channel).

Let's mirror the movement of a simple animation from left to right with an effect that moves the sound from the left channel to the right.

To skip ahead and modify this effect, locate pancontrol.fla in the code archive.

Setting the Scene

  1. Create a new Flash document that's 500 pixels wide and 400 pixels high. Set the frame rate to 24 fps (Modify > Document…).
  2. Rename the default layer Actions, and create two new folders within the Library Panel: Movie Clips and Sound.
  3. Create a new movie clip symbol in the Movie Clips folder with arbitrary content. The example in the code archive uses a static text area in which the text "Sound Effect" appears.
  4. Drag an instance of the movie clip to the stage and name it clipper.
  5. Select File > Import to Library… and choose reverb.mp3 from the code archive, or import a sound file of your choice.
  6. Select the sound clip from the Library Panel, then right-click and select Linkage…. Check the Export for ActionScript checkbox, and enter reverb as the identifier.
  7. Adding the ActionScript

    We're done setting the scene. It's time to add the code to bring it all together.

  8. Select the first frame of the Actions layer and add the following code within the Actions Panel. As this is so similar to the previous example, I've highlighted the differences in bold:
  9. Example 5.3. pancontrol.fla Actions : 1

    MovieClip.prototype.WavePan = function (minValue, maxValue,  
       period)  
    {  
     this.period = period;  
     this.minValue = minValue;  
     this.maxValue = maxValue;  
     this.count = 0;  
     this.reverb = new Sound ();  
     this.reverb.attachSound ("reverb");  
     this.reverb.start (0, 999);  
     this.onEnterFrame = function ()  
     {  
       var value = (1 + Math.cos (this.count++ * 2 * Math.PI /  
           this.period)) / 2;  
       this._x = this.minValue + value *  
           Math.abs (this.maxValue - this.minValue);  
       this.reverb.setPan (-100 + value * 200);  
     };  
    };  
    clipper.WavePan (50, Stage.width - 100, 48);

    We give the method a new name (WavePan), we've, set the horizontal position (instead of the vertical scale) of the movie clip to oscillate between the maximum and minimum values, and have the sound pan between the left and right speakers.

    In our call to WavePan, we pass minimum and maximum values to ensure that the movie clip covers most of the stage:

    clipper.WavePan (50, Stage.width - 100, 48);

    All that remains is to test-drive the effect!

  10. Save your Flash document and preview your work.

Move your speakers apart or put your headphones on, so you can enjoy this effect to the full.

This simple effect can serve multiple purposes within your projects. It can really bring your creations to life, adding pizzazz to animations, navigation systems, and more!

Mini Sound Player

It's time to stretch our legs! We've covered the fundamentals of sound control. Now, let's move into the development of a fully functional sound playback device. In this example, we'll create a random sound player that provides visual feedback about various properties of the random sound clips it plays, as shown in Figure 5.1.

1366_ch5001
Figure 5.1. Create a mini sound player.

To jump forward and edit this effect, locate miniplayer.fla in the code archive.

Setting the Scene

  1. Create a new Flash document that's 450 pixels wide and 100 pixels high. Set the frame rate to 24 fps (Modify > Document…).
  2. Create three new layers, naming the top layer Actions, the middle Elements, and the bottom Background.
  3. Select the Background layer and create a background element that will surround the controls, as shown in Figure 5.1. Lock the Background layer.
  4. Create four buttons (as symbols in the Library) that visually reflect the following functions: Play, Stop, Increase Volume, and Decrease Volume. Refer to miniplayer.fla in the code archive or Figure 5.1 for examples.
  5. Drag instances of the buttons into the first frame of the Elements layer, naming them PlayClip, StopClip, VolumeUp, and VolumeDown. Arrange the buttons so they sit within the bounds of the background you created in step 3.
  6. Add a static text box beneath each of the buttons to identify the tasks they perform. In the example file, I labeled them play, stop, volume + and volume -, respectively.
  7. Locate the following files in the code archive and import them into your library (File > Import to Library…): choir1.mp3, choir2.mp3, choir3.mp3, choir4.mp3, and choir5.mp3.
  8. Select each sound clip within the Library Panel, then right-click and select Linkage…. Check the Export for ActionScript checkbox and accept the default identifier value (which should be choir1, choir2, etc.).
  9. As I've explained before, this allows us to access the sound clips dynamically without having to drag them onto the stage.

    We've successfully created the objects and imported the sounds we need to achieve basic functionality. All that remains is to add the ActionScript that controls the application.

    Adding the ActionScript

    First, we'll add the code that controls the playback of the sounds we imported.

  10. Select the first frame of the Actions layer and add the following code within the Actions Panel:
  11. Example 5.4. miniplayer.fla Actions : 1 (excerpt)

    function randomBetween (a, b)  
    {  
     return Math.min (a, b) + random (Math.abs (a - b) + 1);  
    }  
    PlayClip.onPress = function ()  
    {  
     stopAllSounds ();  
     _root.orchestra = new Sound ();  
     _root.orchestra.attachSound ("choir" + randomBetween (1, 5));  
     _root.orchestra.start ();  
    };

    As the music player plays clips at random, our familiar randomBetween function comes in handy.

    As the heart of this example, the onPress event handler of the PlayClip button definitely merits further study. The first thing it does is stop any sound that may already be playing, so that multiple sound clips aren't played at the same time if the PlayClip button is clicked repeatedly. The built-in stopAllSounds function handles this:

    stopAllSounds ();

    Next, we create a new Sound object and store it in a variable in the main movie (_root) called orchestra. We then use attachSound to load one of the five sounds from the library start it playing:

    _root.orchestra = new Sound ();  
     _root.orchestra.attachSound ("choir" + randomBetween (1, 5));  
     _root.orchestra.start ();

  12. Save and preview your work.
  13. Press the Play button and a randomly selected clip will begin to play; press it again and another random clip will play. It's all functioning as expected.

    Now, we'll add the Stop button's control code. This is much the same as the code we used with the Play button to remove the movie clips and stop all sound on the stage:

  14. Add the following code beneath what you already have:
  15. Example 5.5. miniplayer.fla Actions : 1 (excerpt)

    StopClip.onPress = function ()  
    {  
     stopAllSounds ();  
     _root.orchestra = null;  
    };

    We use stopAllSounds to stop any playing sounds, and throw away the Sound object we'd stored in the orchestra variable. This frees up the memory the object was using.

  16. Save and preview your work.
  17. When you press the Play button, the sound plays; when you hit the Stop button, it stops. Let's add the volume control buttons and finish this example.

  18. Insert the following code beneath what you already have:
  19. Example 5.6. miniplayer.fla Actions : 1 (excerpt)

    VolumeUp.onPress = function ()  
    {  
     if (_root.orchestra.getVolume () < 100)  
     {  
       _root.orchestra.setVolume (_root.orchestra.getVolume () +  
           10);  
     }  
    };  
    VolumeDown.onPress = function ()  
    {  
     if (_root.orchestra.getVolume () > 0)  
     {  
       _root.orchestra.setVolume (_root.orchestra.getVolume () -  
           10);  
     }  
    };

    When the volume of a sound clip is less than 100, we increase it in increments of ten each time the VolumeUp button is pressed. Conversely, when its volume is greater than zero, it's decreased in steps of ten each time the VolumeDown button is pressed.

  20. Save and preview your work.
  21. You can select a random clip by pressing the Play button, stop the dynamically loaded clip with the Stop button, and increase or decrease the volume of the clip using the volume controls. You may want to experiment with sound clips of your own, as those distributed in the code archive are quite short.

    Modifications

    We've successfully created an interface for the playback of random sound clips! We can extend it easily to provide visual feedback about the duration of the loaded track, the play time remaining, the name of the playing clip, and the volume level.

    To edit these additions, locate miniplayer-feedback.fla in the code archive.

  22. Working from the previous example, add a new layer below the Actions layer, and name it Labels. This will hold our text labels, which provide feedback about what's going on.
  23. Select the first frame of the Labels layer and create a new dynamic text field to the right of the volume buttons, as depicted in Figure 5.1. Name the instance volume.
  24. With the text box selected, click Character… in the Property Inspector and select Basic Latin (All Characters in Flash MX). Click OK.
  25. Referencing Figure 5.1 for placement, create the titles clip length and time remaining using static text areas.
  26. Insert three dynamic text fields beside the relevant titles, naming the fields clipname, cliplength and timeleft. Repeat step 3 for each of the text boxes. Make sure each box is large enough to hold the required information.
  27. Select the first frame of the Actions layer and replace the existing code with the following. The changes are extensive, but once again I've highlighted them in bold:
  28. Example 5.7. miniplayer-feedback.fla Actions : 1

    function roundNumber (toRound, numDecimals)  
    {  
     return Math.round (toRound * Math.pow (10, numDecimals)) /  
         Math.pow (10, numDecimals);  
    }  
    function randomBetween (a, b)  
    {  
     return Math.min (a, b) + random (Math.abs (a - b) + 1);  
    }  
    _root.createEmptyMovieClip ("tracker", 1);  
    PlayClip.onPress = function ()  
    {  
     stopAllSounds ();  
     _root.orchestra = new Sound ();  
     var clipnumber = randomBetween (1, 5);  
     _root.orchestra.attachSound ("choir" + clipnumber);  
     _root.orchestra.start ();  
     
     _root.tracker.onEnterFrame = function ()  
     {  
       _root.timeleft.text = roundNumber (  
           (_root.orchestra.duration - _root.orchestra.position)  
           / 1000, 2) + " seconds";  
     };  
     _root.cliplength.text = roundNumber (  
         _root.orchestra.duration / 1000, 2) + " seconds";  
     _root.clipname.text = "Choir" + clipnumber;  
     _root.volume.text = _root.orchestra.getVolume ();  
    };  
    StopClip.onPress = function ()  
    {  
     stopAllSounds ();  
     _root.orchestra = null;  
     _root.cliplength.text = "";  
     _root.clipname.text = "";  
     _root.timeleft.text = "";  
    };  
    VolumeUp.onPress = function ()  
    {  
     if (_root.orchestra.getVolume () < 100)  
     {  
       _root.orchestra.setVolume (_root.orchestra.getVolume () +  
           10);  
       _root.volume.text = _root.orchestra.getVolume ();  
     }  
    };  
    VolumeDown.onPress = function ()  
    {  
     if (_root.orchestra.getVolume () > 0)  
     {  
       _root.orchestra.setVolume (_root.orchestra.getVolume () -  
           10);  
       _root.volume.text = _root.orchestra.getVolume ();  
     }  
    };

    Let's dissect the changes we've made, so we understand how it all works!

    First, we introduce a new math function, roundNumber, which rounds figures to a specified number of decimal places. This will be used to show both the play time remaining for each clip and the clip's total duration.

    function roundNumber (toRound, numDecimals)  
    {  
     return Math.round (toRound * Math.pow (10, numDecimals)) /  
         Math.pow (10, numDecimals);  
    }

    We'll be updating the track time remaining with each frame of the movie, so we'll need an onEnterFrame event handler. Unfortunately, we don't have any obvious movie clip to hook that handler to. We could attach it to one of the buttons in our interface, but it's tidier to create an empty movie clip called tracker to host it:

    _root.createEmptyMovieClip ("tracker", 1);

    We then add the following code to the PlayClip button's onPress handler that sets up the event handler itself:

    _root.tracker.onEnterFrame = function ()  
     {  
       _root.timeleft.text = roundNumber ((_root.orchestra.duration -  
           _root.orchestra.position) / 1000, 2) + " seconds";  
     };

    This continuously updates the timeleft dynamic text field we created earlier. We constantly monitor the position of the sound clip using the duration and position properties of the Sound object, calculating the remaining time in milliseconds. We then convert this to a value in seconds, rounding to two decimal places with the help of our roundNumber function.

    We also update the other dynamic text fields that hold the length of the clip being played, its name, and its volume.

    _root.cliplength.text = roundNumber (_root.orchestra.duration /  
         1000, 2) + " seconds";  
     _root.clipname.text = "Choir" + clipnumber;  
     _root.volume.text = _root.orchestra.getVolume ();

    Within the StopClip button's onPress event handler, we include the following code, which clears the dynamic text fields of the information associated with the clip played previously:

    _root.cliplength.text = "";  
    _root.clipname.text = "";  
    _root.timeleft.text = "";

    Finally, the VolumeUp and VolumeDown onPress event handlers are updated. This ensures that any changes to the clip's volume are reflected in the volume dynamic text field.

    _root.volume.text = _root.orchestra.getVolume ();

    That's it for the code changes.

  29. Save your Flash document and preview it.

There! We have a fully-fledged random clip player that provides information on the duration of the current clip, its name, and the play time remaining.

This example can easily be extended through the addition of more clips to the library. Export them for ActionScript reference, and alter the code that selects the clip to play within the PlayClip button's onPress event handler.

Use an array!
A useful variation would be to store the linkage names of available clips in an array, so that the number of clips available would not have to be hard-coded.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links