Advertisement
  1. Code
  2. Interface Design
Code

Go Retro With a Funky Flash Music Player

by
Difficulty:IntermediateLength:LongLanguages:

We're going to embrace both ActionScript 3 and Flash's design tools to create a retro cassette music player. This tutorial will take you through a variety of topics including music streaming, timeline animation, custom movie clip classes and event handling.


Introduction

Most ActionScript programmers avoid the timeline like the plague, opting to write hundreds of lines of code to perform a task that could have been achieved in seconds using the drawing and animation tools provided by the Flash IDE.

This tutorial will show you how to get the best from both worlds as you build a simple but fun retro music player. It'll encourage you to take advantage of the timeline where appropriate, allowing you to focus on the ActionScript that really matters.


Step 1: Document Settings

I'm using Flash CS5 but this tutorial will work with every Flash CS version. The accompanying source FLAs have been saved in Flash CS3 format and can also be used with any Flash CS version.

Launch Flash and create a new ActionScript 3.0 document. Set the stage size to 800x530px, and the frame rate to 24fps.



Step 2: Interface

Here's the interface we'll be working towards. It's an old-school audio cassette complete with tape that winds through the rollers as music is streamed.


It may seem a little daunting but there are only a few moving parts - the rest is static. Below you can see the various movie clip symbols that the cassette is broken down into.

The cassette housing is split into a back panel...


... and a front panel.


A separate movie clip symbol holds the parts that are found within the casing, including the rollers at the bottom corners and the two reels with the tape that winds around them.



Step 3: Recreating the Interface

The individual steps required to draw the cassette are out of the scope of this tutorial. However, even if you are familiar with Flash's drawing tools I encourage you to take the time to recreate the required movie clips yourself.

Import a bitmap image of the final cassette from: source/reference.png and use it as a point of reference.

Select: File | Import | Import to Library... . Browse to, and select the reference bitmap.


Step 4: Cassette Back Plate

Using the reference bitmap as a starting point, we will create the cassette's back plate.

Create a new movie clip symbol by selecting: Insert | New Symbol (Ctrl + F8). Name the symbol "Back" and set its type to "Movie Clip". Click OK.


Create a guide layer and name it "Reference". Select the layer. Drag an instance of reference.png from the library and centre it on the stage.

Lock the layer. We can start to create the back plate by drawing in layers above, effectively tracing over the reference bitmap.


When constructing the clip, take advantage of timeline layers and folders to keep yourself organised. The different color


ed outlines below highlight the individual layers I used.


Your finished back plate should resemble this:


To see my version open source/cassette-no-code.fla, find the Back movie clip symbol within the library and open it:



Step 5: Cassette Front Plate

The cassette's front plate isn't that different from the back.

Create a new movie clip symbol and name it "Front".

Again, create a guide layer and use the reference bitmap from the library as a guide.

When color


ing the front plate be aware that you'll need to ensure that the surface is transparent in order for the cassette's internal parts (reels, rollers and tape) to be visible beneath.

For your fill color


simply select an alpha percentage from the color


picker panel. I opted for a color


of #A89FBD and 10% alpha.


Try to utilise multiple timeline layers when constructing your movie clip symbol. The different color


ed outlines below highlight the individual layers I used.


Your finished front plate should resemble this:


To see my version open source/cassette-no-code.fla, find the Front movie clip symbol within the library and open it:



Step 6: Organise Your Library

We have the cassette housing complete and stored in the library as Front and Back. At this point you might want to create a folder within your library called "Housing" and move both clips into it along with any additional clips used by them.

You can see below that I created addition sub-folders to help further tidy things. You may want to do the same if the root of your Housing folder looks cluttered.



Step 7: Reel

Now let's create the reels that the tape winds around. Both reels are identical so we only need to create a single movie clip symbol that can be used for both.

Create a new movie clip symbol and name it "Reel".

Try to make your attempt look as close as possible to the reel from the reference bitmap.

Below, the color


ed outlines give some insight into how I constructed my reel, and you can also see how your finished reel should look.


To see my version open source/cassette-no-code.fla, find the Reel movie clip symbol within the library and open it:



Step 8: Animating the Reel

We have a movie clip symbol that represents the reel. Now we can create an animation of the reel turning.

Create a new movie clip symbol and name it "Reel Turning".

Rename the layer to "Reel" and drag the Reel movie clip symbol from the library to the stage. Centre the movie clip instance on the stage.

Move to frame 90 and create a keyframe by selecting: Insert | Timeline | Keyframe.


Move back to the start of the timeline and right-click on frame 1. From the context menu select Create Classic Tween. (If you're using Flash CS3 select Create Motion Tween)

From the frame's Properties pane, set the Rotate field to: CCW. (If you're using Flash CS4 or CS5 then you may need to expand the Tweening category to reveal the Rotate field)


Currently frames 1 and 90 are identical, preventing our animation from looping perfectly.

Move to the end of the timeline and right-click on frame 89. From the context menu select Insert Keyframe. Now right-click on frame 90 and select Remove Frames. You will be left with 89 frames in your timeline.

This slight modification will allow the turning animation to smoothly loop.

To see my version open source/cassette-no-code.fla, find the Reel Turning movie clip symbol within the library and open it:



Step 9: Guide Roller

The two guide rollers that sit at the bottom corners of the cassette are much easier to recreate than the reels. Again we can construct a single library clip that can be used for both.

Create a new movie clip symbol and name it "Roller".

Your finished roller should look like this:


My final version can be found in the library of source/cassette-no-code.fla:



Step 10: Animating the Guide Roller

The procedure for animating the guide roller is almost identical to that of the reel.

Create a new movie clip symbol and name it "Roller Turning".

Rename the layer to "Roller" and drag the Roller movie clip symbol from the library to the stage. Centre the movie clip instance on the stage.

The cassette's rollers will spin faster than the reels, therefore we'll use fewer frames for this animation.

Move to frame 45 and create a keyframe by selecting: Insert | Timeline | Keyframe.


Move back to the start of the timeline and right-click on frame 1. From the context menu select Create Classic Tween. (Flash CS3 users should select Create Motion Tween).

From the frame's Properties pane, set the Rotate field to: CCW.


As was the case with the Roller Turning movie clip symbol, both the first and last frames of the tween will be identical, preventing our animation from looping smoothly.

Move to the end of the timeline and right-click on frame 44. Select Insert Keyframe. Now right-click on frame 45 and select Remove Frames.

The roller will now smoothly loop when animating.

To see my version open source/cassette-no-code.fla, find the Roller Turning movie clip symbol within the library and open it:



Step 11: Containing the Internal Parts

Let's create a new movie clip symbol called "Parts" and drag into it two instances of Reel Turning and two instances of Roller Turning from the library.

Create a guide layer within the movie clip symbol and use the reference bitmap again to help with the position of each instance.

Sit the reels on a layer named "Reels", and sit the rollers on a layer named "Rollers".

Use the free-transform tool to slightly rotate both reels. Take a look at the angle of rotation of both reels in the reference bitmap.

Name the reel instances "reel_left" & "reel_right", and the roller instances "roller_left" & "roller_right".

Your Parts movie clip symbol should look like this (excluding the guide layer):



Step 12: Additional Details

While inside the Parts movie clip symbol, let's take the opportunity to add a few more bits and pieces that you'd find inside an audio cassette.

From the reference bitmap you can see that we'll need to create the felt that the tape will eventually run across, three pins, and two horizontal ridges near the rollers.

We'll ignore the actual tape for the time being and return to it in step 15.

Here is how your finished movie clip symbol should look:


For more detail, explore my final version of the Parts movie clip symbol. Open the Parts movie clip symbol within source/cassette-no-code.fla's library:



Step 13: Organise Your Library

As with step 6, we want to prevent our library from getting out of control. Building the Parts movie clip symbol has probably left you with quite a few new movie clips sitting in the library's root. Let's tidy it up.

Create a new folder and name it "PartsFolder". Now move your Parts movie clip symbol and any associated clips inside this new folder. Also place the movie clip symbols associated with the reels and rollers here too. Now rename the folder to "Parts".

Note: Flash will complain when you try to create a folder that shares the same name as a symbol on the same level. This is why we initially named our folder PartsFolder before eventually renaming it once the Parts movie clip symbol had been moved.

Move the clips that represent the pins, ridges and the felt into the library's Housing folder.

Your library should now be tidier and look something like this:



Step 14: Taking Shape

Time to get a feel for how our audio cassette is shaping up.

Move to the root timeline where you should find a single empty layer.

Create a new movie clip symbol and name it "Audio Cassette".

Within this clip create three layers and name them "Front", "Parts" and "Back". Front should be the top layer with Back being at the bottom.

Create a guide layer and place the reference bitmap on it. Centre the bitmap on the stage and lock the layer.


Drag the Back movie clip symbol from the library onto the Back layer. Use the guide layer to help position it.

Drag the Parts movie clip symbol onto the Parts layer. Position the instance to match the guide layer's reference bitmap.

Finally position the Front movie clip symbol onto the Front layer.

Move back to the root timeline and drag the Audio Cassette clip onto the stage. Name the instance "cassette".

Things should be starting to come together:



Step 15: The Tape

We're almost finished building the user interface. The final task is to create the tape that winds round the reels and across the rollers.

We'll create a separate movie clip symbol to represent the tape and place it inside our Parts clip. Here's what we'll be working towards in the next few steps:


And here's what the final tape movie clip symbol will look like on its own:


The tape clip is actually split into three separate parts. One for the tape wrapped round the left reel and roller. Another for the tape wrapped round the right reel and roller. And a horizontal line at the bottom connecting both sides.


Step 16: Left Reel's Tape

Let's start off by creating the tape wrapped around the left reel and roller.

Create a new movie clip symbol and name it "Tape Left". We'll need a guide layer with the reference bitmap again, so go ahead and create it. Also create two additional layers above it. Name the top-most layer "Tape" and the second layer "Slack".

The Tape layer will represent the tape that winds round the reel. The Slack layer will represent the tape that comes away from the reel and moves through the roller at the bottom left of the cassette.

Let's concentrate on the "Tape" layer first.

We're going to create a black circle to represent the tape that is wound round the reel. We'll use the Oval Primitive tool for this since the circle will need a hole punched through its centre.

First we need to drag some rulers onto the stage to help. If rulers aren't enabled then select from the drop down menu: View | Rulers. (Ctrl + Alt + Shift + R)

Drag two horizontal and two vertical rulers onto the stage. Position the rulers so that they surround and touch the edges of the left reel on the reference bitmap.


Now let's do the same with the outer edges of the reel's tape.


Effectively we've used the rulers to create an outer box and an inner box.

Select the Oval Primitive Tool from the Tools pane. You can select it by holding the left mouse button down over the Rectangle Tool and then selecting the Oval Primitive Tool from the popup panel that appears. Alternatively press Shift + O twice.


From the Properties Inspector select no-stroke color


and a fill color


of #000000.

Using the Oval Primitive Tool, draw a circle from the outer box's top-left corner to its bottom-right corner (Hold down the Shift key while doing this to constrain it to a circle rather than an oval). From the Properties panel, adjust the oval primitive's Inner radius until you have a hole that sits firmly within the inner box created by the rulers.


Insert a blank keyframe on frame 480 of the Tape layer by selecting: Insert | Timeline | Blank Keyframe from the drop-down menu.

Using only the inner box create another Oval Primitive. Set its Inner radius close to the maximum possible value, effectively creating a thin outline.


Effectively we've created the initial and final state of the tape on the left reel. To begin with all the tape is on the left reel. Come the end only a thin slither will remain.

The final step is to create a shape tween between the two keyframes. Select the first frame then from the drop-down menu select: Insert | Shape Tween. Scrub across the timeline to see the tape shrinking over the course of the 480 frames.


Step 17: The Slack

Staying inside the Tape Left movie clip symbol, lock the Tape layer and select the Slack layer's first frame.

Select the Line Tool (N) from the Tools pane and set its color


to #000000.

Using the reference layer as an aid, draw a straight line from underneath the bottom-left roller to the left edge of the reel's tape. You may want to initially use a more visible color


for your line (I opted for #ff0000) as shown here:


Move to frame 480 and create a keyframe by selecting: Modify | Timeline | Convert to Keyframe from the drop-down menu. This will create an exact copy of the line on frame 480.

Move back to frame 1.

Using the Selection Tool (V) bend the line until it sits over the slack in the reference bitmap. You'll need to bend it from several points on the line to get the curve just right.


Change the line's color


back to #000000.

Move to frame 480 again.

Using the Selection Tool (V) drag the top point until it touches the left-hand-side of the reel. I'd recommend you hide the guide layer when doing this.


Make the guide layer visible again, and bend the line until it is curving round the bottom left roller. Again you may need to bend the line from several points to get the curve just right.


Change the line's color back to #000000.

Hide the Reference guide layer.

Create a shape tween between the two keyframes. Right-click the first frame then from the menu select: Create Shape Tween.

Scrub across the timeline to preview the animation. Notice that over the course of the 480 frames the slack starts to drift away from the tape wrapped around the reel. This can be rectified by adding shape hints to the animation.

Move back to the start of the timeline. Select: Modify | Shape | Add Shape Hint (Ctrl + Shift + H) from the drop down menu.

A red circle with the letter 'a' will appear on stage.


Hide the Tape layer and simply move the circle to the top of the line on the Slack layer.


Move to frame 480 and once again move the red circle to the top end of the line on the Slack layer. This time the circle should change color


to green indicating that Flash has understood the hint.


If you move back to frame 1 you should see that the circle on that frame has changed color to yellow.

Scrubbing through the timeline should now give a much better result.

You can further refine the animation by key-framing points throughout the animation where you feel the slack is starting to drift and adding another shape hint.

Take a look at Tape Left within source/cassette-no-code.fla.


You can see that I've applied additional shape hints to the Slack layer at frames 89 and 222.


Step 18: Right Reel's Tape and Slack

The procedure is more-or-less identical for the right reel.

Create a new movie clip symbol and name it Tape Right. Create identical layers to those in the Tape Left movie clip symbol.

You can save some time by copying the start and end frames from the Tape layer in Tape Left and pasting them into the Tape Right movie clip symbol. Just remember to swap their positions. The first frame from Tape Left should be the end frame in Tape Right, and the end frame from Tape Left should be the first frame of Tape Right.

You can also copy and paste the slack lines. Again remember, the line on the first frame of Tape Left should be copied to the end frame in Tape Right, and the line on the end frame of Tape Left should be the first frame in Tape Right.

You will also need to flip both lines by selecting: Modify | Transform | Flip Horizontal from the drop-down menu.

Once you have constructed the shape tweens for both the Tape and Slack layers you should end-up with a movie clip symbol that looks like this on the first frame:


And this on the final frame:



Step 19: Connecting the Tape

Create a new movie clip symbol and name it Tape.

Add a guide layer and drag the reference bitmap onto it. Lock the layer.

Create an additional layer above it named "Tape". Drag an instance of Tape Left and Tape Right from the library onto the layer. Using the reference bitmap as an aid, position both instances. Label the instances "left" and "right" respectively.

Using the Line Tool (N) draw a horizontal line between both sections of tape. Select a color


and stroke thickness for the line that matches that of the tape slack within the Tape Left and Tape Right movie clip symbols.

Your Tape movie clip symbol should look like the following:


Steps 15 - 19 have covered a lot of ground. If you're finding them difficult then you may want to examine my version. Open source/cassette-no-code.fla and find the Tape clip within the library and open it.


Spend some time digging deeper into its movie clips. Pay particular attention to the tape winding animations.


Step 20: Revisiting the Parts Movie Clip Symbol

Now that we have the Tape movie clip symbol, let's add it inside the Parts movie clip symbol.

Find the Parts clip in your library and open it.

Create a layer named Tape.

Organise the layers to ensure that the Rollers layer sits above the Tape layer and the Reels layer sits below the Tape layer.


Drag an instance of the Tape movie clip symbol from the library into the Tape layer. The final version of the Parts movie clip symbol should resemble this:



Step 21: Organise Your Library

It's time once again to tidy the library.

Move any tape related clips that are sitting in the root of your library into the Tape folder.



Step 22: Interface Complete

The visuals are now complete.

Test your movie by selecting: Control | Test Movie | in Flash Professional (Ctrl + Enter) from the drop-down menu. (If you're using Flash CS3 or CS4 then select: Control | Test Movie)

You should see the cassette's wheels turning with the tape unwinding from the left reel and growing on the right.


Step 23: The Document Class

Time to write some ActionScript. We'll start by creating the document class and adding some code to initially cease the timeline animations that automatically start running when we test our movie.

So go ahead, create a new ActionScript 3 file and add the following to it:

Save the class in the same location as your FLA and name it Application.as.

Left-click on the stage (don't click on any movie clip instances sitting on the stage) and set the Document Class field within the Properties pane to: Application.

Our document class doesn't do anything terribly exciting at the moment. A member variable is declared that represents the cassette movie clip that sits on the stage. Inside the constructor we listen for the ADDED_TO_STAGE event, and when it is dispatched we stop the playhead from moving along the various movie clip timelines that represent the reels, rollers and tape.

Test your movie (Ctrl + Enter). You should see the audio cassette sitting motionless on stage.


Step 24: Sound Events

Let's concentrate now on the actual code required to stream an mp3.

If you look at the final SWF for this tutorial you will see that the user can play and pause the music by clicking on the cassette. Also, by letting the music stream for a short period of time it should become apparent that the tape winding animation is tied to the duration and the current point being played in the mp3.

It may seem logical to toggle the actual animations in response to a mouse click on the audio cassette. However the more sensible approach is to trigger these animations in response to events representing the playback of the audio.

In other words, we want the cassette's wheels and tape to animate when an event is dispatched indicating that music is now playing, and the animations to stop when an event is dispatched indicating that the music has now stopped.

Let's create a new ActionScript 3 class and declare these two events:

The class above simply creates two static constants that represent each event - PLAYING and STOPPED. In the next few steps we'll create a sound manager that actually creates and dispatches these events in response to music being streamed and stopped.

Save the class as SoundEvents.as within the same folder as your FLA.


Step 25: The Sound Manager

As discussed in step 24, it will be the sound manager that responds to the user clicking on the cassette movie clip instance.

If no music is currently playing when the user clicks then a request will be made to the sound manager to play the music. If however, music is already being played when the user clicks, a request will be made to stop the music.

Essentially the user's clicking will act as a toggle, playing and pausing the music.

From this we can start to build a class to represent the sound manager. Create a new ActionScript 3 class file and add the following code:

Save the class as SoundManager.as within the same folder as your FLA.

Our sound manager class has three methods and three properties that represent its public API.

There's a setup() method that takes a string representing the URL of the mp3 to be played. And for playback the class provides a play() and a pause() method.

It's also possible to query the sound manager to determine what state it's currently in via the paused, playing and stopped properties that we have defined.

The class internally tracks its own state via the private state member variable that was declared. Three private constants have been declared within the class that represent the states that the sound manager can be in: STOPPED, PAUSED, PLAYING.

The sound manager begins life in the STOPPED state. When a call is made to the play() method, the sound manager moves into the PLAYING state. A call to pause() will move the sound manager into the PAUSED state. When the mp3 is played to completion, the sound manager will move into the STOPPED state.

Since the sound managed needs to be able to dispatch the SoundEvent class' PLAYING and STOPPED events, we have extended from Flash's ActionScript 3 class library, the EventDispatcher class. Take a look at the play() and pause() methods. You will see the PLAYING and STOPPED events being dispatched.

For more detail regarding Flash's EventDispatcher class take a look at its page on the Adobe's ActionScript 3.0 Reference site.

Try not to confuse the sound manager's internal states with the sound events that it dispatches. The internal states (STOPPED, PLAYING and PAUSED) are private constants of the class and are used internally to track state. The events (PLAYING and STOPPED) on the other hand are publicly accessible static constants that reside within the SoundEvents class.

Also notice the @todo comments scattered throughout the class at the moment. This is to indicate pieces of functionality that we have still to add.


Step 26: Instantiating the Sound Manager

It's far from finished, but our sound manager class will compile and run. Let's prove this by creating an instance of the sound manager within our document class and making some calls to its public API.

Move inside the Application.as class and add a new member variable:

And add the following lines at the end of the addedToStage() method:

The code above traces out the state of the sound manager at four different stages - after it is instantiated; after a call has been made to play some music; after a call has been made to stop playing the music; and after a second call to play the music again.

Of course no music will actually play at the moment - we've still to write the code to do that - but internally the sound manager should at present move into the correct state depending on the call being made to it.

Publish and test your movie. Your trace statements will be sent to the Output pane and should look like this:

As you would expect, the results above show the sound manager initially in the STOPPED state. Once a call to play() is made the sound manager moves into the PLAYING state. The sound manager's pause() method is then called, moving it into its PAUSED state. Finally a second call is made to play(), moving the sound manager from its PAUSED state to the PLAYING state again.

Once satisfied that your initial stab at a sound manager is working as expected, delete the test code. Keep the line that declares the sound manager and the line that instantiates it but remove everything else. Your addedToStage() method should now look like this:


Step 27: Listening for the Sound Manager's Events

During step 25 we wrote the code to dispatch the sound events from the sound manager but haven't yet added any listeners. Let's go back into the document class and wire up some event listeners to the sound manager.

Add the following lines of code to the addedToStage() method:

Now write the following two event listener methods:

When the sound manager dispatched the PLAYING event, the document class' musicPlaying() method will get called. When the sound manager dispatches the STOPPED event the document class's musicStopped() method will get called.

At the moment both methods simply send a trace statement to the Output pane but later we'll write some code to start and stop the cassette's animations in response to these events.

Let's write some test code to verify that the event listeners do actually get called in response to the events dispatched by the sound manager. We'll make the same calls we made in step 26 when testing the sound manager's internal state. Simply add the following lines of code at the end of the addedToStage() method:

Publish and run the movie. You should see the following traces in response to each of the calls:

Remove the three lines of test code we just added.


Step 28: Playing Music

It's time to actually stream some music.

We'll take advantage of the following two classes from the ActionScript class library: Sound and SoundChannel.

The Sound class let's you load and play an external mp3 file. The SoundChannel class is used to control the music being played. We'll use it to determine the current point that is being played in the mp3, whether it has reached the end, and to pause it.

More detail regarding Flash's Sound and SoundChannel classes can be found on the Adobe's ActionScript 3.0 Reference site.

Move to your SoundManager class and add the following member variables:

The first two variables will point to instances of the Sound and SoundChannel classes that are required to play and control the music file. The third variable, pos, is used to store, in milliseconds, the mp3's current position. This variable is useful when the music is paused, allowing us to later resume playing the music from the exact same position.

Let's add some code to the setup() method to load the specified mp3 file:

The method is fairly trivial. A URL request is constructed from the music file's URL string, and is then used when instantiating a Sound object. The reference to the Sound object is stored in the snd member variable we declared earlier in this step.

Now we're ready to finish the code to our play() method by using our snd member variable and also obtaining and using a reference to a SoundChannel object.

The play() method needs to handle two situations. When the music is currently stopped and when the music is currently paused. Add the following code to your play() method:

The code is almost identical for both cases. The Sound class provides its own play() method that is used to start playing an opened mp3 file. Our code makes a call to the snd member variable's play() method, which starts playing the streaming mp3 file and returns a SoundChannel reference. We store a reference to the SoundChannel object in the sndChan member variable.

The SoundChannel object dispatched a SOUND_COMPLETE event when the mp3 file has finished played. We add an event listener to our sndChan instance to listen for this event.

Notice that the pos member variable is passed as an argument to the snd object's play() method. This forces the mp3 file to start playing a certain number of milliseconds into the music.

The only difference between the code in the two if-statements is that the pos member variable is reset to 0 if the sound manager was previously in its stopped state. This ensures that the music starts playing from the beginning of the mp3 file. If previously in its PAUSED state, we do not reset the pos member variable since we want the mp3 file to continue playing from where it left off.

Add a placeholder version of the soundFinishedPlaying() method that is called when the mp3 file has finished playing:

We've used a few classes from Flash's built-in class library. Add the following import statements next to the existing import statements within your SoundManager class:


Step 29: Testing the Sound Manager

Let's test the latest version of the sound manager.

First move to your document class and add a new constant that contains the URL of the mp3 file to play. We'll assume the mp3 file will sit in the same location as your SWF:

You can find the mp3 file at: source/any-other-way.mp3. Copy it to the same location as your FLA.

A huge thank you to Brown Eye Superfly for granting the use of their track Any Other Way.

Now within addedToStage() make a call to the sound manager's setup() method, passing it the URL of the mp3 file. Finally make a call to its play() method. Here are the changes:

Publish and test your movie. The mp3 file should start playing and the sound manager should dispatch the PLAYING event, resulting in the following trace statement being sent to the Output pane via the document class' musicPlaying() method:


Step 30: Pausing Music

Code is now in place to start playing an mp3, but the sound manager doesn't currently have the functionality to pause the music or handle the situation where the music has finished playing.

Let's start by adding the code to pause the music.

Move back to the SoundManager class and add the following lines to its pause() method:

The two new lines of code above store the current point that is being played in the mp3 file before stopping playback.

The AS3 API's SoundChannel class provides a position property that returns the current point that is being played in the sound file. We've used this property to obtain from the sndChan member variable the number of milliseconds into the mp3 file we are, and stored this in the pos member variable for use later by the sound manager's play() method.

Once the position is known and stored, a call is then made to stop the mp3 file from playing. This is done via the stop() method that is provided by the SoundChannel class.


Step 31: Playing to Completion

Now let's handle the situation where the mp3 file plays to completion.

In step 28 we added the soundFinishedPlaying() event listener that gets called when the mp3 file has finished playing.

Complete the method by adding the following to it:

The code above moves the sound manager into the STOPPED state and dispatches the STOPPED event to any methods that are listening for it.

Remember in step 27 from within our document class we added a listener to the sound manager for just this very event. Here's the code again as a reminder:

Essentially whenever the mp3 file plays to completion or a call is made to stop the sound manager playing the music, the document class' musicStopped() method will get executed in response.


Step 32: Adding User Interaction

Let's test our current version of the SoundManager class by adding some interaction.

We'll write some code in our document class to check for a mouse click on the cassette movie clip instance and toggle the playing and pausing of our mp3 file.

First, move to the addedToStage() method and remove the following line:

We will no longer immediately start playing the mp3 file. Instead we'll wait for the user to click on the audio cassette for the first time.

We'll be listening for a mouse event so add the following import statement at the beginning of the document class:

Add the following line at the end of the addedToStage() method to listen for the user clicking on the cassette movie clip:

Now write the cassetteClicked() method that will be called when the user clicks on the audio cassette:

The code within this method is fairly straightforward and acts as a simple on/off toggle for the music. If the sound manager is currently not playing any music then call its play() method. Otherwise call its pause() method to stop the currently playing music.


Step 33: Testing User Interaction

Publish and test your movie and try clicking on the audio cassette to toggle the music playback. You should notice that the trace statements within the document class' musicPlaying() and musicStopped() event handlers appear in the Output pane in response to the events being dispatched by the event manager.

Although these two methods don't actually do anything useful yet we'll rectify that in the next step where we'll start handling the animation of the audio cassette in response to sound manager events.


Step 34: Synchronizing Animation with Audio

We'll now write some code to start and stop the audio cassette animation in response to the sound manager's PLAYING and STOPPED events.

Let's however re-factor some of the code within our document class and move it to a more suitable location. After all, it probably makes more sense that we write a class that directly represents the audio cassette and have it handle the cassette's animation and user interactivity.

We'll link this new class to the actual Audio Cassette clip stored in our FLA's library allowing our class to directly represent the cassette movie clip instance sitting on the stage.

First, create a new ActionScript 3 class and name it AudioCassette.as.

Add the following code to the class:

The code within this class should look very familiar. The stopTape() method contains the ActionScript we originally added to the document class in step 23 to stop the audio cassette's animations from playing. The playTape() method is similar and provides a mechanism for starting the audio cassette's animations.

Both these methods are public allowing them to be called directly upon the cassette movie clip instance that sits on the stage.

The user interaction code from the document class has also been brought over to the AudioCassette class.

Since the cassetteClicked() method requires a reference to the sound manager, a sndMan private member variable has been declared to store the reference, and a setup() method has been written allowing the reference to be passed into the AudioCassette class.

Notice that the AudioCassette class extends MovieClip. Essentially the AudioCassette class is going to provide additional functionality and public API calls to all stage instances of the Audio Cassette clip that reside in your library.

We need to make the Flash IDE aware of our intentions though by linking the class to the clip.

To do this, find the Audio Cassette clip in your library. Right-click on it and select the Properties... menu option.


The Symbol Properties panel will appear. Select the Export for ActionScript checkbox. The Class field below it should become populated with the name of your class - AudioCassette. Click the OK button.


Step 35: Tidying the Document Class

Now go back to your document class and remove the code that has been moved into the AudioCassette class. The code to remove is highlighted below:


Step 36: Using the AudioCassette Class

Now let's make the relevant additions to the document class to setup and use the AudioCassette class. Note, that there is no need to instantiate the AudioCassette class. This is automatically performed by the Flash Player for any instances of the Audio Cassette clip that are sitting on the stage. In our case we have a single instance of the clip called cassette, which is being referenced within the document class via the cassette member variable.

The additions to be made to the document class are shown below in bold:

Notice the cassette member variable's type has been changed from MovieClip to AudioCassette to reflect the fact that we have a specialised class that now represents the Audio Cassette movie clip symbol.

The remaining changes aren't that difficult to follow.

Inside the addedToStage() method, we make a call to the cassette's setup() method, passing it a reference to the sound manager.

And inside musicPlaying() and musicStopped(), calls are made to force the audio cassette to start and stop its animations respectively.


Step 37: Testing the Tape Animation

Publish and test your movie.

It's very close to completion now. You can click the audio cassette to toggle the music, and animation should now take place when the music is playing.

In fact the only thing still not working fully is the tape winding animation. Let the music play through and you should see that the tape animation is not yet synchronised with the current playback position and length of the mp3 file.


Step 38: Synchronising the Tape with the Music

At the moment the tape animation simply plays through its timeline until completion, before looping back to the start.

What we actually want to do is determine what percentage of the mp3 file has been played and jump to the correct position within the timeline to reflect this.

The tape winding animation is 480 frames long. If, for example, 50% of the mp3 file has been played then we want to stop the timeline's playhead on frame 240.

We can determine what frame to jump to by using the following formula:

frame = ( position / length ) * total_frames

where

  • frame: is the frame on the timeline to move to.
  • position: is the current position within the mp3, measured in milliseconds.
  • length: is the length of the mp3, specified in milliseconds.
  • total_frames: is the total number of frames in the tape's timeline.

This formula exposes some shortcomings with our sound manager's public API. It currently does not expose any way of determining the length or current position of the mp3 file.

Let's address that now. Move to the SoundManager class and add the following two public getter methods:


Step 39: Updating the Tape Position

Now we can write some ActionScript to update the position of the tape to reflect the current point in the mp3 that is being played.

We'll create two new classes to handle this. Both classes will extend MovieClip. We'll link one class to the Tape Left movie clip symbol in our library, and the other class to the Tape Right movie clip symbol. Each class will have a private member variable that references the sound manager.

We'll start by writing a class for the Tape Left clip. Create an ActionScript 3 file and name it TapeLeft.as. Add the following outline code:

The class has a private member variable named sndMan, which gets sets to a reference of the sound manager from within the setup() method.

At present, code exists within the AudioCassette class' stopTape() and playTape() methods to stop and play the left tape's timeline animation. However, we will remove this code shortly since this will now be handled directly within our TapeLeft class.

You can see this partly in action within the addedToStage() method we added to the class above. The method stops the timeline's playhead on frame 1. The enterFrame() method, which we haven't finished yet will be responsible for monitoring the current position within the mp3 file and updating the timeline's playhead accordingly.

Let's go ahead and finish the enterFrame() method using the formula we discussed:

Find the Tape Left clip in your library. Right-click on it and select the Properties... menu option. From the Symbol Properties pane select the Export for ActionScript checkbox and ensure that the Class field gets populated with your class name - TapeLeft. Click the OK button.


Step 40: The Tape Right Clip

The code required for the Tape Right clip is identical so we can simply re-use the TapeLeft class.

Find the Tape Right movie clip symbol in your library. Right-click on it and select the Properties... menu option. Select the Export for ActionScript checkbox - the class field will automatically get set to TapeRight. However, we haven't actually created a TapeRight class. Instead tell the Flash IDE that you wish to use the TapeLeft class by placing its name in the Base Class field.


When you click OK the Flash IDE will display a panel with the following warning:


This is what we want, so click OK.


Step 41: Some Final Changes

Now all that's left is to make some changes to the AudioCassette class.

Remove the lines of code responsible for starting and stopping the tape animation. They're shown below in bold within the playTape() and stopTape() methods:

Now add the following lines of code to the setup() method:

The additional lines above simply make a call to the setup() method of each of the tape instances, passing them a reference to the sound manager. Remember the TapeLeft class, which both movie clip instances use, requires a reference to the sound manager in order to update the tape's timeline position.


Step 42: Code Complete

That's all the code required for this project.

Go ahead, publish and test your movie.

The audio cassette should animate whenever music is playing and the tape should be perfectly synchronized to the music's current position.


Conclusion

We've covered a lot of ground and taken advantage of both Flash's design tools and ActionScript 3 to bring to life a near photo-realistic retro audio cassette music player.

Hopefully this tutorial has taught you the benefits of utilizing both Flash's drawing tools and the ActionScript 3 programming language. Used together both can help reduce development times and produce incredible results.

While the visual and audio result is striking, what may impress you more is the final file size of your SWF. The SWF file format is incredibly compact. When the Flash IDE and its tools are used correctly it can lead to the publication of unbelievably small files.

Take our final SWF as an example. It's only 18K in size. To give you some perspective that's significantly smaller than the 97K file size of the original reference bitmap you used while working your way through this tutorial.

In other words, our fully interactive audio-streaming SWF, complete with animation, is about a fifth of the size of our static PNG image!

I hope you found this tutorial beneficial.

Thanks for reading!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.