Deprecated: Function set_magic_quotes_runtime() is deprecated in /home/ianguth/ianguthridge.com/wp-settings.php on line 18

Strict Standards: Declaration of Walker_Comment::start_lvl() should be compatible with Walker::start_lvl(&$output) in /home/ianguth/ianguthridge.com/wp-includes/comment-template.php on line 0

Strict Standards: Declaration of Walker_Comment::end_lvl() should be compatible with Walker::end_lvl(&$output) in /home/ianguth/ianguthridge.com/wp-includes/comment-template.php on line 0

Strict Standards: Declaration of Walker_Comment::start_el() should be compatible with Walker::start_el(&$output) in /home/ianguth/ianguthridge.com/wp-includes/comment-template.php on line 0

Strict Standards: Declaration of Walker_Comment::end_el() should be compatible with Walker::end_el(&$output) in /home/ianguth/ianguthridge.com/wp-includes/comment-template.php on line 0

Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method GoogleSitemapGeneratorLoader::Enable() should not be called statically in /home/ianguth/ianguthridge.com/wp-includes/plugin.php on line 339
Working with Sound in Flash | Ian Guthridge.com
Ian Guthridge.com

Working with Sound in Flash

Contents

  1. Intro
  2. Using the Microphone without Loopback
  3. Loading a Sound
  4. Getting Sound Data
  5. Conclusion
  6. Code Dump
  7. Helpful Links


Intro

Well, I have been having some fun making Flash games lately. Unfortunately, working with Action Script is a major pain. While Action Script 3 is a major improvement over Action Script 2, it still has quite a few frustrating elements, and in this section, I will give you some information that I hope will make your future Flash projects go smoother. All the code is reposted at the bottom without my comments dividing it up.

Using the Microphone without Loopback

I wanted to use the microphone as a control for a game I was making. Unfortunately, you aren't able to see raw sound data from the microphone, but you can see the 'activityLevel', which is similar to the volume of the incoming sound. Also, you have to attach the microphone to something for it to become active. In my case, since I didn't have a network session to attach it to, I had to allow loopback (the microphone input loops back to the speakers). Luckily, while activity level is similar to the volume of a microphone, activityLevel and volume are separate properties. Here is what the code to do that would look like:

Actionscript:
  1. Security.showSettings(SecurityPanel.MICROPHONE);

Here we ask the user if he wants to let Flash use his microphone, otherwise it will use his default security settings, which is usually 'Deny'.

Actionscript:
  1. var mic:Microphone = Microphone.getMicrophone();

Pretty straight forward, but we create out microphone here. They added this nifty little pop-up window that will let the user change some properties of the microphone.

Actionscript:
  1. mic.setLoopBack(true);

Now we set our microphone to loop back, more ore less attaching it to our movie, but with the obnoxious side effect of playing what we are saying!

Actionscript:
  1. mic.soundTransform = new SoundTransform(0,0); // SoundTransform(vol:Number = 1, panning:Number = 0)

Time for the fix. We set the microphone's SoundTransform to a new SoundTransform with the volume turned sown to zero.

Now that we have the microphone, how do we use it? You could add an event listener for activity level on the microphone, but I didn't have much luck with that. Instead I did this:

Actionscript:
  1. stage.addEventListener(Event.ENTER_FRAME, stage_EnterFrame);
  2. function stage_EnterFrame(e:Event):void
  3. {
  4.      if(mic.activityLevel> 20) // 0 <= activityLevel <= 100
  5.      {
  6.           //do something;
  7.      }
  8. }


Loading a Sound

There are plenty of resources that show you how to add a sound if it is in your library. Here I am going to show you how to stream a sound instead. It is relatively straightforward, so let's jump right in!

Actionscript:
  1. var sound:Sound = new Sound();
  2. var req:URLRequest = new URLRequest("myPath/mySound.mp3");

First we have to create our sound and a URLRequest. Now the request can be a relative link like the one above, or an absolute like, like "http://mysite.com/myPath/mySound.mp3".

Actionscript:
  1. var context:SoundLoaderContext = new SoundLoaderContext(8000, true); //buffer 8 seconds

Here we declare a new SoundLoaderContext, which lets us set our buffer time, and if we want to require a policy file to load the sound.

Actionscript:
  1. sound.load(req, context);

And then we load the sound.
Now that we have a sound, we could just play it with sound.play(), but if we want to loop it, we have to use a SoundChannel, because SoundChannel throws the SOUND_COMPLETE event. Here we just add an event listener, so I won't bug you with my comments (besides the ones in the code already).

Actionscript:
  1. channel = sound.play(0); //start song from the beginning
  2. channel.addEventListener(Event.SOUND_COMPLETE,restart);
  3. function restart(e:Event):void
  4. {
  5.     channel.removeEventListener(Event.SOUND_COMPLETE,restart); //remove the listener
  6.     channel = null; //ensure the old channel is gone
  7.     channel = sound.play(48000); //start the new sound from the repeat point(48 seconds)
  8.     channel.addEventListener(Event.SOUND_COMPLETE,restart); //add the event listener
  9. }


Getting Sound Data

Now for some fun stuff! Flash lets us see the raw sound data that we are playing, as long as the security sandbox says it is ok. You don't have to worry about the security sandbox if you are playing a sound embed ed in the movie, and it shouldn't be an issue if you are playing a sound stored on the same domain. If you are having trouble, than the other domain that has the sound you are trying to play lacks a valid cross-domain policy file. If you do have an accessible file, then you can use SoundMixer.computeSpectrum(outputArray:ByteArray, FFTMode:Boolean = false, stretchFactor:int = 0):void to get the waveform or spectrum for the current sound (256 data points per channel). If you want the waveform, have FFTMode set to false, and if you want the spectrum set it to true (low frequencies will be on the left half of the data, high frequencies on the right). The streatchFactor is resolution of the sound samples. If you set the stretchFactor value to 0, data is sampled at 44.1 KHz, with a value of 1 the data is sampled at 22.05 KHz, with a value of 2 the data is sampled 11.025 KHz, and so on.This next bit of code will show you how to do the circular waveform I did in the game Shout in the Games section.

Actionscript:
  1. var bytes:ByteArray = new ByteArray();
  2. var n:Number = 0;
  3. SoundMixer.computeSpectrum(bytes, false, 0);
  4. var len:int = 220;
  5. var channelLength:int = 256;
  6. var g:Graphics = stage.graphics;

Here I am grabbing the stage's Graphics object. Drawing happens behind everything, so this only works properly if there is nothing on the stage at this time. You can grab a graphics object from a MovieClip or sprite, so just set up an empty one of those if you want to draw on top of things.

Actionscript:
  1. g.clear();
  2. g.lineStyle(0, 0x0044FF); //Blue-green line
  3. for (var j:int = 0; j <channelLength+180; j++)
  4. {
  5.     n = ((bytes.readFloat()+.5) * len);
  6.     var angle:Number = Number.MIN_VALUE;
  7.     if(j<180)//left half of circle
  8.     {
  9.         angle = (j* Math.PI/180)+Math.PI/2;
  10.     }
  11.     else if( j> channelLength)//check if we have gotten to the right channel data yet
  12.     {
  13.         angle = ((j-channelLength)* Math.PI/180)+3*Math.PI/2; //convert the number to a usable radian value (remember to remove the offset of the channelLength!)
  14.     }
  15.     if(angle != Number.MIN_VALUE)
  16.     {
  17.         var dx:Number = Math.cos(angle) * n; //trig to find the x position of the next point
  18.         var dy:Number = Math.sin(angle) * n; //trig to find the y position
  19.         if(j == 0) g.moveTo(dx+270,dy+160); //magic numbers!!! Offset for drawing the "circle"
  20.         else g.lineTo(dx+270,dy+160);
  21.     }
  22. }

The rest is a loop that draws points along a 'circle'. I think the comments in the code are descriptive enough. (No I am not just being lazy. :P)

Conclusion

Thank you for reading! I hope you found at least some of this helpful. If you have any comments, critiques, or suggestions, don't be afraid to let me know.

Code Dump

Here is the code samples without my comments:

Getting the Microphone

Actionscript:
  1. Security.showSettings(SecurityPanel.MICROPHONE);
  2. var m:Microphone = Microphone.getMicrophone();
  3. m.setLoopBack(true);
  4. m.soundTransform = new SoundTransform(0,0);

Using activityLevel

Actionscript:
  1. stage.addEventListener(Event.ENTER_FRAME, stage_EnterFrame);
  2. function stage_EnterFrame(e:Event):void
  3. {
  4.     if(mic.activityLevel> 20) // 0 <= activityLevel <= 100
  5.     {
  6.         //do something;
  7.     }
  8. }

Loading and Looping a Sound

Actionscript:
  1. var sound:Sound = new Sound();
  2. var req:URLRequest = new URLRequest("myPath/mySound.mp3");
  3. var context:SoundLoaderContext = new SoundLoaderContext(8000, true); //buffer 8 seconds
  4. s.load(req, context);
  5. channel = sound.play(0); //start song from the beginning
  6. channel.addEventListener(Event.SOUND_COMPLETE,restart);
  7. function restart(e:Event):void
  8. {
  9.      channel.removeEventListener(Event.SOUND_COMPLETE,restart); //remove the listener
  10.      channel = null; //ensure the old channel is gone
  11.      channel = sound.play(48000); //start the new sound from the repeat point(48 seconds)
  12.      channel.addEventListener(Event.SOUND_COMPLETE,restart); //add the event listener
  13. }

Dancing Circle

Actionscript:
  1. var bytes:ByteArray = new ByteArray();
  2. var n:Number = 0;
  3. SoundMixer.computeSpectrum(bytes, false, 0);
  4. var len:int = 220;
  5. var channelLength:int = 256;
  6. var g:Graphics = stage.graphics;
  7. g.clear();
  8. g.lineStyle(0, 0x0044FF); //Blue-green line
  9. for (var j:int = 0; j <channelLength+180; j++)
  10. {
  11.     n = ((bytes.readFloat()+.5) * len);
  12.     var angle:Number = Number.MIN_VALUE;
  13.     if(j<180)//left half of circle
  14.     {
  15.         angle = (j* Math.PI/180)+Math.PI/2;
  16.     }
  17.     else if( j> channelLength)//check if we have gotten to the right channel data yet
  18.     {
  19.         angle = ((j-channelLength)* Math.PI/180)+3*Math.PI/2; //convert the number to a usable radian value (remember to remove the offset of the channelLength!)
  20.     }
  21.     if(angle != Number.MIN_VALUE)
  22.     {
  23.         var dx:Number = Math.cos(angle) * n; //trig to find the x position of the next point
  24.         var dy:Number = Math.sin(angle) * n; //trig to find the y position
  25.         if(j == 0) g.moveTo(dx+270,dy+160); //magic numbers!!! Offset for drawing the "circle"
  26.         else g.lineTo(dx+270,dy+160);
  27.     }
  28. }


Helpful Links

Adobe API pages

  1. Microphone
  2. Sound
  3. SoundLoaderContext
  4. SoundTransform
  5. SoundMixer
  6. SoundChannel
  7. Graphics

Other Great Resources

  1. Republic of Code
  2. Adobe Accessing Sound Data Example
  • Share/Bookmark

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!