[snippit] – generating a faux waveform in AS3
Tuesday, December 8th, 2009Working on a Flash project. I had to use the microphone to record some audio and generate a simple waveform so the user has some feedback that they are being heard. While not a true waveform, you can use the microphone activity level to generate something that works pretty well.
Here is the code to generate the above sample:
import com.wirelust.waveform.Waveform; import flash.media.Microphone; private var wave:Waveform = new Waveform(); private var mic:Microphone; private function init():void { wave.height = 50; wave.width = 450; wave.y = this.height/2 - wave.height/2; wave.x = this.width/2 - wave.width/2; this.addChild(wave); mic = Microphone.getMicrophone(); mic.setUseEchoSuppression(false); // loopback is required so we can get the activity level and create the waveform. - so stupid mic.setLoopBack(true); // turn off the volume for the loopback var mySoundTransform:SoundTransform = new SoundTransform(); mySoundTransform.volume = 0; mic.soundTransform = mySoundTransform; this.addEventListener(Event.ENTER_FRAME, onFrameEnter); } private function onFrameEnter(event:Event):void { if (mic != null && !mic.muted) { wave.add(mic.activityLevel); wave.invalidateDisplayList(); } }
And for the Waform class:
import flash.display.*; import flash.events.*; import flash.geom.Matrix; import mx.core.*; import mx.graphics.IFill; import mx.graphics.IStroke; import mx.graphics.SolidColor; import mx.graphics.Stroke; public class Waveform extends UIComponent { private var levels:Array = new Array(); public var color:uint = 0x000000; public var borderColor:uint = 0xCCCCCC; public var borderWidth:uint = 1; public var autoScale:Boolean = true; public function Waveform() { } public function add(level:Number):void { // trim the levels so we don't keep eating up memory while(levels.length > this.width) { levels.shift(); } levels.push(level); } override protected function updateDisplayList(param1:Number, param2:Number) : void { var scaleFactor:Number = 1; // autoscale will find the highest volume and scale all lines in the display accordingly. if (autoScale) { var highestLevel:Number = 0; for (var i:uint=0; i<levels.length; i++) { if (levels[i] > highestLevel) { highestLevel = levels[i]; } } scaleFactor = height/2/highestLevel; } super.updateDisplayList(param1, param2); graphics.clear(); graphics.lineStyle(1, color, 1, true, LineScaleMode.NORMAL); var lineX:uint = 0; for (var j:uint=0; j<levels.length; j++) { graphics.moveTo(lineX, this.height/2 - (levels[j] * scaleFactor)); graphics.lineTo(lineX, this.height/2 + (levels[j] * scaleFactor)); lineX++; } if (borderWidth > 0) { graphics.lineStyle(borderWidth, borderColor, 1, true, LineScaleMode.NORMAL); graphics.drawRect(0, 0, this.width, this.height); } } } }
