1. Code
  2. Game Development

Render an MP3 Audio Spectrum in Flash With computeSpectrum()

In this tutorial, I'll teach you how to create a visual representation of a sound file's audio spectrum, using Flash's SoundMixer.computeSpectrum method. We'll use four classes for this effect: Sound, SoundChannel, SoundMixer, and ByteArray. I'll explain each classes as we use them.
Scroll to top
8 min read

In this tutorial, I'll teach you how to create a visual representation of a sound file's audio spectrum, using Flash's SoundMixer.computeSpectrum method. We'll use four classes for this effect: Sound, SoundChannel, SoundMixer, and ByteArray. I'll explain each classes as we use them.


Final Result Preview

Let's take a look at the final result we will be working towards:


Click to view the demo

Step 1: Set Up Your Flash File

Launch Flash Pro and create a new Flash Document. Set the stage size to 500x300px, the background color to #000000, and the frame rate to 24fps.

Setup Stage Setup Stage Setup Stage

In your timeline, select the existing layer and rename it "Buttons". Then click Window > Common Libraries > Buttons.

Select your favorite button set, then drag and drop the 'Play' and 'Stop' buttons to the bottom-right corner of the stage.

Library-Buttons

Set the instance names of these buttons to play_btn and stop_btn, respectively.

Step 2: Create the Document Class

Create a new AS file, and save it as Main.as. Add this code (read the comments for more details):

This code should be placed in our new Class:

1
2
package  {
3
	import flash.display.Sprite;
4
	import flash.media.Sound; //The Sound class is the first step in working with sound. It is used to load a sound, play a sound, and manage basic sound properties.

5
	import flash.net.URLRequest;
6
	
7
	public class Main extends Sprite {	
8
		private var sound:Sound; 
9
		public function Main() {
10
			sound = new Sound(new URLRequest("sound.mp3")); //assign music to the sound variable.

11
			sound.play(); //play assigned sound.

12
		}
13
	}
14
}

You'll need to put an MP3 file called sound.mp3 in the same directory as your FLA's output directory. Any MP3 will do; on is included in the tutorial's source download.


Step 3: Document Class

Add the class name to the Class field in the Publish section of the Properties panel to associate the FLA with the Main document class.

If you're not familiar with the concept of a document class,check out this Quick Tip before reading further.

Publish section

Then press Ctrl+Enter to test your Application.


Step 4: Handling the Sound Using Buttons

Let's add an instance of a new class: SoundChannel. This class is used to keep different sounds in separate audio channels; each channel is created by an instance of SoundChannel, and we use these instances to control the sounds.

1
2
package  {
3
	import flash.display.Sprite;
4
	import flash.media.Sound;
5
	import flash.media.SoundChannel;
6
	import flash.net.URLRequest;
7
	import flash.events.MouseEvent;
8
	public class Main extends Sprite {
9
		private var sound:Sound;
10
		private var channel:SoundChannel;
11
		
12
		public function Main() {
13
			sound = new Sound(new URLRequest("sound.mp3"));
14
			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
15
			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
16
		}
17
		
18
		private function onPlayHandler(event:MouseEvent):void{
19
			channel = sound.play();
20
		}
21
		
22
		private function onStopHandler(event:MouseEvent):void{
23
			channel.stop();
24
		}
25
	}
26
}

As you can see, when Play is clicked, we don't just play the MP3, we also assign it to a SoundChannel. We can then control the playback through this SoundChannel instance later - in this case, by making it stop.


Step 5: Create Simple Animation

Now let's create some simple animation for this sound, again using the SoundChannel class.

1
2
package  {
3
	import flash.display.Sprite;
4
	import flash.media.Sound;
5
	import flash.media.SoundChannel;
6
	import flash.net.URLRequest;
7
	import flash.events.MouseEvent;
8
	import flash.events.Event;
9
	
10
	public class Main extends Sprite {
11
		
12
		private var sound:Sound;
13
		private var channel:SoundChannel;
14
		
15
		public function Main() {
16
			sound = new Sound(new URLRequest("sound.mp3"));
17
			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
18
			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
19
		}
20
		
21
		private function onPlayHandler(event:MouseEvent):void{
22
			channel = sound.play();//assign sound to channel class 

23
			addEventListener(Event.ENTER_FRAME,animateBars); //render the animation every frame

24
		}
25
		
26
		private function onStopHandler(event:MouseEvent):void{
27
			channel.stop();
28
			graphics.clear();
29
			removeEventListener(Event.ENTER_FRAME,animateBars);//stop rendering the animation

30
		}
31
		
32
		private function animateBars(event:Event):void{
33
			
34
			graphics.clear();
35
			
36
			graphics.beginFill(0xAB300C,1);
37
			//Draw a rectangle whose height corresponds to channel.leftPeak

38
			graphics.drawRect(190,300,50,-channel.leftPeak * 160 );
39
			graphics.endFill();
40
			
41
			graphics.beginFill(0xAB300C,1);
42
			//Draw a rectangle whose height corresponds to channel.rightPeak

43
			graphics.drawRect(250,300,50,-channel.rightPeak  * 160 );
44
			graphics.endFill(); 
45
		}
46
	}
47
}

The leftPeak and rightPeak properties of a SoundChannel instance correspond to the current amplitude of the sound, through the left and right channels. Think of it this way: if you have stereo speakers, then leftPeak is the volume of the sound coming out of the left speaker, and rightPeak is the volume of the sound coming out of the right speaker.

You can press Ctrl+Enter to test your application:

Sound Bar AnimationSound Bar AnimationSound Bar Animation

Step 6: What Is SoundMixer?

The SoundMixer class controls all embedded and streaming sounds in the application, for all SoundChannels at once.

It has three methods: areSoundsInaccessible(), which determines whether any sounds are inaccessible due to security reasons; stopAll(), which stops playback of all sounds; and computeSpectrum(), which is what we're interested in for this tutorial. The latter method takes a "snapshot" of the current sound, and pushes it into a ByteArray object.


Step 7: What Is ByteArray?

The ByteArray class provides methods and properties to optimize reading, writing, and working with binary data. It stores data as an array of bytes, hence its name. Find out more with this Introduction to ByteArray.


Step 8: More Complex Animation

So now let's create a more complex animation using the SoundMixer.computeSpectrum() method. Again, read the comments in the code to fully understand the behavior:

1
2
package {
3
	import flash.display.Sprite;
4
	import flash.media.Sound;
5
	import flash.utils.ByteArray;
6
	import flash.events.Event;
7
	import flash.media.SoundMixer;
8
	import flash.filters.GlowFilter;
9
	import flash.net.URLRequest;
10
	import flash.events.MouseEvent;
11
	import flash.media.SoundChannel;
12
13
	public class Main extends Sprite{
14
		private var sound:Sound;
15
		private var channel:SoundChannel;
16
		private var byteArr:ByteArray = new ByteArray();
17
		private var glow:GlowFilter = new GlowFilter();
18
		private var filterArr:Array;
19
		private var line:Sprite = new Sprite();
20
21
		public function Main(){
22
			// create a "glow" effect for the animation we will render

23
			glow.color = 0x009900;
24
			glow.alpha = 1;
25
			glow.blurX = 10;
26
			glow.blurY = 10;
27
			
28
			// load your MP3 in to the Sound object

29
			sound = new Sound(new URLRequest("sound.mp3"));			
30
			// apply the glow effect

31
			filterArr = new Array(glow);
32
			line.filters = filterArr;
33
			addChild(line);
34
			
35
			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
36
			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
37
		}
38
		
39
		private function onPlayHandler(event:MouseEvent):void{
40
			channel = sound.play(0,1000);
41
			addEventListener(Event.ENTER_FRAME,spectrumHandler);
42
		}
43
		
44
		private function onStopHandler(event:MouseEvent):void{
45
			channel.stop();
46
			line.graphics.clear();
47
			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
48
		}
49
50
		private function spectrumHandler(event:Event):void{
51
			line.graphics.clear();
52
			line.graphics.lineStyle(1,Math.random() * 0xFFFFFF);
53
			line.graphics.moveTo(-1,150);
54
			// push the spectrum's bytes into the ByteArray

55
			SoundMixer.computeSpectrum(byteArr);
56
57
			for (var i:uint=0; i<256; i++){
58
				// read bytes and translate to a number between 0 and +300

59
				var num:Number = byteArr.readFloat() * 150 + 150;
60
				//use this number to draw a line

61
				line.graphics.lineTo(i*2,num);
62
			}
63
		}
64
	}
65
}

The most important parts of this code are lines 53 and 57. Here, the whole sound wave is translated to a ByteArray, which is then read, byte by byte, and translated into a set of numbers.

The ByteArray will be 512 floats long; in the for loop, we only read the first 256 floats, which correspond to the entire sound wave of the left channel (the sound coming through the left speaker).

Press Ctrl+Enter to test your Application.

Sound Line AnimationSound Line AnimationSound Line Animation

Step 9: Fill in the Gaps

We can fill in the area underneath the line to give us a different effect:

Complex Drawing AnimationComplex Drawing AnimationComplex Drawing Animation

All we need to do is draw a box and fill it in, using graphics methods. The code for this is as follows:

1
2
package {
3
	import flash.display.Sprite;
4
	import flash.media.Sound;
5
	import flash.utils.ByteArray;
6
	import flash.events.Event;
7
	import flash.media.SoundMixer;
8
	import flash.filters.GlowFilter;
9
	import flash.net.URLRequest;
10
	import flash.events.MouseEvent;
11
	import flash.media.SoundChannel;
12
13
	public class Main extends Sprite{
14
		private var sound:Sound;
15
		private var channel:SoundChannel;
16
		private var byteArr:ByteArray = new ByteArray();
17
		private var glow:GlowFilter = new GlowFilter();
18
		private var filterArr:Array;
19
		private var line:Sprite = new Sprite();
20
21
		public function Main(){
22
			glow.color = 0xFF0000;
23
			glow.alpha = 1;
24
			glow.blurX = 10;
25
			glow.blurY = 10;
26
			
27
			sound = new Sound(new URLRequest("sound.mp3"));
28
			
29
			filterArr = new Array(glow);
30
			line.filters = filterArr;
31
			addChild(line);
32
			addChild(play_btn);
33
			addChild(stop_btn);
34
			
35
			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
36
			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
37
		}
38
		
39
		private function onPlayHandler(event:MouseEvent):void{
40
			channel = sound.play(0,1000);
41
			addEventListener(Event.ENTER_FRAME,spectrumHandler);
42
		}
43
		
44
		private function onStopHandler(event:MouseEvent):void{
45
			channel.stop();
46
			line.graphics.clear();
47
			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
48
		}
49
50
		private function spectrumHandler(event:Event):void{
51
			// draw one edge of the box, and specify a fill

52
			line.graphics.clear();
53
			line.graphics.beginFill(0xFF0000,1);
54
			line.graphics.lineStyle(1,0xFF0000);
55
			line.graphics.moveTo(-1,150);
56
			SoundMixer.computeSpectrum(byteArr);
57
58
			for (var i:uint=0; i<256; i++){
59
				var num:Number = byteArr.readFloat() * 200 + 150;
60
				line.graphics.lineTo(i*2,num);
61
			}
62
63
			//draw the rest of the box

64
			line.graphics.lineTo(512,300);
65
			line.graphics.lineTo(0,300);
66
			line.graphics.lineTo(-1,150);
67
		}
68
	}
69
}

Step 10: Try Something Different

We can take this idea further, to add even more interesting and complex effects:

Complex Drawing AnimationComplex Drawing AnimationComplex Drawing Animation

In this case, we'll draw two spectra on top of each other, one for the left channel and one for the right. To achieve this, we'll use two for loops that each read in 256 floats, one after the other.

1
2
package {
3
	import flash.display.Sprite;
4
	import flash.media.Sound;
5
	import flash.utils.ByteArray;
6
	import flash.events.Event;
7
	import flash.media.SoundMixer;
8
	import flash.filters.GlowFilter;
9
	import flash.net.URLRequest;
10
	import flash.events.MouseEvent;
11
	import flash.media.SoundChannel;
12
13
	public class Main extends Sprite{
14
		private var sound:Sound;
15
		private var channel:SoundChannel;
16
		private var byteArr:ByteArray = new ByteArray();
17
		private var glow:GlowFilter = new GlowFilter();
18
		private var filterArr:Array;
19
		private var line:Sprite = new Sprite();
20
		private var num:Number;
21
		public const GRAFT_HEIGHT:int = 150; //set animation height

22
		public const CHANNEL_SIZE:int = 256; //set left/right channel size

23
24
		public function Main(){
25
			glow.color = 0x009900;
26
			glow.alpha = 1;
27
			glow.blurX = 10;
28
			glow.blurY = 10;
29
			
30
			sound = new Sound(new URLRequest("sound.mp3"));
31
			
32
			filterArr = new Array(glow); //add glow to the animation

33
			line.filters = filterArr;
34
			addChild(line);
35
			
36
			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
37
			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
38
		}
39
		
40
		private function onPlayHandler(event:MouseEvent):void{
41
			channel = sound.play(0,1000); // play sound 1000 times

42
			addEventListener(Event.ENTER_FRAME,spectrumHandler);
43
		}
44
		
45
		private function onStopHandler(event:MouseEvent):void{
46
			channel.stop();
47
			line.graphics.clear();
48
			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
49
		}
50
51
		private function spectrumHandler(event:Event):void{
52
			num = 0;
53
			
54
			line.graphics.clear(); // create current graphics

55
			line.graphics.lineStyle(0, 0x00FF00);
56
			line.graphics.beginFill(0x00FF00,0.5);
57
			line.graphics.moveTo(0,GRAFT_HEIGHT);
58
			
59
			SoundMixer.computeSpectrum(byteArr);// add bytes to Sound mixer

60
			
61
			for (var i:int = 0; i < CHANNEL_SIZE; i++) {
62
                		num = (byteArr.readFloat() * GRAFT_HEIGHT);
63
                		line.graphics.lineTo(i * 2, GRAFT_HEIGHT - num);
64
            		}
65
			
66
			line.graphics.lineTo(CHANNEL_SIZE * 2, GRAFT_HEIGHT);
67
			line.graphics.endFill();
68
			 
69
			line.graphics.lineStyle(0, 0xFF0000);
70
			line.graphics.beginFill(0xFF0000, 0.5);
71
			line.graphics.moveTo(CHANNEL_SIZE * 2,GRAFT_HEIGHT);
72
			 
73
			for (i = CHANNEL_SIZE; i > 0; i--) {
74
				num = (byteArr.readFloat() * GRAFT_HEIGHT);
75
				line.graphics.lineTo(i * 2, GRAFT_HEIGHT - num);
76
			}
77
			
78
			line.graphics.lineTo(0, GRAFT_HEIGHT);
79
			line.graphics.endFill();
80
		}
81
	}
82
}

Conclusion

So we have learnt how to use the various Sound classes, and how to create beautiful sound drawing animations using SoundMixer.

Thank you for taking the time to read this article, because this is my first tutorial. If you have any questions, please leave them in a comment.