package { import aether.utils.ImageUtil; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.filters.BitmapFilterQuality; import flash.filters.BitmapFilterType; import flash.filters.GradientGlowFilter; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.utils.ByteArray; [SWF(width=400, height=300, backgroundColor=0x000000)] /** * Draws the raw sound wave of a loaded sound playing in a circular pattern with * multiple filters applied. A copied, scaled up version of the same pattern is * placed behind to add more visual interest. */ public class hush_wave_brew extends Sprite { // the radius of the main circular pattern private const WAVE_RADIUS:uint = 150; // the colors used for the visualization private const WAVE_COLORS:Array = [0x6666FF, 0xFFFFFF, 0x9966FF]; private var _soundController:component_control; private var _centerSprite:Sprite; private var _backgroundData:BitmapData; /** * Constructor. Creates assets in which the visualization will be drawn and loads sound. */ public function hush_wave_brew() { makeBackground(); makeCenterSprite(); _soundController = new component_control("../assets/music/miles-brew.mp3"); _soundController.addEventListener(Event.CHANGE, onSoundChange); } /** * Creates background bitmap data instance and places this on stage through a bitmap. */ private function makeBackground():void { _backgroundData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0xFF000000); var background:Bitmap = new Bitmap(_backgroundData); addChild(background); } /** * Places a new sprite center stage in which the main visualization will be drawn. * A gradient glow filter is applied to the sprite. */ private function makeCenterSprite():void { _centerSprite = new Sprite(); _centerSprite.x = stage.stageWidth/2; _centerSprite.y = stage.stageHeight/2; addChild(_centerSprite); _centerSprite.filters = [ new GradientGlowFilter( 5, 45, WAVE_COLORS, [0, 1], [0, 180, 255], 10, 10, 1, BitmapFilterQuality.MEDIUM, BitmapFilterType.FULL, true ) ]; } /** * Updates the background bitmap data with current visuals on the stage, scaled up and * set at a low opacity over the previous rendering. */ private function updateBackground():void { var capture:BitmapData = ImageUtil.getBitmapData(this); // amount to scale up screen capture var scale:Number = 1.3; var matrix:Matrix = new Matrix(); matrix.scale(scale, scale); // centers scaled up image matrix.translate((width-width*scale)/2, (height-height*scale)/2); // draws at low opacity so previous renderings are still visible _backgroundData.draw(capture, matrix, new ColorTransform(.8, .6, .7, .3)); } /** * Updates the main visualization with new sound data. */ private function updateCenterSprite():void { // raw sound wave data is captured var spectrumData:ByteArray = _soundController.getSoundSpectrum(false); _centerSprite.graphics.clear(); _centerSprite.graphics.lineStyle(1, 0xFFFFFF); var x:Number; var y:Number; var value:Number; var angle:Number; var i:int = -1; while (++i < 512) { // value is scaled to be within WAVE_RADIUS value value = Math.ceil(WAVE_RADIUS*spectrumData.readFloat()); // each value will be drawn at different angle around full circle angle = i/512*Math.PI*2; x = Math.cos(angle)*value; y = Math.sin(angle)*value; _centerSprite.graphics.moveTo(0, 0); _centerSprite.graphics.lineTo(x, y); } } /** * Handler for when the sound changes (basically, an ENTER_FRAME while the sound is playing). * This calls updateBackground() and updateCenterSprite() to redraw visualization. * * @param event Event dispatched by SoundController. */ private function onSoundChange(event:Event):void { updateBackground(); updateCenterSprite(); } } }