/* Example usage: // Import the class import com.sparepencil.visuals.SmokeScreen; // Create a SmokeScreen instance of 500 by 400 pixels var visual:SmokeScreen = new SmokeScreen(500, 400); // Add it to the stage addChild(visual); // Visualise a sound (playing starts automatically) visual.startVisual(new Sound(new URLRequest("visual.mp3"))); SmokeScreen visualisation Copyright 2008 Bas van Doren */ package com.sparepencil.visuals { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.events.Event; import flash.filters.BlurFilter; import flash.filters.ColorMatrixFilter; import flash.geom.Point; import flash.media.Sound; import flash.media.SoundChannel; import flash.media.SoundMixer; import flash.utils.ByteArray; public class SmokeScreen extends MovieClip { private var ba:ByteArray; private var bf:BlurFilter; private var bm:Bitmap; private var bmd:BitmapData; private var cmf:ColorMatrixFilter; private var fft:Boolean; private var sc:SoundChannel; private var xoffset:Number; private var yoffset:Number; private var maxspeed:Number; private var maxamp:Number; private var xblur:Number; private var yblur:Number; private var linewidth:Number; /* Constructor. @param vwidth Width of the visualisation. @param vheight Height of the visualisation */ public function SmokeScreen(vwidth:Number, vheight:Number):void { // Create a new Bitmap bmd = new BitmapData(vwidth, vheight, true, 0x000000); bm = new Bitmap(bmd); // Add it to this MovieClip this.addChild(bm); // Visualisation was designed at 500x400(@40fps) // Let's recalculate some values maxspeed = 10 * vheight/400; maxamp = 100 * vheight/400; xblur = 3 * vwidth/500; yblur = 8 * vheight/400; linewidth = 1 * vheight/400; // Create two filters (will be applied to Bitmap when rendering) bf = new BlurFilter(xblur, yblur, 3); cmf = new ColorMatrixFilter( [1,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,0.54445,0]); // Calculate offsets for drawing the visualisation xoffset = vwidth * 0.5; yoffset = vheight * 0.9; // Apply fast Fourier transformation to spectrum? fft = true; } /* Starts playing and visualising a Sound object. @param sound Sound object to play and visualise. */ public function startVisual(sound:Sound):void { sc = sound.play(); stage.addEventListener(Event.ENTER_FRAME, renderVisual); } /* Stops playing and visualising. */ public function stopVisual():void { sc.stop(); stage.removeEventListener(Event.ENTER_FRAME, renderVisual); } private function renderVisual(e:Event) { ba = new ByteArray(); // Fill the ByteArray with the computed sound spectrum SoundMixer.computeSpectrum(ba, fft); // Clear any previous drawings and apply linestyle this.graphics.clear(); this.graphics.lineStyle(linewidth, 0xFFFFFF); // Read the first spectrum value... var centerY1:Number = ba.readFloat() * -maxamp + yoffset; // and move the 'drawing cursor' to the corresponding point this.graphics.moveTo(xoffset, centerY1); // Start drawing the first half of the spectrum (left channel on stereo) for (var i:uint = 1; i < 256; i++) { var ampLeft:Number = ba.readFloat() * -maxamp + yoffset; this.graphics.lineTo(xoffset - i * (xoffset/256), ampLeft); } // Move the drawing cursor back to the starting point this.graphics.moveTo(xoffset, centerY1); // Read the first spectrum value (of the second half)... var centerY2:Number = ba.readFloat() * -maxamp + yoffset; // and draw a line to the corresponding point this.graphics.lineTo(xoffset, centerY2); // Start drawing the second half of the spectrum (right channel on stereo) for (i = 257; i < 512; i++) { var ampRight:Number = ba.readFloat() * -maxamp + yoffset; this.graphics.lineTo(i * (xoffset/256), ampRight); } // Render the MoveClip content in the BitmapData bmd.draw(this); // Scroll the bitmap depending on the overall volume bmd.scroll(0, Math.round((sc.leftPeak + sc.rightPeak) * 0.5 * -maxspeed)); // Draw transparent lines along the sides to counter 'blur artifacts' for(i = 0; i < bmd.height; i++) { bmd.setPixel(0, i, 0x00000000); bmd.setPixel(bmd.width -1, i, 0x00000000); } // Clear the drawings this.graphics.clear(); // Apply filters to BitmapData bmd.applyFilter(bmd, bmd.rect, new Point(0,0), bf); bmd.applyFilter(bmd, bmd.rect, new Point(0,0), cmf); } } }