package { import aether.effects.carnival.KaleidoscopeEffect; import aether.utils.ImageUtil; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.BlendMode; import flash.display.Sprite; import flash.filters.BlurFilter; import flash.events.Event; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.utils.ByteArray; [SWF(width=400, height=300, backgroundColor=0x000000)] /** * Sound visualization with values in a frequency spectrum being drawn into a bar with different colors. * A segment of this graph (the lower frequencies) is then drawn into a wheel shape that is rotated in 3D space * and constantly rotated each frame. */ public class graphic_flex_image_effects_11_Flex_Pinwheel extends Sprite { private var _soundController:graphic_flex_image_effects_11_Flex_SoundController; private var _pinwheelBitmap:Bitmap; private var _pinwheelHolder:Sprite; private var _backgroundData:BitmapData; /** * Constructor. Creates assets in which the visualization will be drawn and loads sound. */ public function graphic_flex_image_effects_11_Flex_Pinwheel() { makeBackground(); makegraphic_flex_image_effects_11_Flex_Pinwheel(); _soundController = new graphic_flex_image_effects_11_Flex_SoundController("graphic-flex-image-effects-11-assets-ToyMakersArmy.mp3"); _soundController.addEventListener(Event.CHANGE, onSoundChange); } /** * Creates background bitmap data and places these on stage through bitmap instance. * A blur filter, heavy on the y axis, is applied to the bitmap. */ private function makeBackground():void { _backgroundData = new BitmapData(stage.stageWidth, stage.stageHeight); var bitmap:Bitmap = new Bitmap(_backgroundData); bitmap.filters = [new BlurFilter(1, 20)]; addChild(bitmap); } /** * Creates the sprite and nested bitmap in which the sound visualization will be drawn. */ private function makegraphic_flex_image_effects_11_Flex_Pinwheel():void { var width:Number = stage.stageWidth; var height:Number = stage.stageHeight; _pinwheelHolder = new Sprite(); _pinwheelBitmap = new Bitmap(); // offset by half width and half height to make 3D transformations occur around center of image _pinwheelBitmap.x -= width/2; _pinwheelBitmap.y -= height/2; _pinwheelHolder.addChild(_pinwheelBitmap); var outerHolder:Sprite = new Sprite(); // outer holder is centered on stage horizontally, a little above center vertically outerHolder.x = width/2; outerHolder.y = height*2/5; // gives "overhead view" of wheel outerHolder.rotationX = -60; outerHolder.addChild(_pinwheelHolder); addChild(outerHolder); } /** * Updates sound visualization with new sound data. This draws the frequency spectrum into a column, * with each pixel color and alpha being determined by the value of the frequency. This column is scaled up into a * an image the size of the stage, which is then drawn into a pinwheel shape using aether's Kaleidoscope effect. * This final image is set as the data for the pinwheel bitmap and this bitmap's parent is rotated a little each frame. */ private function updategraphic_flex_image_effects_11_Flex_Pinwheel():void { // get current sound playing frequency data var spectrumData:ByteArray = _soundController.getSoundSpectrum(); var row:BitmapData = new BitmapData(1, 512, true); var alpha:BitmapData = new BitmapData(1, 512); var value:int; var i:int = -1; while (++i < 512) { // each value is multipled by the full spectrum of colors value = Math.ceil(0xFFFFFF*spectrumData.readFloat()); // a full opacity pixel with the calculated color is drawn in row row.setPixel32(0, i, 0xFF << 24 | value); // a happy accident, this actually makes little sense, but gives a nicer effect // for the lower alpha pixels, giving a more blue tint to resulting effect alpha.setPixel(0, i, 0xFF*value); } // copies red channel from alpha bitmap data to alpha channel of row row.copyChannel(alpha, alpha.rect, new Point(), BitmapDataChannel.RED, BitmapDataChannel.ALPHA); // scales the up the row image as it is drawn into an image the size of the stage var matrix:Matrix = new Matrix(); matrix.scale(stage.stageWidth, stage.stageHeight/512); var bitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000); bitmapData.draw(row, matrix); // scaled up image has kaleidoscope effect applied new KaleidoscopeEffect(9).apply(bitmapData); _pinwheelBitmap.bitmapData = bitmapData; // spinning wheel got to go round... _pinwheelHolder.rotation += 2; } /** * Updates the background bitmap data with current visuals on the stage, with slight color transform. * The image is scrolled down vertically to give appearance of pixels from previous renders falling down. */ private function updateBackground():void { var capture:BitmapData = ImageUtil.getBitmapData(this); _backgroundData.draw(capture, null, new ColorTransform(.6, .7, .7, .9)); _backgroundData.scroll(0, 10); } /** * Handler for when the sound changes (basically, an ENTER_FRAME while the sound is playing). * This calls the update methods in this class to redraw visualization. * * @param event Event dispatched by SoundController. */ private function onSoundChange(event:Event):void { updategraphic_flex_image_effects_11_Flex_Pinwheel(); updateBackground(); } } }