Tired of those old-fashioned animated Christmas cards with Santa Claus laughing, a sleigh flying in the sky with a bunch of trees and sparkling lights?

This year you have no excuse. I'm going to show you how to build a virtual keyboard that plays Jingle Bells. You'll even be able to extend the concept and add more songs and notes to the piano.

For this tut I'll be using a combination of Tweenlite, the Flex SDK, the Flash IDE and Flash Develop.

Step 1: New File

Start Adobe Flash and create an ActionScript 3 Flash file.

Step 2: Properties

Open the properties and set the FPS to 30 and the stage size to 600 x 380px.

Step 3: Layer 1

Rename layer 1 as "background" and create a white rectangle of 580x360. Convert it to a movieclip symbol named "frame_mc" and set its position to x:10 y:10.

Step 4: Drop Shadow

Add a drop shadow filter with the following parameters:

Step 5: Keyboard Layer

Add a new layer called "keyboard", create a primitive rectangle 60x190 with a 5 pixel corner radius and with no stroke. Make it a movieclip symbol and call it "keybase_mc".

Step 6: Reflection and Glow Layers

Hit F8 and create a new movieclip called "key_mc". Create two more layers inside key_mc (besides the one already present with keybase_mc). Name them: "reflection" and "glow". Copy the frame to the newly created layers.

Step 7: glow_mc

NOTE: I've changed the frame_mc colors for a while to allow me to see the modifications on the keys. Select the movieclip in the glow layer, name it "glow_mc", open the filters and edit them according to the image below:

Step 8: reflection_mc

Select the movieclip in the reflection layer, name it "reflection_mc", open the filters and edit them to match the image below:

Step 9: base_mc

now select the movieclip in the base layer, name it "base_mc", open the filters and edit them to match the image below:

Step 10: Key

Copy and paste the key until you end up with 7 instances. Arrange them evenly across the stage.

Step 11: Align

Open the align tool and click the "horizontal spacing" icon.

Step 12: Notes

Create a new layer, call it "notes". Then write down C D E F G A B on the keys add the text to a new movieclip. Open the movieclip filters and edit them such as the image below:

Step 13: Numbers

Create a new layer, call it "numbers". Write the numbers from 1 to 7, this will represent the numbers that you will press on your keyboard to make the ecard key highlight.

Step 14: Flex SDK Path

Go to edit > preferences > ActionScript > ActionScript 3.0 settings and locate your Flex SDK path (you will need this to embed files directly through code).

Step 15: Flash Develop

Open Flash Develop (I'm just using this cause I like it so much more than the usual ActionScript editor from the flash IDE when writing packages) and create 2 blank as3 files. Name them "Main.as" and "Background.as", save them in the same folder as your .fla.

Step 16: Document Class

Inside Flash IDE set Main.as as your Document class.

Step 17: Autoplay Button

Create an autoplay movieClip and name it "autoplay_mc". This will be an autoplay button.

Step 18: Snowflakes

To create some snow flakes falling create a new movieclip, draw a smalll white circle inside and add a linkage identifier of "SnowFlake".

Step 19: Main.as

In Flash Develop open Main.as, define your Main class extending a movieclip and create a function called Main.

Start by importing these Classes inside your package:

import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.display.StageScaleMode;
	import flash.events.KeyboardEvent;
	import flash.utils.Timer;
	import com.greensock.TweenLite;
	import com.greensock.easing.*;
	import Background; //we will create a background class based on perlin noise and a transform matrix along with a few filled shapes so we can have a nice smooth transition
	import Snow; //i just grabbed kirupas snow and packaged it -> http://troyworks.com/blog/2008/11/26/flash-kirupa-snow-in-as30/
	import flash.media.Sound;

Step 20: Variables

Inside your class define these variables:

//this will be our background
		private var _background:Background;
		
		//this will be our snow storm
		private var snow:Snow;
		
		//->notes
		//Embeding this way requires FLEX SDK -> alternative method is to add these sounds to your library and add a linkage ID to them.
		[Embed(source="assets/A.mp3")]
		private var A:Class;
		private var a:Sound = new A() as Sound;
		
		[Embed(source="assets/B.mp3")]
		private var B:Class;
		private var b:Sound = new B() as Sound;
		
		[Embed(source="assets/C.mp3")]
		private var C:Class;
		private var c:Sound = new C() as Sound;
		
		[Embed(source="assets/D.mp3")]
		private var D:Class;
		private var d:Sound = new D() as Sound;
		
		[Embed(source = "assets/E.mp3")]
		private var E:Class;
		private var e:Sound = new E() as Sound;
		
		[Embed(source="assets/F.mp3")]
		private var F:Class;
		private var f:Sound = new F() as Sound;
		
		[Embed(source="assets/G.mp3")]
		private var G:Class;
		private var g:Sound = new G() as Sound;
		
		
		//Storing the notes in an array will make it easier to link to the keyboard
		private var notes:Array = [c,d,e,f,g,a,b]
		
		//Note sequence for the music								 
		private var noteSequence:Array = [f, f, f,
										f, f, f,
										f, a, d, e, f,
										g, g, g,
										g, g, e, e,
										d, b, a, f, d, c]
		//Current note that is playing
		private var curnote:Number = 0
			
		//Sequence of delay that the music needs to have between the notes
		private var noteDelay:Array = [100, 100 , 300,
									100, 100 ,300,
									100, 100, 100,100,200,
									100, 100, 200,
									90, 100, 90,100,
									100, 120, 120, 120, 120, 300]
									
		//Timer to play the music
		private var tunetimer:Timer = new Timer(noteDelay[0]);

Step 21: Main()

The Main function

//Main function waits for the the maintimeline to be added to stage
		public function Main():void{
			addEventListener(Event.ADDED_TO_STAGE, addedToStage);
		}

Step 22: Initialize

After being added to stage we'll initialize the background and the virtual keyboard:

//when added to stage we can set a stage scale mode, the background and the start the virtual piano
		private function addedToStage(e:Event):void {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			addBackground();
			startMachine();
		}

Step 23: Background Effects

Let's sort out the moving background and the Snow:

//adds the background
		private function addBackground():void {
			
			_background = new Background(150,150); //the reason the size is smaller is because it's very CPU intensive
			_background.x = 5; //to give a white margin for the frame
			_background.y = 5;
			_background.width = 570 //scale it up to the size right size
			_background.height = 350
			frame_mc.addChild(_background); //adds background to the frame
		
			snow = new Snow(570, 350)	//creates a snow storm instance

Step 24: Virtual Keyboard

The initialization of the virtual keyboard

private function startMachine(e:MouseEvent = null):void {
			
			//associates the keyboard events
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown)
			stage.addEventListener(KeyboardEvent.KEY_UP, onkeyUp)
			
			//associates an autoplay method to the autoplay button 
			autoplay_mc.addEventListener(MouseEvent.CLICK, startAutoPlay);
			autoplay_mc.buttonMode = true;
			
			//associates the notes to the keys
			var i:int = 0
			while (i < 7) {
				this["key"+i].note = notes[i]
				i++
			}
			//makes the highlight of the keys disappear
			lowlightKeys();
		}

Step 25: Highlight

We need to create a function to remove the highlight from the keys:

private function lowlightKeys() {
			var i:int = 0
			while (i < 7) {
				TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:0} );
				i++
			}
		}

Step 26: Key Events

Let's now handle the Key up and Key down events:

private function onkeyDown(e:KeyboardEvent):void {
			var i:int=0
			switch(e.keyCode) {
				case 49: //keycode for 1
					i=0
				break;
				case 50: //keycode for 2
					i=1
				break;
				case 51: //keycode for 3
					i=2
				break;
				case 52: //keycode for 4
					i=3
				break;
				case 53: //keycode for 5
					i=4
				break;
				case 54: //keycode for 6
					i=5
				break;
				case 55: //keycode for 7
					i=6
				break;
			}
			notes[i].play();
			TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:1} ); //highlights the key
		}
		
		private function onkeyUp(e:KeyboardEvent):void {
			var i:int=0
			switch(e.keyCode) {
				case 49:
					i=0
				break;
				case 50:
					i=1
				break;
				case 51:
					i=2
				break;
				case 52:
					i=3
				break;
				case 53:
					i=4
				break;
				case 54:
					i=5
				break;
				case 55:
					i=6
				break;
			}
			TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:0} ); //lowlights the key
		}

Step 27: Autoplay Functions

How to start and stop the autoplay

private function startAutoPlay(e:MouseEvent = null) {
			curnote = 0; //everytime i start autoplay i reset the current playing note
			tunetimer.delay = noteDelay[curnote] * 3 //this increases the delay set previously
			tunetimer.addEventListener(TimerEvent.TIMER, autoPlayTune) //adds a listener to the timer event for everytime the timer is triggered
			tunetimer.start() //starts the timer
		}
private function stopAutoPlay(e:MouseEvent = null) {
			tunetimer.stop() //stops timer
			tunetimer.removeEventListener(TimerEvent.TIMER, autoPlayTune) //removes the event
		}

Step 28: Update

Updating the virtual keyboard along with the music

private function updateMachine():void {
			lowlightKeys(); // resets the keys highlights
			var i:int = 0
			while (i < 7) {
				if (this["key" + i].note == noteSequence[curnote]) {
					TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:1} ); //if current note is the one associeated with the key then highlights it
				}
				i++
			}
			curnote++ //goes to next note
			if (curnote > noteSequence.length) {
				curnote = 0; //resets current note
				stopAutoPlay(); //stops autoplay
			}
		}

Step 29: The Complete Code

Here's the full Main.as code

package{
	
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.display.StageScaleMode;
	import flash.events.KeyboardEvent;
	import flash.utils.Timer;
	import com.greensock.TweenLite;
	import com.greensock.easing.*;
	import Background;
	import Snow
	import flash.media.Sound;
	
	public class Main extends MovieClip{

		private var _background:Background;
		
		private var snow:Snow;
		
		[Embed(source="assets/A.mp3")]
		private var A:Class;
		private var a:Sound = new A() as Sound;
		
		[Embed(source="assets/B.mp3")]
		private var B:Class;
		private var b:Sound = new B() as Sound;
		
		[Embed(source="assets/C.mp3")]
		private var C:Class;
		private var c:Sound = new C() as Sound;
		
		[Embed(source="assets/D.mp3")]
		private var D:Class;
		private var d:Sound = new D() as Sound;
		
		[Embed(source = "assets/E.mp3")]
		private var E:Class;
		private var e:Sound = new E() as Sound;
		
		[Embed(source="assets/F.mp3")]
		private var F:Class;
		private var f:Sound = new F() as Sound;
		
		[Embed(source="assets/G.mp3")]
		private var G:Class;
		private var g:Sound = new G() as Sound;
		
		private var notes:Array = [c,d,e,f,g,a,b]
									 
		private var noteSequence:Array = [f, f, f,
						  f, f, f,
						  f, a, d, e, f,
						  g, g, g,
						  g, g, e, e,
						  d, b, a, f, d, c]
		private var curnote:Number = 0
			
		private var noteDelay:Array = [100, 100 , 300,
					       100, 100 ,300,
					       100, 100, 100,100,200,
					       100, 100, 200,
					       90, 100, 90,100,
					       100, 120, 120, 120, 120, 300]
									
		private var tunetimer:Timer = new Timer(noteDelay[0]);
		
		public function Main():void{
			addEventListener(Event.ADDED_TO_STAGE, addedToStage);
		}
		
		private function addedToStage(e:Event):void {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			addBackground();
			startMachine();
		}
		
		//adds the background
		private function addBackground():void {
			
			_background = new Background(150,150);
			_background.x = 5;
			_background.y = 5;
			_background.width = 570 
			_background.height = 350
			frame_mc.addChild(_background);
		
			snow = new Snow(570, 350);
			frame_mc.addChild(snow);
		}
		
		
		private function startMachine(e:MouseEvent = null):void {
			

			stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown)
			stage.addEventListener(KeyboardEvent.KEY_UP, onkeyUp)
			
			autoplay_mc.addEventListener(MouseEvent.CLICK, startAutoPlay);
			autoplay_mc.buttonMode = true;
			
			var i:int = 0
			while (i < 7) {
				this["key"+i].note = notes[i]
				i++
			}
			lowlightKeys();
		}
		
		private function lowlightKeys() {
			var i:int = 0
			while (i < 7) {
				TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:0} );
				i++
			}
		}
		
		private function onkeyDown(e:KeyboardEvent):void {
			var i:int=0
			switch(e.keyCode) {
				case 49: 
					i=0
				break;
				case 50: 
					i=1
				break;
				case 51: 
					i=2
				break;
				case 52: 
					i=3
				break;
				case 53: 
					i=4
				break;
				case 54: 
					i=5
				break;
				case 55: 
					i=6
				break;
			}
			notes[i].play();
			TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:1} );
		}
		
		private function onkeyUp(e:KeyboardEvent):void {
			var i:int=0
			switch(e.keyCode) {
				case 49:
					i=0
				break;
				case 50:
					i=1
				break;
				case 51:
					i=2
				break;
				case 52:
					i=3
				break;
				case 53:
					i=4
				break;
				case 54:
					i=5
				break;
				case 55:
					i=6
				break;
			}
			TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:0} );
		}
		
		
		//AUTO PLAY FUNCTIONS
	    private function startAutoPlay(e:MouseEvent = null) {
			curnote = 0;
			tunetimer.delay = noteDelay[curnote] * 3 
			tunetimer.addEventListener(TimerEvent.TIMER, autoPlayTune)
			tunetimer.start()
		}
		
		private function stopAutoPlay(e:MouseEvent = null) {
			tunetimer.stop()
			tunetimer.removeEventListener(TimerEvent.TIMER, autoPlayTune)
		}
		
		private function autoPlayTune(e:TimerEvent) {
			if(curnote<noteSequence.length){
				noteSequence[curnote].play(); //plays the note
				tunetimer.delay = noteDelay[curnote] * 3
			}
			updateMachine()
		}
		
		private function updateMachine():void {
			lowlightKeys();
			var i:int = 0
			while (i < 7) {
				if (this["key" + i].note == noteSequence[curnote]) {
					TweenLite.to(this["key" + i].glow_mc, 0.5,{alpha:1} );
				}
				i++
			}
			curnote++ 
			if (curnote > noteSequence.length) {
				curnote = 0; 
				stopAutoPlay();
			}
		}
	}
	
}

Step 30: Background Class

Now on to the background class. We'll begin by importing these classes..

import flash.display.Shape;
	import flash.events.Event;
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Bitmap;
	import flash.display.BitmapData;  
	import flash.display.BlendMode;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.geom.Point;
    import flash.geom.Matrix;
   	import flash.filters.ColorMatrixFilter;
	import flash.display.GradientType;
   	import flash.display.Graphics;
   	import flash.display.InterpolationMethod;
	import flash.display.SpreadMethod;

Step 31: Variables

..then defining the variables:

//Noise
		private var dir:Array
		private var point:Point
		private var bd:BitmapData;
		private var bmp:Bitmap;
		private var bdmultiply:BitmapData;
		private var bms:Sprite;
		private var rect:Rectangle
		private var cmf:ColorMatrixFilter;
		private var w:Number
		private var h:Number
		
		//Linear Gradient Fill
		private var gshape:Shape
        private var gmetrics:Rectangle
        private var gmatrix:Matrix
		private var gtype:String
		private var gspread:String
		private var ginterpolation:String
		private var gcolours:Array
		private var galphas:Array
		private var gratios:Array
		
		//Solid Fill
		private var sshape:Shape

Step 32: Initial Function

Here's the initial function:

public function Background($width:Number=100, $height:Number=100)
		{
			w = $width
			h = $height
			rect = new Rectangle(0, 0, w, h);
			point = new Point(0, 0);
			dir = [new Point(1, 262), new Point(400, 262)];
			
			//this one is just to give a solid background to the whole stage
			initBackgroundSolid();
			
			//this will control the bightness contrast and saturation of the noise
			initColorMatrix();
			
			//there will be two noise backgrounds this will initiate them
			initBackgroundNoise();
			
			//a gradient is added so we dont get noisiated.. (get it? too much noise gets you noisiated? haha...hmmm)
			initBackgroundGradient();
		}

Step 33: initColorMatrix()

This function will control the bightness contrast and saturation of the noise, it's a very powerfull filter.

private function initColorMatrix():void {
		cmf = new ColorMatrixFilter([2, 0, 0, 0, -20, //red
									 0, 2, 0, 0, -20, //green
									 0, 0, 2, 0, -20, //blue
									 0, 0, 0, 1, -20 ]); //alpha
		}

Step 34: Solid Background Color

This one is just to give a solid background to the whole stage.

private function initBackgroundSolid():void {
			sshape = new Shape();
			sshape.graphics.beginFill(0x170a02,1)
			sshape.graphics.drawRect( 0, 0, w, h );
			sshape.graphics.endFill();
			addChild(sshape)
		}

Step 35: Noises

The noises:

private function initBackgroundNoise():void {
		//first noise
		bd = new BitmapData(w, h, false, 0 );
		bmp = new Bitmap(bd);
		bmp.smoothing = true;
		addChild(bmp);
		
		//second noise that overlaps the first noise through an overlay blend mode
		bdmultiply = new BitmapData(w, h, false, 0 );
		bms = new Sprite();
		bms.addChild(new Bitmap(bdmultiply))
		addChild(bms)
		bms.blendMode = "overlay";
		
		//renders the background so that the noise seems to be moving
		addEventListener(Event.ENTER_FRAME, renderBG);
	}

Step 36: Mask

Here's the gradient mask:

private function initBackgroundGradient() {
			
			//this is a basic gradient box with alpha and rotated 90ยบ so that it starts from top-bottom instead of left-right
			gshape = new Shape();
			gmetrics = new Rectangle();
			gmatrix = new Matrix();
			
			gtype = GradientType.LINEAR;
			gspread = SpreadMethod.PAD;
			ginterpolation = InterpolationMethod.LINEAR_RGB;
			
			gcolours = [ 0x170a02, 0x170a02 ];
			galphas = [ 0, 1 ];
			gratios = [ 0, 255 ];
			
			gmatrix.createGradientBox(w, h,(Math.PI/180)*90 );
			
			gshape.graphics.clear();
			gshape.graphics.beginGradientFill(gtype, gcolours, galphas, gratios, gmatrix, gspread, ginterpolation );
			
			gshape.graphics.drawRect( 0, 0, w, h );
			gshape.graphics.endFill();
			addChild(gshape)
	}

Step 37: Render

It's render time!

private function renderBG(event:Event):void {
		//updates noise direction
		dir[0].x-= 1.5
		dir[0].y-= 0 //these are here for you to play with
		dir[1].x-= 0 //these are here for you to play with
		dir[1].y -= 0 //these are here for you to play with
		
		//defines the first background bitmap to have a perlin noise
		bd.perlinNoise(w, h, 2, 10, false, true, 7, true, dir);
		//coloring time (play with these values)
		bd.colorTransform(rect, new ColorTransform(1, 0.7, 0.5));
		//aplies the brigthness contrast and saturation modifications made earlier
		bd.applyFilter(bd, rect, point, cmf)
		
		//the other perlin noise
		bdmultiply.perlinNoise(w, h, 3, 21, false, true, 7, true, dir)
		//the other perlin noise collors
		bdmultiply.colorTransform(rect, new ColorTransform(1, 0.6, 0.4));
	}

Step 38: Complete Background Class

Here's the whole background Class:

package
{
	import flash.display.Shape;
	import flash.events.Event;
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Bitmap;
	import flash.display.BitmapData;  
	import flash.display.BlendMode;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.geom.Point;
   	import flash.geom.Matrix;
    	import flash.filters.ColorMatrixFilter;
	import flash.display.GradientType;
    	import flash.display.Graphics;
   	import flash.display.InterpolationMethod;
	import flash.display.SpreadMethod;

	public class Background extends MovieClip
	{
		private var dir:Array
		private var point:Point
		private var bd:BitmapData;
		private var bmp:Bitmap;
		private var bdmultiply:BitmapData;
		private var bms:Sprite;
		private var rect:Rectangle
		private var cmf:ColorMatrixFilter;
		private var w:Number
		private var h:Number
		
		private var gshape:Shape
        	private var gmetrics:Rectangle
       		private var gmatrix:Matrix
		private var gtype:String
		private var gspread:String
		private var ginterpolation:String
		private var gcolours:Array
		private var galphas:Array
		private var gratios:Array

		private var sshape:Shape
		
		public function Background($width:Number=100, $height:Number=100)
		{
			w = $width
			h = $height
			rect = new Rectangle(0, 0, w, h);
			point = new Point(0, 0);
			dir = [new Point(1, 262), new Point(400, 262)];
			
			initBackgroundSolid();
			initColorMatrix();
			initBackgroundNoise();
			initBackgroundGradient();
		}
		
		private function initColorMatrix():void {
			cmf = new ColorMatrixFilter([2, 0, 0, 0, -20, //red
						     0, 2, 0, 0, -20, //green
						     0, 0, 2, 0, -20, //blue
						     0, 0, 0, 1, -20 ]); //alpha
		}
		
		private function initBackgroundSolid():void {
			sshape = new Shape();
			sshape.graphics.beginFill(0x170a02,1)
			sshape.graphics.drawRect( 0, 0, w, h );
			sshape.graphics.endFill();
			addChild(sshape)
		}
		
		private function initBackgroundNoise():void {
			bd = new BitmapData(w, h, false, 0 );
          		bmp = new Bitmap(bd);
			bmp.smoothing = true;
			addChild(bmp);
			
			bdmultiply = new BitmapData(w, h, false, 0 );
			bms = new Sprite();
			bms.addChild(new Bitmap(bdmultiply))
			addChild(bms)
			bms.blendMode = "overlay";
			
			addEventListener(Event.ENTER_FRAME, renderBG);
		}
		
		private function initBackgroundGradient() {
			
			gshape = new Shape();
			gmetrics = new Rectangle();
			gmatrix = new Matrix();
			
			gtype = GradientType.LINEAR;
			gspread = SpreadMethod.PAD;
			ginterpolation = InterpolationMethod.LINEAR_RGB;
			
			gcolours = [ 0x170a02, 0x170a02 ];
			galphas = [ 0, 1 ];
			gratios = [ 0, 255 ];
			
			gmatrix.createGradientBox(w, h,(Math.PI/180)*90 );
			
			gshape.graphics.clear();
			gshape.graphics.beginGradientFill(gtype, gcolours, galphas, gratios, gmatrix, gspread, ginterpolation );
			
			gshape.graphics.drawRect( 0, 0, w, h );
			gshape.graphics.endFill();
			addChild(gshape)
		}
		
		private function renderBG(event:Event):void {
			dir[0].x-= 1.5
			dir[0].y-= 0 
			dir[1].x-= 0
			dir[1].y -= 0

			bd.perlinNoise(w, h, 2, 10, false, true, 7, true, dir);
			bd.colorTransform(rect, new ColorTransform(1, 0.7, 0.5));
			bd.applyFilter(bd, rect, point, cmf)

			bdmultiply.perlinNoise(w, h, 3, 21, false, true, 7, true, dir)
			bdmultiply.colorTransform(rect, new ColorTransform(1, 0.6, 0.4));
		}
		
 	}
 }

Step 39: Snow

The snow class is not mine, it was written by Troy Gardner, I just adapted it from the timeline to a package this is why I'm not commenting on the code. Create a "Snow.as" and copy this code inside.

package 
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.utils.Dictionary;
	

	public class Snow extends MovieClip
	{
		var snowflakes:Array = new Array();
		var snowflakeProps:Dictionary= new Dictionary(true);
		var max_snowsize:Number = .04;
		// pixels
		var snowflakesCnt:Number = 150;
		var oheight:Number;
		var owidth:Number;
		
		public function Snow($width,$height):void {

			owidth = $width;
			oheight = $height;
			// quantity
			for (var i:int=0; i<snowflakesCnt; i++) {

				var t:MovieClip = new SnowFlake();//
				t.name = "snowflake"+i;

				t.alpha = 20+Math.random()*60;
				t.x = -(owidth/2)+Math.random()*(1.5*owidth);
				t.y = -(oheight/2)+Math.random()*(1.5*oheight);
				t.scaleX = t.scaleY=.5+Math.random()*(max_snowsize*10);
				var o:Object = new Object();
				o.k = 1+Math.random()*2;
				o.wind = -1.5+Math.random()*(1.4*3);

				snowflakeProps[t] = o;

				addChild(t);
				snowflakes.push(t);
			}
			addEventListener(Event.ENTER_FRAME,snowFlakeMover)
		}
		private function shakeUp():void{
			for (var i:int=0; i<snowflakes.length; i++) {
				var t:MovieClip = snowflakes[i] as MovieClip;
				t.x = -(owidth/2)+Math.random()*(1.5*owidth);
				t.y = -(oheight/2)+Math.random()*(1.5*oheight);
			}
		}
		private function snowFlakeMover(evt:Event):void {
			var dO:MovieClip;
			var o :Object;
			if(visible && parent.visible){
			for (var i:int = 0; i < snowflakes.length; i++) {
				dO = snowflakes[i] as MovieClip;
				o = snowflakeProps[dO];
				dO.y += o.k;
				dO.x += o.wind;
				if (dO.y>oheight+10) {

					dO.y = -20;

				}
				if (dO.x>owidth+20) {

					dO.x = -(owidth/2)+Math.random()*(1.5*owidth);
					dO.y = -20;

				} else if (dO.x<-20) {

					dO.x= -(owidth/2)+Math.random()*(1.5*owidth);
					dO.y = -20;
				}

			}
			}
		}
	}
	
}

Conclusion

My music skills aren't the greatest, the music may sound a bit strange. Oh well, with this tutorial you should now be able to create your own songs with more notes and different tones :). I hope you liked this tutorial, you'll find the commented code and both cs4 and cs3 versions up on the zip file. Thanks for reading!