Firebird – a sound visualization

Andreas | 2010-01-22 | Flash

The other day I stumbled upon a minimalistic music video by Peter Gabriel called Der Rhythmus der Hitze. As I’ve never had the chance to experiment with the Spectrum-functionality in AS3 I thought this would be a perfect first example as I found the birdlike visuals were quite nice and mesmerizing. Here’s the result.

Firebird

package
{
        import flash.display.GradientType;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.filters.GlowFilter;
        import flash.geom.Matrix;
        import flash.media.SoundMixer;
        import flash.utils.ByteArray;
        import se.xcom.math.DegreesVector;

        public class Firebird extends Sprite
        {
                private const BAR_WIDTH:int = 1;
                private var ba:ByteArray;
                private var matrix:Matrix;
                private var degrees:DegreesVector;
                private var counter:int;
                private var aColours:Array;
               
                public function Firebird()
                {
                        super();
                        counter = 0;
                        aColours = [0xFFFFFF,0xFFFF33,0xFF2200,0xFF0000];
                        ba = new ByteArray();
                        matrix = new Matrix();
                        degrees = new DegreesVector();
                        this.filters = [new GlowFilter(0xFF2211,1,20,30,3,2)];
                        this.addEventListener(Event.ENTER_FRAME,onFrameTick);
                }
               
                private function onFrameTick(e:Event)
                {
                        var enhance:Number
                        var barHeight:Number
                        var posY:Number
                       
                        // get new ByteArray from soundmixer
                        SoundMixer.computeSpectrum(ba,true);
                       
                        // setting up gradientcolours. Using the aColours gives us the flexibility
                        //  to switch between different colours in the future if we would like to.
                        var gradientColours:Array = [aColours[3], aColours[2], aColours[1], aColours[0], aColours[1], aColours[2], aColours[3]];
                       
                        with(graphics)
                        {      
                                clear();
                                for (var i:int=0; i<256; i+=BAR_WIDTH)
                                {      
                                        // enhance largen the shape towards the middle. The first 60 bars will be enhanced
                                        // (simply to create the birdhead)
                                        enhance = 60-i;
                                        enhance = (enhance <0)?0:enhance;
                                       
                                        // now the bar is moved in Y-axis using a normal sinus curve. (Using a faster custom Sine-class)
                                        posY = degrees.fastSin(int(counter+i*0.65))*160;       
                                       
                                        // bar height is calculated using the sound spectrum in the ByteArray.
                                        // It is multiplied and enhanced if close to the middle
                                barHeight = (ba.readFloat() * (100+enhance));
                               
                                // creating the gradientbox set up gradientfill.
                                matrix.createGradientBox(BAR_WIDTH,2*barHeight,1.57075,0,-barHeight-posY*0.5);
                                        beginGradientFill(GradientType.LINEAR,gradientColours,[0,1,1,1,1,1,0],[0,50,110,128,146,205,255],matrix);
                                       
                                        // Draing 2 bars. One for each wing. Adding BAR_WIDTH on the left to avoid a gap in the middle.
                                drawRect(i, -barHeight-posY*0.5, BAR_WIDTH, 2*barHeight);    
                                drawRect(-i+BAR_WIDTH, -barHeight-posY*0.5, BAR_WIDTH, 2*barHeight);            
                                }
                        }
                        // adding counter so the Sine-curve starts one step away next frame (result: the wave motion)
                        counter+=1;
                }
        }
}

The code is quite straight forward.
Every single frame the SoundMixer creates a ByteArray containing Numbers from 0 – 1 which is used in order to create the bars/lines. The only thing that is custom is the DegreeVector class that converts all Radian to Degrees (as I’m no fan of radians). What it also does is to use a precalculated array of Sine-values that speedens up the sine-calculations a bit. This is of course not necessary and you could easily use the normal Math.sin functions to get the same result.

Just build a Firebird object in your main class, add it to stage and start playing any sound and Phoenix will manifest itself.

Tags: , , , , ,


Responses


  1. Terrific work! This is the type of information that should be shared around the web. Shame on the search engines for not positioning this post higher!



  2. good points and the details are more precise than somewhere else, thanks.

    - Murk



  3. Beautiful stuff! It won’t work without se.xcom.math.DegreesVector though. Is it available somewhere?



LEAVE COMMENT