In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Zero Gravity Escape

Its a post compo edition of my entree to LudumDare 21
Real entree here http://www.ludumdare.com/compo/ludum-dare-21/?action=preview&uid=232

I would not really call it a game , more of a prototype of one, and not a very good one at that :D
Seems I managed to get in to a top 10% of entress in "innovation". Guess those who voted so never played Toribash :D

Anyways worked a little on presentation for post compo entree. As it was pure code by the end of LD21 decided to have little bit of fun and add textures and sounds trough pure code too. Results? This weights 75K without a font :D

Things used and done:
Used Box2D
Used AS3 SFXr for sounds http://code.google.com/p/as3sfxr/
GreeenShock TweenLite
bit101 components for buttons

Other then that, ~1200 lines of my code among which is Texture class for generating star sky, ship alloy and crates textures.

P.S Switch to fullscreen, this game was not meant to work in 465x465 window :)
Get Adobe Flash player
by wonderwhyer 08 Oct 2011
    Embed
/**
 * Copyright wonderwhyer ( http://wonderfl.net/user/wonderwhyer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/n1Mj
 */

package{

    import Box2D.Dynamics.*
    import Box2D.Collision.*
    import Box2D.Collision.Shapes.*
    import Box2D.Dynamics.Joints.*
    import Box2D.Dynamics.Contacts.*
    import Box2D.Common.Math.*
    import com.bit101.components.ComboBox;
    import com.bit101.components.PushButton;
    import com.greensock.*;
    import com.greensock.easing.Back;  

    import flash.events.Event;
    import flash.display.*;
    import flash.events.KeyboardEvent;
    import flash.filters.BevelFilter;
    import flash.filters.DropShadowFilter;
    import flash.filters.GlowFilter;
    import flash.geom.Rectangle;
    import flash.text.*;


    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import com.bit101.components.Knob;
    import flash.utils.getTimer;
    import flash.geom.Point;
    
    import flash.system.Capabilities;
    
    /**
     * ...
     * @author EduardRuzga www.wonderwhy-er.com
     * Game made for LudumDare 21 compo, 
     * post compo edition with some textures and sounds added
     */
     
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
    public class Main extends MovieClip {
        
        public var bodyParts:Array = [];
        public var bodyPartsHash:Object = {};
        public var debug:TextField;
        public var playing:Boolean = true;
        public var m_currId:int = 0;
        public var sandBox:SandBox;
        static public var m_sprite:Sprite;
        static public var ui:Sprite;
        static public var dragedJoint:Sprite;
        
        public static var _instance:Main;
        
        public var selecting:Boolean = false;
        public var selectionStartX:Number = 0;
        public var selectionStartY:Number = 0;
    
        [Embed(systemFont="serif", fontWeight="bold", fontName="font1", mimeType="application/x-font", embedAsCFF="false")]
        private static var font:Class;
        
        public var glow:GlowFilter = new GlowFilter(0xFF0000);
        public var skyTexture:BitmapData;
        public var sky:Sprite;
        
        public var startScreen:Sprite;
        public var GameName:TextField;
        public var GameNameTexture:Sprite;
        public var StartGameText:TextField;
        
        public var pause:PushButton;
        public var fullScreenBtn:PushButton;
        public var soundBtn:PushButton;
        
        public var reStart:PushButton;
        
        public function Main(){
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT
            stage.addEventListener(Event.RESIZE, resize);
            //StartGame();
            
            startScreen = new Sprite();
            addChild(startScreen);
            GameName = new TextField();
            GameName.defaultTextFormat = new TextFormat("font1", 50, 0xFFFFFF, true);
            

            _instance = this;
            
            GameName.text = "Zero\n      Gravity\n           Escape";


            GameName.autoSize = TextFieldAutoSize.LEFT;
            GameName.embedFonts = true;
            GameName.selectable = false;
            GameNameTexture = new Sprite();
            var bmd:BitmapData = Textures.getShipAlloy(100, 100,1);
            bmd = Textures.getShipAlloy(100, 100,1);
            GameNameTexture.graphics.beginBitmapFill(bmd);
            GameNameTexture.graphics.drawRect(0, 0, GameName.width, GameName.height);
            GameNameTexture.graphics.endFill();
            GameNameTexture.x = GameName.x;
            GameNameTexture.y = GameName.y;
            startScreen.addChild(GameNameTexture);
            startScreen.addChild(GameName);
            GameNameTexture.mask = GameName;
            
            
            
            StartGameText = new TextField();
            StartGameText.defaultTextFormat = new TextFormat("font1", 30, 0xFFFFFF, true);
            StartGameText.text = "Click anywhere to start";
            startScreen.addChild(StartGameText);
            StartGameText.y = GameName.y + GameName.height + 50;
            StartGameText.autoSize = TextFieldAutoSize.CENTER;
            StartGameText.embedFonts = true;
            StartGameText.selectable = false;
            StartGameText.x = GameName.x + (GameName.width - StartGameText.width) / 2;
            
            startScreen.x = (stage.stageWidth - startScreen.width) / 2;
            startScreen.y = (stage.stageHeight - startScreen.height) / 2;
            
            stage.addEventListener(MouseEvent.CLICK, StartGame);
            
            var t:uint = getTimer();
            SFX.init();
            trace((getTimer()-t));
            
        }
        
        public function resize(e:Event):void
        {
            if (startScreen) {
                startScreen.x = (stage.stageWidth - startScreen.width) / 2;
                startScreen.y = (stage.stageHeight - startScreen.height) / 2;
            }
        }
        
        public function StartGame(e:Event = null):void
        {
            removeChild(startScreen);
            addEventListener(Event.ENTER_FRAME, update, false, 0, true);
            stage.removeEventListener(MouseEvent.CLICK, StartGame);
            
            
            
            
            skyTexture = Textures.getStarSky(500, 500);
            sky = new Sprite();
            sky.graphics.beginBitmapFill(skyTexture);
            sky.graphics.drawRect(0, 0, 1100 + Capabilities.screenResolutionX, 1000 + Capabilities.screenResolutionY);
            sky.graphics.endFill();
            addChild(sky);
            sky.mouseEnabled = sky.mouseChildren = false;
            
            m_sprite = new Sprite();
            m_sprite.name = "Engine";
            addChild(m_sprite);
            
            m_sprite.mouseEnabled = false;
            
            ui = new Sprite();
            ui.mouseEnabled = ui.mouseChildren = false;
            addChild(ui);
            // input
            
            var hints:TextField = new TextField();
            hints.mouseEnabled = false;
            hints.autoSize = TextFieldAutoSize.LEFT;
            hints.textColor = 0xFFFFFF;
            hints.defaultTextFormat = new TextFormat(null, 14);
            hints.text = "Story: you are on a space station,\n gravity went off, \nnow you need to get to the button to turn it on again" 
            +"\n\n Controls:\n- click on joints and drag to set angles\n-click anywhere and drag to select multiple joints and relax or fixate them\n-use space to pause the game for more precise and simulatious commands joint edditing\n-press R to restart";
            ui.addChild(hints);
            

            
            stage.addEventListener(MouseEvent.MOUSE_UP, OnMouseRelease);
            
            debug = new TextField();
            debug.autoSize = TextFieldAutoSize.LEFT;
            debug.x = 300;
            addChild(debug);
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, OnStageDrag);
            
            
            pause = new PushButton(this, 5, 5, "Pause(Space)", Pause);
            fullScreenBtn = new PushButton(this, pause.x+pause.width + 5, 5, "Fullscreen", fullScreen);
            soundBtn = new PushButton(this, fullScreenBtn.x + fullScreenBtn.width + 5, 5, "Turn sounds off", sounds);
            reStart = new PushButton(this,soundBtn.x+soundBtn.width + 5, 5, "Restart(R)", Restart);
        }
        
        public function sounds(e:Event=null):void
        {
            SfxrSynth.Mute = !SfxrSynth.Mute;
            soundBtn.label = SfxrSynth.Mute?"Turn sounds on":"Turn sounds off";
        }
        
        public function fullScreen(e:Event = null):void
        {
            if (stage.displayState == StageDisplayState.FULL_SCREEN)
            {
                stage.displayState = StageDisplayState.NORMAL;
                fullScreenBtn.label = "Fullscreen";
            }
            else
            {
                stage.displayState = StageDisplayState.FULL_SCREEN;
                fullScreenBtn.label = "Exit Fullscreen";
            }
            
        }
        
        public function Pause(e:Event=null):void
        {
            playing = !playing;
            pause.label = playing?"Pase(Space)":"Play(Space)";
        }
        
        public function OnKeyDown(e:KeyboardEvent):void
        {
            switch(e.keyCode)
            {
                case 32:
                    Pause();
                break;
                case 82:
                    Restart();
                break;
            }
        }
        
        public function Restart(e:Event = null):void
        {
            sandBox = null;
            pressed = false;
            while (m_sprite.numChildren>0)
            {
                m_sprite.removeChildAt(0);
            }
            bodyParts = [];
        }
        
        public function formatRadians(n:Number):Number
        {
            return Math.round(n * 180 / Math.PI);
        }
        
        public var pressed:Boolean = false;
        
        public function ButtonPress():void
        {
            if (!pressed)
            {
                SFX.powerUp.play();
                pressed = true;
                

                
                TweenLite.to(SandBox._instance.gravity, 1,  { delay:1, x:0,y:10, ease:Back.easeOut} );
                //var t:GTween = new GTween(SandBox._instance.gravity, 1, { }, { delay:1, ease:fl.motion.easing.Back.easeOut } );
                //t.proxy.x = 0;
                //t.proxy.y = 10;
                
                var spr:Sprite = new Sprite();
                spr.graphics.beginFill(0);
                spr.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
                var theEnd:TextField = new TextField();
                theEnd.textColor = 0xFFFFFF;
                theEnd.defaultTextFormat = new TextFormat(null, 20);
                theEnd.text = "To be conitnued... Hopefully. \nClick to see how clumsy austraunauts are with gravity :D";
                theEnd.autoSize = TextFieldAutoSize.LEFT;
                theEnd.x = (stage.stageWidth - theEnd.width) / 2;
                theEnd.y = (stage.stageHeight - theEnd.height) / 2;

                spr.addChild(theEnd);
                addChild(spr);
                spr.alpha = 0;
                TweenLite.to(spr, 1,  { delay:0, x:0,y:10, ease:Back.easeOut } );
                //t = new GTween(spr, 1, { }, { delay:0, ease:fl.motion.easing.Back.easeOut } );
                //t.proxy.x = 0;
                //t.proxy.y = 10;
                
                spr.addEventListener(MouseEvent.CLICK, Remove);
                
                
                TweenLite.to(spr, 1,  { delay:2, alpha:1, ease:Back.easeOut } );
                //t = new GTween(spr, 1, { }, { delay:2, ease:fl.motion.easing.Back.easeOut } );
                //t.proxy.alpha = 1;
            }
            

        }
        
        public function Remove(e:Event):void
        {
            removeChild(e.currentTarget as Sprite);
            
        }
        
        public function update(e:Event):void{

            m_sprite.graphics.clear()

            
            // if null, set new test
            if (!sandBox) {
                sandBox = new SandBox();
                var itms:Array = [];
                for (var key:String in sandBox.muscles)
                {
                    itms.push(key);
                    var info:Object = { name:key, "joint":sandBox.muscles[key], "angle":0, "state":false };
                    bodyPartsHash[key] = info;                        
                    bodyParts.push( info  );
                }
                var walls:Sprite = new Sprite();
                var texture:BitmapData = Textures.getShipAlloy(100, 100);
                
                var body:b2Body = sandBox.m_world.m_bodyList;
                while (body)
                {
                    var rect:Rectangle = body.m_userData as Rectangle;
                    if (rect != null)
                    {
                        walls.graphics.beginBitmapFill(texture);
                        walls.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
                    }
                    body = body.GetNext();
                }
                walls.filters = [new DropShadowFilter(0,45,0,1,10,10,1.5,1,true)/*Textures.bvl*/,new GlowFilter(0,1,300,300,2)];
                
                var walls2:Sprite = new Sprite();
                walls2.filters = [new DropShadowFilter(0,45,0,1,10,10,1.5,1,true)/*new BevelFilter(5, 45, 0xffffff, 1, 0, 1, 5, 5)*/];
                rect = walls.getBounds(walls);
                walls2.graphics.beginBitmapFill(Textures.getShipAlloy(100, 100,1));
                walls2.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
                walls2.graphics.drawCircle(200, 200, 50 );
                walls2.graphics.drawCircle(650, 200, 50 );
                walls2.graphics.drawCircle(400, 600, 50 );
                walls2.graphics.drawCircle(850, 600, 50 );
                walls2.mouseChildren = walls2.mouseEnabled = walls.mouseEnabled = walls.mouseChildren = false;
                walls2.cacheAsBitmap = walls.cacheAsBitmap = true;
                m_sprite.addChild(walls2);
                m_sprite.addChild(walls);
            }
            ui.graphics.clear();
            
            var scale:Number = 30;
            
            // update current test
            if (playing)
            {
                sandBox.Update();
                var headPos:b2Vec2 = (bodyPartsHash["neck"].joint as b2Joint).GetBody1().GetPosition().Copy();
                headPos.Multiply(scale);
                ui.x = m_sprite.x = -headPos.x+stage.stageWidth/2;
                ui.y = m_sprite.y = -headPos.y+stage.stageHeight/2;
                sky.x = -headPos.x / 2 - Capabilities.screenResolutionX / 2;
                sky.y = -headPos.y / 2 - Capabilities.screenResolutionY / 2;
            }
            

            
            
            
            body = sandBox.m_world.m_bodyList;
            while (body)
            {
                if (body.m_userData as Sprite != null)
                {
                    var sp:Sprite = body.m_userData as Sprite;
                    if(sp){
                        if (sp.parent != m_sprite)
                        {
                            m_sprite.addChild(sp);
                        }
                        var pos:b2Vec2 = body.GetPosition();
                        sp.x = pos.x*scale;
                        sp.y = pos.y * scale;
                        sp.rotation = body.GetAngle() * (180 / Math.PI);
                    }
                }
                body = body.GetNext();
            }
            var dir:b2Vec2;
            
            if (dragedJoint)
            {
                if(!dragedJoint.hitTestPoint(dragedJoint.mouseX,dragedJoint.mouseY,true))
                {

                    var i:uint = int(dragedJoint.name);
                    var bodyPartInfo:Object = bodyParts[i];
                    if(!bodyPartInfo.state && (getTimer()-mouseDownTime)>100)
                        bodyPartInfo.state = true;
                    var joint:b2RevoluteJoint = bodyPartInfo.joint as b2RevoluteJoint;
                    
                    var angle:Number;
                    
                    var vec:b2Vec2 = new b2Vec2(dragedJoint.x - m_sprite.mouseX, dragedJoint.y - m_sprite.mouseY);
                    var newAngle:Number = Math.atan2(vec.y, vec.x);
                    
                    
                    var baseVec:b2Vec2 = joint.m_localAnchor2.Copy();
                    baseVec.Subtract(joint.GetBody2().GetLocalCenter());
                    var baseAgnle:Number = Math.atan2(baseVec.y, baseVec.x);


                    
                    //hack some angle problems after too much rotations
                    if (bodyPartInfo.name.indexOf("Elbow") < 0 && bodyPartInfo.name.indexOf("Shoulder") < 0)
                    {
                        baseAgnle += Math.PI;
                    }
                    
                    var finalAngle:Number = (newAngle + baseAgnle) - bringDownRadian(joint.GetBody1().GetAngle());
                    
                    if (finalAngle > Math.PI)
                        finalAngle -= Math.PI * 2;
                    else if (finalAngle < -Math.PI)
                        finalAngle += Math.PI * 2;
                    
                    finalAngle = Math.max(joint.GetLowerLimit(), Math.min(joint.GetUpperLimit(), finalAngle));    
                    
                    
                    
                    bodyPartInfo.angle = finalAngle;
                  
                    
                    
                    ui.graphics.lineStyle(1, 0xFF0000);
                    ui.graphics.moveTo(dragedJoint.x, dragedJoint.y);
                    ui.graphics.lineTo(m_sprite.mouseX, m_sprite.mouseY);

                }
            }
            var selectionRect:Rectangle;
            if (selecting)
            {
                ui.graphics.lineStyle(1, 0xFFFF00);
                selectionRect = new Rectangle(Math.min(m_sprite.mouseX, selectionStartX), Math.min(m_sprite.mouseY, selectionStartY), Math.abs(m_sprite.mouseX - selectionStartX), Math.abs(m_sprite.mouseY - selectionStartY));
                ui.graphics.drawRect(selectionRect.x,selectionRect.y,selectionRect.width,selectionRect.height);
                
            }
            
            for (i = 0; i < bodyParts.length; i++)
            {
                bodyPartInfo = bodyParts[i];
                joint = bodyPartInfo.joint as b2RevoluteJoint;
                sp = joint.m_userData as Sprite;
                if (sp)
                {
                    if (sp.parent != m_sprite)
                    {
                        m_sprite.addChild(sp);
                        sp.name = i.toString();
                        
                        sp.addEventListener(MouseEvent.MOUSE_DOWN, OnJointDrag);
                    }
                    
                    if (selecting)
                    {
                        var bounds:Rectangle = sp.getBounds(m_sprite);
                        if (bounds.intersects(selectionRect))
                        {
                            sp.filters = [glow];
                        }
                        else 
                        {
                            sp.filters = [];
                        }
                    }
                    else
                        sp.filters = [];
                        
                        
                    var center:b2Vec2 = joint.GetAnchor1();
                    center.Add(joint.GetAnchor2());
                    center.Multiply(0.5);
                    sp.x = center.x*scale;
                    sp.y = center.y * scale;
                    dir = (joint as b2RevoluteJoint).GetBody2().GetPosition().Copy();
                    dir.Subtract((joint as b2RevoluteJoint).GetAnchor2());
                    var ang:Number = Math.atan2(dir.y,dir.x)* (180 / Math.PI);
                    sp.rotation = ang;// (joint as b2RevoluteJoint).GetBody2().GetAngle() * (180 / Math.PI);
                    sp.alpha = 0.5 + (bodyPartInfo.state?0.5:0);
                }
                
                if (bodyParts[i].state)
                {
                    (joint as b2RevoluteJoint).m_enableMotor = true;
                    var angleDif:Number = joint.GetJointAngle() - Number(bodyPartInfo.angle);///(180/Math.PI);
                    //trace("dif:"+angleDif);
                    if(angleDif!=0)
                        joint.SetMotorSpeed( -5 * angleDif);
                }
                else
                {
                    (joint as b2RevoluteJoint).m_enableMotor = false;
                }
            }                    
        }
        
        public function bringDownRadian(n:Number):Number
        {
            var res:Number = n%(Math.PI*2);
            return res;
        }
        
        public function OnStageDrag(e:Event):void
        {
            if (e.target == stage)
            {
                selecting = true;
                selectionStartX = m_sprite.mouseX;
                selectionStartY = m_sprite.mouseY;
            }
        }
        
        public function OnMouseRelease(e:Event):void
        {
            if(dragedJoint)
            {
                var i:uint = int(dragedJoint.name);
                var bodyPartInfo:Object = bodyParts[i];
                var joint:b2RevoluteJoint = bodyPartInfo.joint as b2RevoluteJoint;
                joint.SetMotorSpeed(0);
                dragedJoint = null;
            }
            if (selecting)
            {
                selecting = false;
                var selected:Array = [];
                var activeCount:int = 0;
                var unactiveCount:int = 0;
                var selectionRect:Rectangle = new Rectangle(Math.min(m_sprite.mouseX, selectionStartX), Math.min(m_sprite.mouseY, selectionStartY), Math.abs(m_sprite.mouseX - selectionStartX), Math.abs(m_sprite.mouseY - selectionStartY));
                for (i = 0; i < bodyParts.length; i++)
                {
                    bodyPartInfo = bodyParts[i];
                    joint = bodyPartInfo.joint as b2RevoluteJoint;
                    var sp:Sprite = joint.m_userData as Sprite;
                    sp.filters = [];
                    var bounds:Rectangle = sp.getBounds(m_sprite);
                    if (bounds.intersects(selectionRect))
                    {
                        selected.push(bodyPartInfo);
                        if (bodyPartInfo.state)
                            activeCount++
                        else
                            unactiveCount++
                    }
                }
                var newState:Boolean = unactiveCount>activeCount;
                for (i = 0; i < selected.length; i++)
                {
                    selected[i].state = newState;
                    
                    selected[i].angle = selected[i].joint.GetJointAngle();
                }
            }
        }
        
        public var mouseDownTime:Number;
        
        public function OnJointDrag(e:Event):void
        {
            mouseDownTime = getTimer();
            dragedJoint = e.currentTarget as Sprite;
            var i:uint = int(dragedJoint.name);
            var bodyPartInfo:Object = bodyParts[i];
            var joint:b2RevoluteJoint = bodyPartInfo.joint as b2RevoluteJoint;
            if (bodyPartInfo.state)
            {
                bodyPartInfo.state = false;
            }
            else
            {
                bodyPartInfo.state = true;
                bodyPartInfo.angle = joint.GetJointAngle();
            }
        }

    }
}

import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Dynamics.Joints.*;
import Box2D.Dynamics.Contacts.*;
import Box2D.Common.*;
import Box2D.Common.Math.*;
import com.greensock.*;
import com.greensock.easing.*;  
import flash.filters.DropShadowFilter;
import flash.geom.Rectangle;
import flash.utils.setTimeout;
import Main;

import flash.utils.getTimer
import flash.display.*;


class SandBox{
    
    public var muscles:Array;
    public var m_world:b2World;
    public var m_bomb:b2Body;
    public var m_mouseJoint:b2MouseJoint;
    public var m_iterations:int = 10;
    public var m_timeStep:Number = 1/30;
    public var m_physScale:Number = 30;
    // Sprite to draw in to
    public var m_sprite:Sprite;
    public var m_door1Motor:b2PrismaticJoint;
    
    public static var CostumeColor:uint = 0xcccccc;
    
    public var contactListener:ContactListener;
    
    public var BodyParts:Array;
    
    public var button:b2Body;
    
    public static var _instance:SandBox;
    
    public var gravity:b2Vec2;
    
    public function SandBox(){
        
        m_sprite = Main.m_sprite;
        
        _instance = this;
        
        var worldAABB:b2AABB = new b2AABB();
        worldAABB.lowerBound.Set(-1000.0, -1000.0);
        worldAABB.upperBound.Set(1000.0, 1000.0);
        
        
        
        // Define the gravity vector
        gravity = new b2Vec2(0.0, 10.0);
        
        // Allow bodies to sleep
        var doSleep:Boolean = true;
        
        // Construct a world object
        m_world = new b2World(worldAABB, gravity, doSleep);
        // set debug draw
        /*var dbgDraw:b2DebugDraw = new b2DebugDraw();
        var dbgSprite:Sprite = new Sprite();
        m_sprite.addChild(dbgSprite);
        dbgDraw.m_sprite = m_sprite;
        dbgDraw.m_drawScale = 30.0;
        dbgDraw.m_fillAlpha = 1;
        dbgDraw.m_lineThickness = 1.0;
        dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
        m_world.SetDebugDraw(dbgDraw);*/
        
        contactListener = new ContactListener();
        m_world.SetContactListener(contactListener);
        
        TweenLite.to(gravity, 1,  { delay:1, x:0,y:0, ease:Back.easeOut } );
        //var t:GTween = new GTween(gravity, 1, { }, { delay:1, ease:fl.motion.easing.Back.easeOut } );
        //t.proxy.x = 0;
        //t.proxy.y = 0;
        
        setTimeout(SFX.powerDown.play, 1000, false);
        
        // Create border of boxes
        
        var bd:b2BodyDef;
        var circ:b2CircleDef = new b2CircleDef();
        var box:b2PolygonDef = new b2PolygonDef();
        var jd:b2RevoluteJointDef = new b2RevoluteJointDef();
        var friction:Number = 0.7;
        var restitiution :Number = 0.3;
        muscles = [];
        BodyParts = [];
        {
            var startX:Number = 250;
            var startY:Number = 200;
            
            // BODIES
            
            // Head
            circ.radius = 12.5 / m_physScale;
            circ.density = 1.0;
            circ.friction = friction;                
            circ.restitution = restitiution;
            //circ.filter.groupIndex = -1;
            bd = new b2BodyDef();
            bd.allowSleep = false;
            bd.position.Set(startX / m_physScale, (startY+3) / m_physScale);
            var head:b2Body = m_world.CreateBody(bd);
            head.m_userData = CreateHelmet(12.5);
            head.CreateShape(circ);
            head.SetMassFromShapes();
            BodyParts.push(head);
            
            // Torso1
            box.SetAsBox(20 / m_physScale, 10 / m_physScale);
            box.density = 1.0;
            box.friction = friction;                box.restitution = 0.1;
            //box.filter.groupIndex = -1;
            bd = new b2BodyDef();
            bd.position.Set(startX / m_physScale, (startY + 28) / m_physScale);
            var torso1:b2Body = m_world.CreateBody(bd);
            torso1.CreateShape(box);
            torso1.SetMassFromShapes();
            BodyParts.push(torso1);
            
            torso1.m_userData = CreateBoxSprite(CostumeColor,20,10);
            // Torso2
            box.SetAsBox(10 / m_physScale, 10 / m_physScale);
            bd = new b2BodyDef();
            bd.position.Set(startX / m_physScale, (startY + 43) / m_physScale);
            var torso2:b2Body = m_world.CreateBody(bd);
            torso2.CreateShape(box);
            torso2.SetMassFromShapes();
            torso2.m_userData = CreateBoxSprite(CostumeColor, 10, 10);
            BodyParts.push(torso2);
            // Torso3
            bd = new b2BodyDef();
            box.SetAsBox(15 / m_physScale, 10 / m_physScale);
            bd.position.Set(startX / m_physScale, (startY + 58) / m_physScale);
            var torso3:b2Body = m_world.CreateBody(bd);
            torso3.CreateShape(box);
            torso3.SetMassFromShapes();
            torso3.m_userData = CreateBoxSprite(CostumeColor, 15, 10);
            BodyParts.push(torso3);
            // UpperArm
            box.SetAsBox(18 / m_physScale, 6.5 / m_physScale);
            box.density = 1.0;
            box.friction = friction;                box.restitution = 0.1;
            //box.filter.groupIndex = -1;
            bd = new b2BodyDef();
            // L
            bd.position.Set((startX - 33) / m_physScale, (startY + 20) / m_physScale);
            var upperArmL:b2Body = m_world.CreateBody(bd);
            upperArmL.CreateShape(box);
            upperArmL.SetMassFromShapes();
            upperArmL.m_userData = CreateBoxSprite(CostumeColor, 18, 6.5);
            BodyParts.push(upperArmL);
            // R
            bd.position.Set((startX + 33) / m_physScale, (startY + 20) / m_physScale);
            var upperArmR:b2Body = m_world.CreateBody(bd);
            upperArmR.CreateShape(box);
            upperArmR.SetMassFromShapes();
            upperArmR.m_userData = CreateBoxSprite(CostumeColor, 18, 6.5);
            BodyParts.push(upperArmR);
            // LowerArm
            box.SetAsBox(18/ m_physScale, 6 / m_physScale);
            box.density = 1.0;
            box.friction = friction;                box.restitution = 0.1;
            //box.filter.groupIndex = -1;
            bd = new b2BodyDef();
            
            
            // L
            bd.position.Set((startX - 61) / m_physScale, (startY + 20) / m_physScale);
            var lowerArmL:b2Body = m_world.CreateBody(bd);
            lowerArmL.CreateShape(box);
            lowerArmL.SetMassFromShapes();
            lowerArmL.m_userData = CreateBoxSprite(CostumeColor, 17, 6);
            BodyParts.push(lowerArmL);
            // R
            bd.position.Set((startX + 61) / m_physScale, (startY + 20) / m_physScale);
            var lowerArmR:b2Body = m_world.CreateBody(bd);
            lowerArmR.CreateShape(box);
            lowerArmR.SetMassFromShapes();
            lowerArmR.m_userData = CreateBoxSprite(CostumeColor, 17, 6);
            BodyParts.push(lowerArmR);
            
            //palms
            
            
            
            // UpperLeg
            box.SetAsBox(8 / m_physScale, 24 / m_physScale);
            box.density = 2.0;
            box.friction = friction;                
            box.restitution = restitiution;
            box.filter.groupIndex = -1;
            bd = new b2BodyDef();
            // L
            bd.position.Set((startX - 8) / m_physScale, (startY + 86) / m_physScale);
            var upperLegL:b2Body = m_world.CreateBody(bd);
            upperLegL.CreateShape(box);
            upperLegL.SetMassFromShapes();
            upperLegL.m_userData = CreateBoxSprite(CostumeColor, 7.5, 22);
            BodyParts.push(upperLegL);
            // R
            bd.position.Set((startX + 8) / m_physScale, (startY + 86) / m_physScale);
            var upperLegR:b2Body = m_world.CreateBody(bd);
            upperLegR.CreateShape(box);
            upperLegR.SetMassFromShapes();
            upperLegR.m_userData = CreateBoxSprite(CostumeColor, 7.5, 22);
            BodyParts.push(upperLegR);
            // LowerLeg
            box.SetAsBox(7 / m_physScale, 26 / m_physScale);
            box.density = 2.0;
            box.friction = friction;                
            box.restitution = restitiution;
            box.filter.groupIndex = 0;
            bd = new b2BodyDef();
            // L
            bd.position.Set((startX - 7.5) / m_physScale, (startY + 127) / m_physScale);
            var lowerLegL:b2Body = m_world.CreateBody(bd);
            lowerLegL.CreateShape(box);
            lowerLegL.SetMassFromShapes();
            lowerLegL.m_userData =  CreateBoxSprite(CostumeColor, 8, 26);
            BodyParts.push(lowerLegL);
            // R
            bd.position.Set((startX + 7.5) / m_physScale, (startY + 127) / m_physScale);
            var lowerLegR:b2Body = m_world.CreateBody(bd);
            lowerLegR.CreateShape(box);
            lowerLegR.SetMassFromShapes();
            lowerLegR.m_userData = CreateBoxSprite(CostumeColor, 8, 26);
            BodyParts.push(lowerLegR);
            
            // JOINTS
            jd.enableLimit = true;

            jd.maxMotorTorque = 50.0;
            jd.motorSpeed     = 0.0;
            jd.enableMotor    = true;
            
            // Head to shoulders
            jd.lowerAngle = -40 / (180/Math.PI);
            jd.upperAngle = 40 / (180/Math.PI);
            jd.Initialize(torso1, head, new b2Vec2(startX / m_physScale, (startY + 15) / m_physScale));
            var neck:b2Joint = m_world.CreateJoint(jd);;
            muscles["neck"] = neck;
            
            var jointPointSize:Number = 6;
            
            neck.m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);

            
            // Upper arm to shoulders
            // L
            jd.maxMotorTorque = 300.0;
            jd.lowerAngle = -85 / (180/Math.PI);
            jd.upperAngle = 130 / (180/Math.PI);
            jd.Initialize(torso1, upperArmL, new b2Vec2((startX - 18) / m_physScale, (startY + 20) / m_physScale));
            muscles["LShoulder"] = m_world.CreateJoint(jd);
            muscles["LShoulder"].m_userData = CreateCircleSprite(0xFFFF00,jointPointSize,true,true);
            
            //jd.enableMotor    = false;
            // R
            jd.lowerAngle = -130 / (180/Math.PI);
            jd.upperAngle = 85 / (180/Math.PI);
            jd.Initialize(torso1, upperArmR, new b2Vec2((startX + 18) / m_physScale, (startY + 20) / m_physScale));
            muscles["RShoulder"] = m_world.CreateJoint(jd);
            muscles["RShoulder"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            // Lower arm to upper arm
            // L
            jd.lowerAngle = -130 / (180/Math.PI);
            jd.upperAngle = 130 / (180/Math.PI);
            jd.Initialize(upperArmL, lowerArmL, new b2Vec2((startX - 45) / m_physScale, (startY + 20) / m_physScale));
            muscles["LElbow"] = m_world.CreateJoint(jd);
            muscles["LElbow"].m_userData = CreateCircleSprite(0xFFFF00,jointPointSize,true,true);
            // R
            jd.lowerAngle = -130 / (180/Math.PI);
            jd.upperAngle = 130 / (180/Math.PI);
            jd.Initialize(upperArmR, lowerArmR, new b2Vec2((startX + 45) / m_physScale, (startY + 20) / m_physScale));
            muscles["RElbow"] = m_world.CreateJoint(jd);
            muscles["RElbow"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            // Shoulders/stomach
            jd.maxMotorTorque = 50.0;
            jd.lowerAngle = -15 / (180/Math.PI);
            jd.upperAngle = 15 / (180/Math.PI);
            jd.Initialize(torso1, torso2, new b2Vec2(startX / m_physScale, (startY + 35) / m_physScale));
            muscles["UPress"] = m_world.CreateJoint(jd);
            muscles["UPress"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            // Stomach/hips
            jd.Initialize(torso2, torso3, new b2Vec2(startX / m_physScale, (startY + 50) / m_physScale));
            muscles["DPress"] = m_world.CreateJoint(jd);
            muscles["DPress"].m_userData = CreateCircleSprite(0xFFFF00,jointPointSize,true,true);
            // Torso to upper leg
            // L
            jd.maxMotorTorque = 400.0;
            jd.lowerAngle = -25 / (180/Math.PI);
            jd.upperAngle = 135 / (180/Math.PI);
            jd.Initialize(torso3, upperLegL, new b2Vec2((startX - 8) / m_physScale, (startY + 72) / m_physScale));
            muscles["LLeg"] = m_world.CreateJoint(jd);
            muscles["LLeg"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            // R
            jd.lowerAngle = -135 / (180/Math.PI);
            jd.upperAngle = 25 / (180/Math.PI);
            jd.Initialize(torso3, upperLegR, new b2Vec2((startX + 8) / m_physScale, (startY + 72) / m_physScale));
            muscles["RLeg"] = m_world.CreateJoint(jd);
            muscles["RLeg"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            
            // Upper leg to lower leg
            // L
            jd.lowerAngle = -115 / (180/Math.PI);
            jd.upperAngle = 25 / (180/Math.PI);
            jd.Initialize(upperLegL, lowerLegL, new b2Vec2((startX - 8) / m_physScale, (startY + 105) / m_physScale));
            muscles["LKnee"] = m_world.CreateJoint(jd);
            muscles["LKnee"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
            // R
            jd.lowerAngle = -25 / (180/Math.PI);
            jd.upperAngle = 115 / (180/Math.PI);
            jd.Initialize(upperLegR, lowerLegR, new b2Vec2((startX + 8) / m_physScale, (startY + 105) / m_physScale));
            muscles["RKnee"] = m_world.CreateJoint(jd);
            muscles["RKnee"].m_userData = CreateCircleSprite(0xFFFF00, jointPointSize,true,true);
        }

        var texture:BitmapData = Textures.getShipAlloy(100, 100);
        CreateWall(0, 0, 50, 800, texture);
        CreateWall(0, 0, 1000, 50, texture);
        CreateWall(0, 800, 1050, 50, texture);    
        CreateWall(1000, 0, 50, 850, texture);    
        
        CreateWall(0, 400, 800, 30, texture);
        CreateWall(370, 0, 30, 200, texture);
        CreateWall(770, 200, 30, 200, texture);
        
        var boxPileStart:Number = 100;
        for (var i:uint = 0; i < 4; i++)
        {
            CreateBox(boxPileStart + i * 40, 370, 40, 40, 2,0.1, 0x220000);
        }
        for (i = 0; i < 3; i++)
        {
            CreateBox(boxPileStart + i * 40, 330, 40, 40, 2,0.1, 0x220000);
        }            
        CreateBox(boxPileStart+60, 290, 40, 40, 2,0.1, 0x220000);
        for (i = 0; i < 15; i++)
        {
            CreateBox(100+Math.random()*900, 100+Math.random()*700, Math.random()*50+50, 50+Math.random()*50,1,0.1, 0x440000).ApplyForce(new b2Vec2(Math.random()*5, Math.random()*5), new b2Vec2(Math.random()*5, Math.random()*5));
        }
        
        
            // button
            circ = new b2CircleDef();
            circ.radius = 12 / m_physScale;
            circ.isSensor = true;
            
            bd = new b2BodyDef();
            bd.position.Set(200/m_physScale, 600 / m_physScale);
            button = m_world.CreateBody(bd);
            button.m_userData = CreateButton(12);
            button.CreateShape(circ);
            button.SetMassFromShapes();
        
    }
    
    public function CreateBox(x:Number, y:Number, width:Number, height:Number, density:uint = 1,restitution:Number=0.1, color:uint = 0):b2Body
    {
        var bd:b2BodyDef;
        var box:b2PolygonDef = new b2PolygonDef();
        var jd:b2RevoluteJointDef = new b2RevoluteJointDef();
        var friction:Number = 0.7;
        var restitiution :Number = 0.3;
        bd = new b2BodyDef();
        bd.allowSleep = false;
        bd.position.Set((x+width*0.5) / m_physScale, (y+height*0.5) / m_physScale);
        box.SetAsBox(width*0.5 / m_physScale, height*0.5 / m_physScale);
        box.density = density;
        box.friction = friction;                
        box.restitution = restitution;
        var Box:b2Body = m_world.CreateBody(bd);
        Box.CreateShape(box);
        Box.SetMassFromShapes();
        Box.m_userData = CreateCrateSprite( width*0.5, height*0.5,0xDDDDDD);
        return Box;
    }
    
    public static function CreateCrateSprite(hWidth:Number, hHeight:Number,color:uint):Sprite
    {
        var sp:Sprite = new Sprite();
        var g:Graphics = sp.graphics;
        g.lineStyle(4,color,1,true);
        g.beginBitmapFill(Textures.getMetalWireTexture(color),null,true,true);
        g.drawRoundRect(-hWidth, -hHeight, hWidth * 2, hHeight * 2,13,13);
        g.endFill();
        sp.filters = [new DropShadowFilter(0, 45, 0, 1, 6, 6, 1.5, 1, true)]
        sp.cacheAsBitmap = true;
        return sp;
    }
    
    public function CreateWall(x:Number, y:Number, width:Number, height:Number, texture:BitmapData):void
    {
        var wallSd:b2PolygonDef = new b2PolygonDef();
        var wallBd:b2BodyDef = new b2BodyDef();
        var wallB:b2Body;
        
        //wallSd.
        
        wallBd.position.Set((x+width/2)/m_physScale, (y+height/2)/m_physScale);
        wallSd.SetAsBox(width*0.5/m_physScale, height*0.5/m_physScale);
        wallB = m_world.CreateBody(wallBd);
        wallB.CreateShape(wallSd);
        wallB.SetMassFromShapes();
        wallB.m_userData = new Rectangle(x, y, width, height);
    }
    
    
    public static function CreateCircleSprite(color:uint, r:Number, interactive:Boolean = false, line:Boolean = false ):Sprite
    {
        var res:Sprite = new Sprite();
        res.graphics.beginFill(color);
        res.graphics.drawCircle( 0, 0, r);
        res.graphics.endFill();
        if (line)
        {
            res.graphics.lineStyle(1, 0);
            res.graphics.moveTo(-r, 0);
            res.graphics.lineTo(r, 0);
        }
        res.buttonMode = res.mouseEnabled = res.mouseChildren = interactive;
        return res;
    }
    
    public static function CreateButton(r:Number):Sprite
    {
        var res:Sprite = new Sprite();
        res.graphics.beginFill(0x8080dd);
        res.graphics.drawCircle( 0, 0, r);
        res.graphics.endFill();
        res.graphics.beginFill(0xaa0000);
        res.graphics.drawCircle(0, 0, -r * 0.8);
        res.filters = [new DropShadowFilter()];
        return res;
    }
    
    public static function CreateHelmet(r:Number):Sprite
    {
        var res:Sprite = new Sprite();
        res.graphics.beginFill(CostumeColor);
        res.graphics.drawCircle( 0, 0, r);
        res.graphics.endFill();
        res.graphics.beginFill(0x0000aa);
        res.graphics.drawEllipse(-r*0.9, -r*0.7, r * 1.8, r * 1.6);
        res.graphics.endFill();
        res.graphics.beginFill(0xFFFFFF);
        res.graphics.drawCircle( -r * 0.4, -r * 0.2, r * 0.3);
        return res;
    }
    
    public static function CreateBoxSprite(color:uint, hWidth:Number, hHeight:Number,interactive:Boolean=false,texture:BitmapData=null):Sprite
    {
        var res:Sprite = new Sprite();
        if (texture)
            res.graphics.beginBitmapFill(texture);
        else
            res.graphics.beginFill(color);
        res.graphics.drawRect( -hWidth, -hHeight, hWidth * 2, hHeight * 2);
        res.buttonMode = res.mouseEnabled = res.mouseChildren = interactive;
        res.graphics.endFill();
        return res;
    }
    
    public function Update():void{
        var physStart:uint = getTimer();
        m_world.Step(m_timeStep, m_iterations);
    }
            
}
    
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.filters.BevelFilter;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.display.Graphics;
import flash.display.BlendMode;
import flash.geom.Matrix;
import flash.geom.Point;


class Textures 
{
    
    public static var bmd:BitmapData;
    public static var sp:Sprite = new Sprite();
    public static var blr:BlurFilter = new BlurFilter(2,2);
    public static var sp2:Sprite = new Sprite();
    public static var bmd2:BitmapData;
    public static var clrt:ColorTransform = new ColorTransform(0.9,0.9,0.9);
    public static var bvl:BevelFilter = new BevelFilter(4,45,0xE9D6CF,1,0x352726,1,4,4);
    public static var m:Matrix = new Matrix();
    
    public static function getStarSky(width:Number,height:Number):BitmapData
    {
        sp2.addChild(sp);
        bmd = new BitmapData(width,height,false,0);
        bmd2 =  new BitmapData(bmd.width,bmd.height,true,0);
        sp.graphics.clear();
        var space:Number = bmd.width*bmd.height;
        var g:Graphics = sp.graphics;
        g.beginFill(0xFFFFFF);
        var stars:Number = 10*space/10000;
        
        for(var i:uint = 0;i<stars;i++)
        {
            var size:Number = Math.random()*2;
            var xx:Number = Math.random()*(bmd.width-10)+5;
            var yy:Number = Math.random()*(bmd.width-10)+5;
            g.drawCircle(xx,yy,size);
        }
        sp.filters = [blr];

        bmd.draw(sp2);
        bmd2.fillRect(bmd2.rect,0);
        bmd2.perlinNoise(500,500,3,Math.random()*int.MAX_VALUE,true,true,7);
        bmd.draw(bmd2,null,null,BlendMode.MULTIPLY);
        bmd2.colorTransform(bmd2.rect,clrt);
        bmd.draw(bmd2,null,null,BlendMode.HARDLIGHT);
        return bmd;
    }
    
    public static function getMetalWireTexture(color:uint):BitmapData
    {
        var g:Graphics = sp.graphics;
        g.clear();
        g.beginFill(color);
        g.drawRect(-3,-3,23,21);
        g.drawCircle(0,7,3);
        g.drawCircle(8,7,3);
        g.drawCircle(16,7,3);
        g.drawCircle(4,0,3);
        g.drawCircle(12,0,3);
        g.drawCircle(4,14,3);
        g.drawCircle(12, 14, 3);
        m.tx = m.ty = 0;
        m.b = m.c = 0;
        m.a = m.d = 0.7;
        sp.filters = [new BevelFilter(4,45,0xffffff,1,0,1,6,6)];
        var bmd:BitmapData = new BitmapData(11,10,false,0);
        bmd.draw(sp, m);
        sp.filters = [];
        m.a = m.d = 1;
        return bmd;
    }
    
    public static function getShipAlloy(width:Number, height:Number, steps:Number = 3):BitmapData
    {
        bmd = new BitmapData(width,height,false,0);
        bmd2 =  new BitmapData(bmd.width*3, bmd.height*3, true, 0);
        
        bmd2.fillRect(bmd2.rect,0);
        bmd.fillRect(bmd.rect,0x605788);
        for(var k:uint = 0;k<steps;k++){
            
            sp.graphics.clear();
            var g:Graphics = sp.graphics;
            
            var rects:Number = 20;
        
                g.clear();
                for(var i:uint = 0;i<rects;i++)
                {
        
                    g.beginFill(0x605788);
                    if(Math.random()<0.6)
                        g.lineStyle(1,0x7B738F);
                    else
                        g.lineStyle(0,0,0);
                    var w:Number = Math.random()*20+10;
                    var h:Number = Math.random()*20+10;
                    var xx:Number = Math.random()*(bmd.width+10-w)-5;
                    var yy:Number = Math.random()*(bmd.width+10-h)-5;
                    g.drawRect(xx,yy,w,h);
                }
                
            for(i=0;i<3;i++)
            {
                for(var j:uint=0;j<3;j++)
                {
                    m.tx = bmd.width*i;
                    m.ty = bmd.height*j;
                    bmd2.draw(sp,m,null,BlendMode.HARDLIGHT);
                }
            }
            //bmd2.applyFilter(bmd2,bmd2.rect,new Point(),bvl);
            m.tx = -bmd.width;
            m.ty = -bmd.height;
            bmd.draw(bmd2,m);
        }
        return bmd;
    }
    
    
}

import Box2D.Collision.b2ContactPoint;
import Box2D.Dynamics.b2ContactListener;
import Box2D.Dynamics.Contacts.b2ContactResult;

/**
 * ...
 * @author EduardRuzga www.wonderwhy-er.com
 * Game made for LudumDare 21 compo
 */
class ContactListener extends b2ContactListener 
{

    public override function Add(point:b2ContactPoint) : void
    {
        // handle add point
        //trace("contact");
        var l:Number = point.velocity.Length();
        var i1:Boolean = SandBox._instance.BodyParts.indexOf(point.shape1.m_body) > 0;
        var i2:Boolean = SandBox._instance.BodyParts.indexOf(point.shape2.m_body) > 0;
        if ( i1 || i2 )
        {
            if (point.shape1.m_body == SandBox._instance.button || point.shape2.m_body == SandBox._instance.button)
            {

                Main._instance.ButtonPress();
                
            }
            else
            {
                //trace(l);
                if (l > 2 && (i1 != i2) )
                {
                    SFX.bodySound.play(l/10);
                }
            }
        }
        else
        {
            if (l > 2)
                SFX.crateSound.play(l/10);
        }
        
    }

    public override function Persist(point:b2ContactPoint) : void
    {
        // handle persist point

    }

    public override function Remove(point:b2ContactPoint) : void
    {
        // handle remove point

    }

    public override function Result(point:b2ContactResult) : void
    {
        // handle results
        
    }

}
    

class SFX 
{
    public static var bodySound:SfxrSynth;
    public static var crateSound:SfxrSynth;
    public static var powerUp:SfxrSynth;
    public static var powerDown:SfxrSynth;
    
    
    
    public static function init():void
    {
        bodySound = new SfxrSynth();
        bodySound.params.setSettingsString("3,,0.1022,,0.23,0.09,,-0.6283,,0.4,0.31,0.02,,,0.02,,,,1,,,,,0.34");
        bodySound.cacheSound();
        
        crateSound = new SfxrSynth();
        crateSound.params.setSettingsString("3,,0.1368,0.7009,0.16,0.0907,,0.1222,,,,,,,,,0.2074,-0.1865,1,,,,,0.17");
        crateSound.cacheSound();
        
        powerUp = new SfxrSynth();
        powerUp.params.setSettingsString("0,0.52,0.27,,0.81,0.2,,0.089,,,,,,0.5889,,,,,1,,,,,0.24");
        powerUp.cacheSound();
        
        powerDown = new SfxrSynth();
        powerDown.params.setSettingsString("0,0.09,0.1,,0.6,0.2,,0.089,,,,,,0.13,-0.48,,-0.04,,1,,,,-0.02,0.19");
        powerDown.cacheSound();
    }
    
}



import flash.display.Shape;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.getTimer;
/**
 * SfxrSynth
 * 
 * Copyright 2010 Thomas Vian
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @author Thomas Vian
 */
class SfxrSynth
{
    //--------------------------------------------------------------------------
    //
    //  Sound Parameters
    //
    //--------------------------------------------------------------------------
    
    private var _params:SfxrParams = new SfxrParams;    // Params instance
    
    private var _sound:Sound;                            // Sound instance used to play the sound
    private var _channel:SoundChannel;                    // SoundChannel instance of playing Sound
    
    private var _mutation:Boolean;                        // If the current sound playing or caching is a mutation
    
    private var _cachedWave:ByteArray;                    // Cached wave data from a cacheSound() call
    private var _cachingNormal:Boolean;                    // If the synth is caching a normal sound
    
    private var _cachingMutation:int;                    // Current caching ID
    private var _cachedMutation:ByteArray;                // Current caching wave data for mutation
    private var _cachedMutations:Vector.<ByteArray>;    // Cached mutated wave data
    private var _cachedMutationsNum:uint;                // Number of cached mutations
    private var _cachedMutationAmount:Number;            // Amount to mutate during cache
    
    private var _cachingAsync:Boolean;                    // If the synth is currently caching asynchronously
    private var _cacheTimePerFrame:uint;                // Maximum time allowed per frame to cache sound asynchronously
    private var _cachedCallback:Function;                // Function to call when finished caching asynchronously
    private var _cacheTicker:Shape;                        // Shape used for enterFrame event
    
    private var _waveData:ByteArray;                    // Full wave, read out in chuncks by the onSampleData method
    private var _waveDataPos:uint;                        // Current position in the waveData
    private var _waveDataLength:uint;                    // Number of bytes in the waveData
    private var _waveDataBytes:uint;                    // Number of bytes to write to the soundcard
    
    private var _original:SfxrParams;                    // Copied properties for mutation base
    
    //--------------------------------------------------------------------------
    //
    //  Synth Variables
    //
    //--------------------------------------------------------------------------
    
    private var _finished:Boolean;                        // If the sound has finished
    
    private var _masterVolume:Number;                    // masterVolume * masterVolume (for quick calculations)
    
    private var _waveType:uint;                            // The type of wave to generate
    
    private var _envelopeVolume:Number;                    // Current volume of the envelope
    private var _envelopeStage:int;                        // Current stage of the envelope (attack, sustain, decay, end)
    private var _envelopeTime:Number;                    // Current time through current enelope stage
    private var _envelopeLength:Number;                    // Length of the current envelope stage
    private var _envelopeLength0:Number;                // Length of the attack stage
    private var _envelopeLength1:Number;                // Length of the sustain stage
    private var _envelopeLength2:Number;                // Length of the decay stage
    private var _envelopeOverLength0:Number;            // 1 / _envelopeLength0 (for quick calculations)
    private var _envelopeOverLength1:Number;            // 1 / _envelopeLength1 (for quick calculations)
    private var _envelopeOverLength2:Number;            // 1 / _envelopeLength2 (for quick calculations)
    private var _envelopeFullLength:Number;                // Full length of the volume envelop (and therefore sound)
    
    private var _sustainPunch:Number;                    // The punch factor (louder at begining of sustain)
    
    private var _phase:int;                                // Phase through the wave
    private var _pos:Number;                            // Phase expresed as a Number from 0-1, used for fast sin approx
    private var _period:Number;                            // Period of the wave
    private var _periodTemp:Number;                        // Period modified by vibrato
    private var _maxPeriod:Number;                        // Maximum period before sound stops (from minFrequency)
    
    private var _slide:Number;                            // Note slide
    private var _deltaSlide:Number;                        // Change in slide
    private var _minFreqency:Number;                    // Minimum frequency before stopping
    
    private var _vibratoPhase:Number;                    // Phase through the vibrato sine wave
    private var _vibratoSpeed:Number;                    // Speed at which the vibrato phase moves
    private var _vibratoAmplitude:Number;                // Amount to change the period of the wave by at the peak of the vibrato wave
    
    private var _changeAmount:Number;                    // Amount to change the note by
    private var _changeTime:int;                        // Counter for the note change
    private var _changeLimit:int;                        // Once the time reaches this limit, the note changes
    
    private var _squareDuty:Number;                        // Offset of center switching point in the square wave
    private var _dutySweep:Number;                        // Amount to change the duty by
    
    private var _repeatTime:int;                        // Counter for the repeats
    private var _repeatLimit:int;                        // Once the time reaches this limit, some of the variables are reset
    
    private var _phaser:Boolean;                        // If the phaser is active
    private var _phaserOffset:Number;                    // Phase offset for phaser effect
    private var _phaserDeltaOffset:Number;                // Change in phase offset
    private var _phaserInt:int;                            // Integer phaser offset, for bit maths
    private var _phaserPos:int;                            // Position through the phaser buffer
    private var _phaserBuffer:Vector.<Number>;            // Buffer of wave values used to create the out of phase second wave
    
    private var _filters:Boolean;                        // If the filters are active
    private var _lpFilterPos:Number;                    // Adjusted wave position after low-pass filter
    private var _lpFilterOldPos:Number;                    // Previous low-pass wave position
    private var _lpFilterDeltaPos:Number;                // Change in low-pass wave position, as allowed by the cutoff and damping
    private var _lpFilterCutoff:Number;                    // Cutoff multiplier which adjusts the amount the wave position can move
    private var _lpFilterDeltaCutoff:Number;            // Speed of the low-pass cutoff multiplier
    private var _lpFilterDamping:Number;                // Damping muliplier which restricts how fast the wave position can move
    private var _lpFilterOn:Boolean;                    // If the low pass filter is active
    
    private var _hpFilterPos:Number;                    // Adjusted wave position after high-pass filter
    private var _hpFilterCutoff:Number;                    // Cutoff multiplier which adjusts the amount the wave position can move
    private var _hpFilterDeltaCutoff:Number;            // Speed of the high-pass cutoff multiplier
    
    private var _noiseBuffer:Vector.<Number>;            // Buffer of random values used to generate noise
    
    private var _superSample:Number;                    // Actual sample writen to the wave
    private var _sample:Number;                            // Sub-sample calculated 8 times per actual sample, averaged out to get the super sample
    private var _sampleCount:uint;                        // Number of samples added to the buffer sample
    private var _bufferSample:Number;                    // Another supersample used to create a 22050Hz wave
    
    private var _volumeM:Number = 1;
    public static var Mute:Boolean = false;
    //--------------------------------------------------------------------------
    //    
    //  Getters / Setters
    //
    //--------------------------------------------------------------------------
    
    /** The sound parameters */
    public function get params():SfxrParams { return _params; }
    public function set params(value:SfxrParams):void
    {
        _params = value;
        _params.paramsDirty = true;
    }
    
    //--------------------------------------------------------------------------
    //    
    //  Sound Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     * Plays the sound. If the parameters are dirty, synthesises sound as it plays, caching it for later. 
     * If they're not, plays from the cached sound. 
     * Won't play if caching asynchronously. 
     */
    public function play(volume:Number=1):void
    {
        if (Mute) return;
        _volumeM = volume;
        //trace(_params.getSettingsString());
        if (_cachingAsync) return;
        
        stop();
        
        _mutation = false;
        
        if (_params.paramsDirty || _cachingNormal || !_cachedWave) 
        {
            // Needs to cache new data
            _cachedWave = new ByteArray;
            _cachingNormal = true;
            _waveData = null;
            
            reset(true);
        }
        else
        {
            // Play from cached data
            _waveData = _cachedWave;
            _waveData.position = 0;
            _waveDataLength = _waveData.length;
            _waveDataBytes = 24576;
            _waveDataPos = 0; 
        }
        
        if (!_sound) (_sound = new Sound()).addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
        
        _channel = _sound.play();
    }
    
    /**
     * Plays a mutation of the sound.  If the parameters are dirty, synthesises sound as it plays, caching it for later. 
     * If they're not, plays from the cached sound. 
     * Won't play if caching asynchronously. 
     * @param    mutationAmount    Amount of mutation
     * @param    mutationsNum    The number of mutations to cache before picking from them
     */
    public function playMutated(mutationAmount:Number = 0.05, mutationsNum:uint = 15):void
    {
        stop();
        
        if (_cachingAsync) return;
        
        _mutation = true;
        
        _cachedMutationsNum = mutationsNum;
        
        if (_params.paramsDirty || !_cachedMutations) 
        {
            // New set of mutations
            _cachedMutations = new Vector.<ByteArray>();
            _cachingMutation = 0;
        }
        
        if (_cachingMutation != -1)
        {
            // Continuing caching new mutations
            _cachedMutation = new ByteArray;
            _cachedMutations[_cachingMutation] = _cachedMutation;
            _waveData = null;
            
            _original = _params.clone();
            _params.mutate(mutationAmount);
            reset(true);
        }
        else
        {
            // Play from random cached mutation
            _waveData = _cachedMutations[uint(_cachedMutations.length * Math.random())];
            _waveData.position = 0;
            _waveDataLength = _waveData.length;
            _waveDataBytes = 24576;
            _waveDataPos = 0;
        }
        
        if (!_sound) (_sound = new Sound()).addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
        
        _channel = _sound.play();
    }
    
    /**
     * Stops the currently playing sound
     */
    public function stop():void
    {
        if(_channel) 
        {
            _channel.stop();
            _channel = null;
        }
        
        if(_original)
        {
            _params.copyFrom(_original);
            _original = null;
        }
    }
    
    /**
     * If there is a cached sound to play, reads out of the data. 
     * If there isn't, synthesises new chunch of data, caching it as it goes. 
     * @param    e    SampleDataEvent to write data to
     */
    private function onSampleData(e:SampleDataEvent):void
    {
        if(_waveData)
        {
            if(_waveDataPos + _waveDataBytes > _waveDataLength) _waveDataBytes = _waveDataLength - _waveDataPos;
            
            if (_waveDataBytes > 0)
            {
                if(_volumeM==1)
                    e.data.writeBytes(_waveData, _waveDataPos, _waveDataBytes);
                else
                {
                    _waveData.position = _waveDataPos;
                    var floats:Number = _waveDataBytes / 4;
                    for (var i:uint = 0; i < floats; i++)
                    {
                        e.data.writeFloat(_waveData.readFloat() * _volumeM);
                    }
                }
            }
            
            _waveDataPos += _waveDataBytes;
        }
        else
        {    
            var length:uint;
            var l:uint;
            
            if (_mutation)
            {
                if (_original)
                {
                    _waveDataPos = _cachedMutation.position;
                    
                    if (synthWave(_cachedMutation, 3072, true))
                    {
                        _params.copyFrom(_original);
                        _original = null;
                        
                        _cachingMutation++;
                        
                        if ((length = _cachedMutation.length) < 24576)
                        {
                            // If the sound is smaller than the buffer length, add silence to allow it to play
                            _cachedMutation.position = length;
                            for(i = 0, l = 24576 - length; i < l; i++) _cachedMutation.writeFloat(0.0);
                        }
                        
                        if (_cachingMutation >= _cachedMutationsNum)
                        {
                            _cachingMutation = -1;
                        }
                    }
                    
                    _waveDataBytes = _cachedMutation.length - _waveDataPos;
                    
                    e.data.writeBytes(_cachedMutation, _waveDataPos, _waveDataBytes);
                }
            }
            else
            {
                if (_cachingNormal)
                {
                    _waveDataPos = _cachedWave.position;
                    
                    if (synthWave(_cachedWave, 3072, true))
                    {
                        if ((length = _cachedWave.length) < 24576)
                        {
                            // If the sound is smaller than the buffer length, add silence to allow it to play
                            _cachedWave.position = length;
                            for(i = 0, l = 24576 - length; i < l; i++) _cachedWave.writeFloat(0.0);
                        }
                        
                        _cachingNormal = false;
                    }
                    
                    _waveDataBytes = _cachedWave.length - _waveDataPos;
                    
                    e.data.writeBytes(_cachedWave, _waveDataPos, _waveDataBytes);
                }
            }
        }
    }
    
    //--------------------------------------------------------------------------
    //    
    //  Cached Sound Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     * Cache the sound for speedy playback. 
     * If a callback is passed in, the caching will be done asynchronously, taking maxTimePerFrame milliseconds 
     * per frame to cache, them calling the callback when it's done. 
     * If not, the whole sound is cached imidiately - can freeze the player for a few seconds, especially in debug mode. 
     * @param    callback            Function to call when the caching is complete
     * @param    maxTimePerFrame        Maximum time in milliseconds the caching will use per frame
     */
    public function cacheSound(callback:Function = null, maxTimePerFrame:uint = 5):void
    {
        stop();
        
        if (_cachingAsync) return;
        
        reset(true);
        
        _cachedWave = new ByteArray();
        
        if (Boolean(callback)) 
        {
            _mutation = false;
            _cachingNormal = true;
            _cachingAsync = true;
            _cacheTimePerFrame = maxTimePerFrame;
            
            _cachedCallback = callback;
            
            if (!_cacheTicker) _cacheTicker = new Shape;
            
            _cacheTicker.addEventListener(Event.ENTER_FRAME, cacheSection);
        }
        else
        {
            _cachingNormal = false;
            _cachingAsync = false;
            
            synthWave(_cachedWave, _envelopeFullLength, true);
            
            var length:uint = _cachedWave.length;
            
            if(length < 24576)
            {
                // If the sound is smaller than the buffer length, add silence to allow it to play
                _cachedWave.position = length;
                for(var i:uint = 0, l:uint = 24576 - length; i < l; i++) _cachedWave.writeFloat(0.0);
            }
        }
    }
    
    /**
     * Caches a series of mutations on the source sound. 
     * If a callback is passed in, the caching will be done asynchronously, taking maxTimePerFrame milliseconds 
     * per frame to cache, them calling the callback when it's done. 
     * If not, the whole sound is cached imidiately - can freeze the player for a few seconds, especially in debug mode. 
     * @param    mutationsNum        Number of mutations to cache
     * @param    mutationAmount        Amount of mutation
     * @param    callback            Function to call when the caching is complete
     * @param    maxTimePerFrame        Maximum time in milliseconds the caching will use per frame
     */
    public function cacheMutations(mutationsNum:uint, mutationAmount:Number = 0.05, callback:Function = null, maxTimePerFrame:uint = 5):void
    {
        stop();
        
        if (_cachingAsync) return;
        
        _cachedMutationsNum = mutationsNum;
        _cachedMutations = new Vector.<ByteArray>();
        
        if (Boolean(callback))
        {
            _mutation = true;
            
            _cachingMutation = 0;
            _cachedMutation = new ByteArray;
            _cachedMutations[0] = _cachedMutation;
            _cachedMutationAmount = mutationAmount;
            
            _original = _params.clone();
            _params.mutate(mutationAmount);
            
            reset(true);
            
            _cachingAsync = true;
            _cacheTimePerFrame = maxTimePerFrame;
            
            _cachedCallback = callback;
            
            if (!_cacheTicker) _cacheTicker = new Shape;
            
            _cacheTicker.addEventListener(Event.ENTER_FRAME, cacheSection);
        }
        else
        {
            var original:SfxrParams = _params.clone();
            
            for(var i:uint = 0; i < _cachedMutationsNum; i++)
            {
                _params.mutate(mutationAmount);
                cacheSound();
                _cachedMutations[i] = _cachedWave;
                _params.copyFrom(original);
            }
            
            _cachingMutation = -1;
        }
    }
    
    /**
     * Performs the asynchronous cache, working for up to _cacheTimePerFrame milliseconds per frame
     * @param    e    enterFrame event
     */
    private function cacheSection(e:Event):void 
    {
        var cacheStartTime:uint = getTimer();
        
        while (getTimer() - cacheStartTime < _cacheTimePerFrame)
        {
            if (_mutation)
            {
                _waveDataPos = _cachedMutation.position;
                
                if (synthWave(_cachedMutation, 500, true))
                {
                    _params.copyFrom(_original);
                    _params.mutate(_cachedMutationAmount);
                    reset(true);
                    
                    _cachingMutation++;
                    _cachedMutation = new ByteArray;
                    _cachedMutations[_cachingMutation] = _cachedMutation;
                    
                    if (_cachingMutation >= _cachedMutationsNum)
                    {
                        _cachingMutation = -1;
                        _cachingAsync = false;
                        
                        _params.paramsDirty = false;
                        
                        _cachedCallback();
                        _cachedCallback = null;
                        _cacheTicker.removeEventListener(Event.ENTER_FRAME, cacheSection);
                        
                        return;
                    }
                }
            }
            else
            {
                _waveDataPos = _cachedWave.position;
                
                if (synthWave(_cachedWave, 500, true))
                {
                    _cachingNormal = false;
                    _cachingAsync = false;
                    
                    _cachedCallback();
                    _cachedCallback = null;
                    _cacheTicker.removeEventListener(Event.ENTER_FRAME, cacheSection);
                    
                    return;
                }
            }
        }
    }
    
    //--------------------------------------------------------------------------
    //    
    //  Synth Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     * Resets the runing variables from the params
     * Used once at the start (total reset) and for the repeat effect (partial reset)
     * @param    totalReset    If the reset is total
     */
    private function reset(totalReset:Boolean):void
    {
        // Shorter reference
        var p:SfxrParams = _params;
        
        _period = 100.0 / (p.startFrequency * p.startFrequency + 0.001);
        _maxPeriod = 100.0 / (p.minFrequency * p.minFrequency + 0.001);
        
        _slide = 1.0 - p.slide * p.slide * p.slide * 0.01;
        _deltaSlide = -p.deltaSlide * p.deltaSlide * p.deltaSlide * 0.000001;
        
        if (p.waveType == 0)
        {
            _squareDuty = 0.5 - p.squareDuty * 0.5;
            _dutySweep = -p.dutySweep * 0.00005;
        }
        
        if (p.changeAmount > 0.0)     _changeAmount = 1.0 - p.changeAmount * p.changeAmount * 0.9;
        else                         _changeAmount = 1.0 + p.changeAmount * p.changeAmount * 10.0;
        
        _changeTime = 0;
        
        if(p.changeSpeed == 1.0)     _changeLimit = 0;
        else                         _changeLimit = (1.0 - p.changeSpeed) * (1.0 - p.changeSpeed) * 20000 + 32;
        
        if(totalReset)
        {
            p.paramsDirty = false;
            
            _masterVolume = p.masterVolume * p.masterVolume;
            
            _waveType = p.waveType;
            
            if (p.sustainTime < 0.01) p.sustainTime = 0.01;
            
            var totalTime:Number = p.attackTime + p.sustainTime + p.decayTime;
            if (totalTime < 0.18) 
            {
                var multiplier:Number = 0.18 / totalTime;
                p.attackTime *= multiplier;
                p.sustainTime *= multiplier;
                p.decayTime *= multiplier;
            }
            
            _sustainPunch = p.sustainPunch;
            
            _phase = 0;
            
            _minFreqency = p.minFrequency;
            
            _filters = p.lpFilterCutoff != 1.0 || p.hpFilterCutoff != 0.0;
            
            _lpFilterPos = 0.0;
            _lpFilterDeltaPos = 0.0;
            _lpFilterCutoff = p.lpFilterCutoff * p.lpFilterCutoff * p.lpFilterCutoff * 0.1;
            _lpFilterDeltaCutoff = 1.0 + p.lpFilterCutoffSweep * 0.0001;
            _lpFilterDamping = 5.0 / (1.0 + p.lpFilterResonance * p.lpFilterResonance * 20.0) * (0.01 + _lpFilterCutoff);
            if (_lpFilterDamping > 0.8) _lpFilterDamping = 0.8;
            _lpFilterDamping = 1.0 - _lpFilterDamping;
            _lpFilterOn = p.lpFilterCutoff != 1.0;
            
            _hpFilterPos = 0.0;
            _hpFilterCutoff = p.hpFilterCutoff * p.hpFilterCutoff * 0.1;
            _hpFilterDeltaCutoff = 1.0 + p.hpFilterCutoffSweep * 0.0003;
            
            _vibratoPhase = 0.0;
            _vibratoSpeed = p.vibratoSpeed * p.vibratoSpeed * 0.01;
            _vibratoAmplitude = p.vibratoDepth * 0.5;
            
            _envelopeVolume = 0.0;
            _envelopeStage = 0;
            _envelopeTime = 0;
            _envelopeLength0 = p.attackTime * p.attackTime * 100000.0;
            _envelopeLength1 = p.sustainTime * p.sustainTime * 100000.0;
            _envelopeLength2 = p.decayTime * p.decayTime * 100000.0 + 10;
            _envelopeLength = _envelopeLength0;
            _envelopeFullLength = _envelopeLength0 + _envelopeLength1 + _envelopeLength2;
            
            _envelopeOverLength0 = 1.0 / _envelopeLength0;
            _envelopeOverLength1 = 1.0 / _envelopeLength1;
            _envelopeOverLength2 = 1.0 / _envelopeLength2;
            
            _phaser = p.phaserOffset != 0.0 || p.phaserSweep != 0.0;
            
            _phaserOffset = p.phaserOffset * p.phaserOffset * 1020.0;
            if(p.phaserOffset < 0.0) _phaserOffset = -_phaserOffset;
            _phaserDeltaOffset = p.phaserSweep * p.phaserSweep * p.phaserSweep * 0.2;
            _phaserPos = 0;
            
            if(!_phaserBuffer) _phaserBuffer = new Vector.<Number>(1024, true);
            if(!_noiseBuffer) _noiseBuffer = new Vector.<Number>(32, true);
            
            for(var i:uint = 0; i < 1024; i++) _phaserBuffer[i] = 0.0;
            for(i = 0; i < 32; i++) _noiseBuffer[i] = Math.random() * 2.0 - 1.0;
            
            _repeatTime = 0;
            
            if (p.repeatSpeed == 0.0)     _repeatLimit = 0;
            else                         _repeatLimit = int((1.0-p.repeatSpeed) * (1.0-p.repeatSpeed) * 20000) + 32;
        }
    }
    
    /**
     * Writes the wave to the supplied buffer ByteArray
     * @param    buffer        A ByteArray to write the wave to
     * @param    waveData    If the wave should be written for the waveData
     * @return                If the wave is finished
     */
    private function synthWave(buffer:ByteArray, length:uint, waveData:Boolean = false, sampleRate:uint = 44100, bitDepth:uint = 16):Boolean
    {
        _finished = false;
        
        _sampleCount = 0;
        _bufferSample = 0.0;
        
        for(var i:uint = 0; i < length; i++)
        {
            if (_finished) return true;
            
            // Repeats every _repeatLimit times, partially resetting the sound parameters
            if(_repeatLimit != 0)
            {
                if(++_repeatTime >= _repeatLimit)
                {
                    _repeatTime = 0;
                    reset(false);
                }
            }
            
            // If _changeLimit is reached, shifts the pitch
            if(_changeLimit != 0)
            {
                if(++_changeTime >= _changeLimit)
                {
                    _changeLimit = 0;
                    _period *= _changeAmount;
                }
            }
            
            // Acccelerate and apply slide
            _slide += _deltaSlide;
            _period *= _slide;
            
            // Checks for frequency getting too low, and stops the sound if a minFrequency was set
            if(_period > _maxPeriod)
            {
                _period = _maxPeriod;
                if(_minFreqency > 0.0) _finished = true;
            }
            
            _periodTemp = _period;
            
            // Applies the vibrato effect
            if(_vibratoAmplitude > 0.0)
            {
                _vibratoPhase += _vibratoSpeed;
                _periodTemp = _period * (1.0 + Math.sin(_vibratoPhase) * _vibratoAmplitude);
            }
            
            _periodTemp = int(_periodTemp);
            if(_periodTemp < 8) _periodTemp = 8;
            
            // Sweeps the square duty
            if (_waveType == 0)
            {
                _squareDuty += _dutySweep;
                     if(_squareDuty < 0.0) _squareDuty = 0.0;
                else if (_squareDuty > 0.5) _squareDuty = 0.5;
            }
            
            // Moves through the different stages of the volume envelope
            if(++_envelopeTime > _envelopeLength)
            {
                _envelopeTime = 0;
                
                switch(++_envelopeStage)
                {
                    case 1: _envelopeLength = _envelopeLength1; break;
                    case 2: _envelopeLength = _envelopeLength2; break;
                }
            }
            
            // Sets the volume based on the position in the envelope
            switch(_envelopeStage)
            {
                case 0: _envelopeVolume = _envelopeTime * _envelopeOverLength0;                                     break;
                case 1: _envelopeVolume = 1.0 + (1.0 - _envelopeTime * _envelopeOverLength1) * 2.0 * _sustainPunch; break;
                case 2: _envelopeVolume = 1.0 - _envelopeTime * _envelopeOverLength2;                                 break;
                case 3: _envelopeVolume = 0.0; _finished = true;                                                     break;
            }
            
            // Moves the phaser offset
            if (_phaser)
            {
                _phaserOffset += _phaserDeltaOffset;
                _phaserInt = int(_phaserOffset);
                     if(_phaserInt < 0)     _phaserInt = -_phaserInt;
                else if (_phaserInt > 1023) _phaserInt = 1023;
            }
            
            // Moves the high-pass filter cutoff
            if(_filters && _hpFilterDeltaCutoff != 0.0)
            {
                _hpFilterCutoff *= _hpFilterDeltaCutoff;
                     if(_hpFilterCutoff < 0.00001)     _hpFilterCutoff = 0.00001;
                else if(_hpFilterCutoff > 0.1)         _hpFilterCutoff = 0.1;
            }
            
            _superSample = 0.0;
            for(var j:int = 0; j < 8; j++)
            {
                // Cycles through the period
                _phase++;
                if(_phase >= _periodTemp)
                {
                    _phase = _phase - _periodTemp;
                    
                    // Generates new random noise for this period
                    if(_waveType == 3) 
                    { 
                        for(var n:uint = 0; n < 32; n++) _noiseBuffer[n] = Math.random() * 2.0 - 1.0;
                    }
                }
                
                // Gets the sample from the oscillator
                switch(_waveType)
                {
                    case 0: // Square wave
                    {
                        _sample = ((_phase / _periodTemp) < _squareDuty) ? 0.5 : -0.5;
                        break;
                    }
                    case 1: // Saw wave
                    {
                        _sample = 1.0 - (_phase / _periodTemp) * 2.0;
                        break;
                    }
                    case 2: // Sine wave (fast and accurate approx)
                    {
                        _pos = _phase / _periodTemp;
                        _pos = _pos > 0.5 ? (_pos - 1.0) * 6.28318531 : _pos * 6.28318531;
                        _sample = _pos < 0 ? 1.27323954 * _pos + .405284735 * _pos * _pos : 1.27323954 * _pos - 0.405284735 * _pos * _pos;
                        _sample = _sample < 0 ? .225 * (_sample *-_sample - _sample) + _sample : .225 * (_sample * _sample - _sample) + _sample;
                        
                        break;
                    }
                    case 3: // Noise
                    {
                        _sample = _noiseBuffer[Math.min(uint(_phase * 32 / int(_periodTemp)),31)];
                        break;
                    }
                }
                
                // Applies the low and high pass filters
                if (_filters)
                {
                    _lpFilterOldPos = _lpFilterPos;
                    _lpFilterCutoff *= _lpFilterDeltaCutoff;
                         if(_lpFilterCutoff < 0.0) _lpFilterCutoff = 0.0;
                    else if(_lpFilterCutoff > 0.1) _lpFilterCutoff = 0.1;
                    
                    if(_lpFilterOn)
                    {
                        _lpFilterDeltaPos += (_sample - _lpFilterPos) * _lpFilterCutoff;
                        _lpFilterDeltaPos *= _lpFilterDamping;
                    }
                    else
                    {
                        _lpFilterPos = _sample;
                        _lpFilterDeltaPos = 0.0;
                    }
                    
                    _lpFilterPos += _lpFilterDeltaPos;
                    
                    _hpFilterPos += _lpFilterPos - _lpFilterOldPos;
                    _hpFilterPos *= 1.0 - _hpFilterCutoff;
                    _sample = _hpFilterPos;
                }
                
                // Applies the phaser effect
                if (_phaser)
                {
                    _phaserBuffer[_phaserPos&1023] = _sample;
                    _sample += _phaserBuffer[(_phaserPos - _phaserInt + 1024) & 1023];
                    _phaserPos = (_phaserPos + 1) & 1023;
                }
                
                _superSample += _sample;
            }
            
            // Averages out the super samples and applies volumes
            _superSample = _masterVolume * _envelopeVolume * _superSample * 0.125;
            
            // Clipping if too loud
                 if(_superSample > 1.0)     _superSample = 1.0;
            else if(_superSample < -1.0)     _superSample = -1.0;
            
            if(waveData)
            {
                // Writes same value to left and right channels
                buffer.writeFloat(_superSample);
                buffer.writeFloat(_superSample);
            }
            else
            {
                _bufferSample += _superSample;
                
                _sampleCount++;
                
                // Writes mono wave data to the .wav format
                if(sampleRate == 44100 || _sampleCount == 2)
                {
                    _bufferSample /= _sampleCount;
                    _sampleCount = 0;
                    
                    if(bitDepth == 16)     buffer.writeShort(int(32000.0 * _bufferSample));
                    else                 buffer.writeByte(_bufferSample * 127 + 128);
                    
                    _bufferSample = 0.0;
                }
            }
        }
        
        return false;
    }
    
    
    //--------------------------------------------------------------------------
    //    
    //  .wav File Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     * Returns a ByteArray of the wave in the form of a .wav file, ready to be saved out
     * @param    sampleRate        Sample rate to generate the .wav at    
     * @param    bitDepth        Bit depth to generate the .wav at    
     * @return                    Wave in a .wav file
     */
    public function getWavFile(sampleRate:uint = 44100, bitDepth:uint = 16):ByteArray
    {
        stop();
        
        reset(true);
        
        if (sampleRate != 44100) sampleRate = 22050;
        if (bitDepth != 16) bitDepth = 8;
        
        var soundLength:uint = _envelopeFullLength;
        if (bitDepth == 16) soundLength *= 2;
        if (sampleRate == 22050) soundLength /= 2;
        
        var filesize:int = 36 + soundLength;
        var blockAlign:int = bitDepth / 8;
        var bytesPerSec:int = sampleRate * blockAlign;
        
        var wav:ByteArray = new ByteArray();
        
        // Header
        wav.endian = Endian.BIG_ENDIAN;
        wav.writeUnsignedInt(0x52494646);        // Chunk ID "RIFF"
        wav.endian = Endian.LITTLE_ENDIAN;
        wav.writeUnsignedInt(filesize);            // Chunck Data Size
        wav.endian = Endian.BIG_ENDIAN;
        wav.writeUnsignedInt(0x57415645);        // RIFF Type "WAVE"
        
        // Format Chunk
        wav.endian = Endian.BIG_ENDIAN;
        wav.writeUnsignedInt(0x666D7420);        // Chunk ID "fmt "
        wav.endian = Endian.LITTLE_ENDIAN;
        wav.writeUnsignedInt(16);                // Chunk Data Size
        wav.writeShort(1);                        // Compression Code PCM
        wav.writeShort(1);                        // Number of channels
        wav.writeUnsignedInt(sampleRate);        // Sample rate
        wav.writeUnsignedInt(bytesPerSec);        // Average bytes per second
        wav.writeShort(blockAlign);                // Block align
        wav.writeShort(bitDepth);                // Significant bits per sample
        
        // Data Chunk
        wav.endian = Endian.BIG_ENDIAN;
        wav.writeUnsignedInt(0x64617461);        // Chunk ID "data"
        wav.endian = Endian.LITTLE_ENDIAN;
        wav.writeUnsignedInt(soundLength);        // Chunk Data Size
        
        synthWave(wav, _envelopeFullLength, false, sampleRate, bitDepth);
        
        wav.position = 0;
        
        return wav;
    }
}

    /**
     * SfxrParams
     * 
     * Copyright 2010 Thomas Vian
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     * 
     * @author Thomas Vian
     */
    class SfxrParams
    {
        //--------------------------------------------------------------------------
        //
        //  Properties
        //
        //--------------------------------------------------------------------------
        
        /** If the parameters have been changed since last time (shouldn't used cached sound) */
        public var paramsDirty:Boolean;    
        
        private var _waveType            :uint =     0;        // Shape of the wave (0:square, 1:saw, 2:sin or 3:noise)
        
        private var _masterVolume        :Number =     0.5;    // Overall volume of the sound (0 to 1)
        
        private var _attackTime            :Number =    0.0;    // Length of the volume envelope attack (0 to 1)
        private var _sustainTime        :Number =     0.0;    // Length of the volume envelope sustain (0 to 1)
        private var _sustainPunch        :Number =     0.0;    // Tilts the sustain envelope for more 'pop' (0 to 1)
        private var _decayTime            :Number =     0.0;    // Length of the volume envelope decay (yes, I know it's called release) (0 to 1)
        
        private var _startFrequency        :Number =     0.0;    // Base note of the sound (0 to 1)
        private var _minFrequency        :Number =     0.0;    // If sliding, the sound will stop at this frequency, to prevent really low notes (0 to 1)
        
        private var _slide                :Number =     0.0;    // Slides the note up or down (-1 to 1)
        private var _deltaSlide            :Number =     0.0;    // Accelerates the slide (-1 to 1)
        
        private var _vibratoDepth        :Number =     0.0;    // Strength of the vibrato effect (0 to 1)
        private var _vibratoSpeed        :Number =     0.0;    // Speed of the vibrato effect (i.e. frequency) (0 to 1)
        
        private var _changeAmount        :Number =     0.0;    // Shift in note, either up or down (-1 to 1)
        private var _changeSpeed        :Number =     0.0;    // How fast the note shift happens (only happens once) (0 to 1)
        
        private var _squareDuty            :Number =     0.0;    // Controls the ratio between the up and down states of the square wave, changing the tibre (0 to 1)
        private var _dutySweep            :Number =     0.0;    // Sweeps the duty up or down (-1 to 1)
        
        private var _repeatSpeed        :Number =     0.0;    // Speed of the note repeating - certain variables are reset each time (0 to 1)
        
        private var _phaserOffset        :Number =     0.0;    // Offsets a second copy of the wave by a small phase, changing the tibre (-1 to 1)
        private var _phaserSweep        :Number =     0.0;    // Sweeps the phase up or down (-1 to 1)
        
        private var _lpFilterCutoff        :Number =     0.0;    // Frequency at which the low-pass filter starts attenuating higher frequencies (0 to 1)
        private var _lpFilterCutoffSweep:Number =     0.0;    // Sweeps the low-pass cutoff up or down (-1 to 1)
        private var _lpFilterResonance    :Number =     0.0;    // Changes the attenuation rate for the low-pass filter, changing the timbre (0 to 1)
        
        private var _hpFilterCutoff        :Number =     0.0;    // Frequency at which the high-pass filter starts attenuating lower frequencies (0 to 1)
        private var _hpFilterCutoffSweep:Number =     0.0;    // Sweeps the high-pass cutoff up or down (-1 to 1)
        
        //--------------------------------------------------------------------------
        //
        //  Getters / Setters
        //
        //--------------------------------------------------------------------------
        
        /** Shape of the wave (0:square, 1:saw, 2:sin or 3:noise) */
        public function get waveType():uint { return _waveType; }
        public function set waveType(value:uint):void { _waveType = value > 3 ? 0 : value; paramsDirty = true; }
        
        /** Overall volume of the sound (0 to 1) */
        public function get masterVolume():Number { return _masterVolume; }
        public function set masterVolume(value:Number):void { _masterVolume = clamp1(value); paramsDirty = true; }
        
        /** Length of the volume envelope attack (0 to 1) */
        public function get attackTime():Number { return _attackTime; }
        public function set attackTime(value:Number):void { _attackTime = clamp1(value); paramsDirty = true; }
        
        /** Length of the volume envelope sustain (0 to 1) */
        public function get sustainTime():Number { return _sustainTime; }
        public function set sustainTime(value:Number):void { _sustainTime = clamp1(value); paramsDirty = true; }
        
        /** Tilts the sustain envelope for more 'pop' (0 to 1) */
        public function get sustainPunch():Number { return _sustainPunch; }
        public function set sustainPunch(value:Number):void { _sustainPunch = clamp1(value); paramsDirty = true; }
        
        /** Length of the volume envelope decay (yes, I know it's called release) (0 to 1) */
        public function get decayTime():Number { return _decayTime; }
        public function set decayTime(value:Number):void { _decayTime = clamp1(value); paramsDirty = true; }

        /** Base note of the sound (0 to 1) */
        public function get startFrequency():Number { return _startFrequency; }
        public function set startFrequency(value:Number):void { _startFrequency = clamp1(value); paramsDirty = true; }
        
        /** If sliding, the sound will stop at this frequency, to prevent really low notes (0 to 1) */
        public function get minFrequency():Number { return _minFrequency; }
        public function set minFrequency(value:Number):void { _minFrequency = clamp1(value); paramsDirty = true; }
        
        /** Slides the note up or down (-1 to 1) */
        public function get slide():Number { return _slide; }
        public function set slide(value:Number):void { _slide = clamp2(value); paramsDirty = true; }
        
        /** Accelerates the slide (-1 to 1) */
        public function get deltaSlide():Number { return _deltaSlide; }
        public function set deltaSlide(value:Number):void { _deltaSlide = clamp2(value); paramsDirty = true; }
        
        /** Strength of the vibrato effect (0 to 1) */
        public function get vibratoDepth():Number { return _vibratoDepth; }
        public function set vibratoDepth(value:Number):void { _vibratoDepth = clamp1(value); paramsDirty = true; }
        
        /** Speed of the vibrato effect (i.e. frequency) (0 to 1) */
        public function get vibratoSpeed():Number { return _vibratoSpeed; }
        public function set vibratoSpeed(value:Number):void { _vibratoSpeed = clamp1(value); paramsDirty = true; }
        
        /** Shift in note, either up or down (-1 to 1) */
        public function get changeAmount():Number { return _changeAmount; }
        public function set changeAmount(value:Number):void { _changeAmount = clamp2(value); paramsDirty = true; }
        
        /** How fast the note shift happens (only happens once) (0 to 1) */
        public function get changeSpeed():Number { return _changeSpeed; }
        public function set changeSpeed(value:Number):void { _changeSpeed = clamp1(value); paramsDirty = true; }
        
        /** Controls the ratio between the up and down states of the square wave, changing the tibre (0 to 1) */
        public function get squareDuty():Number { return _squareDuty; }
        public function set squareDuty(value:Number):void { _squareDuty = clamp1(value); paramsDirty = true; }
        
        /** Sweeps the duty up or down (-1 to 1) */
        public function get dutySweep():Number { return _dutySweep; }
        public function set dutySweep(value:Number):void { _dutySweep = clamp2(value); paramsDirty = true; }
        
        /** Speed of the note repeating - certain variables are reset each time (0 to 1) */
        public function get repeatSpeed():Number { return _repeatSpeed; }
        public function set repeatSpeed(value:Number):void { _repeatSpeed = clamp1(value); paramsDirty = true; }
        
        /** Offsets a second copy of the wave by a small phase, changing the tibre (-1 to 1) */
        public function get phaserOffset():Number { return _phaserOffset; }
        public function set phaserOffset(value:Number):void { _phaserOffset = clamp2(value); paramsDirty = true; }
        
        /** Sweeps the phase up or down (-1 to 1) */
        public function get phaserSweep():Number { return _phaserSweep; }
        public function set phaserSweep(value:Number):void { _phaserSweep = clamp2(value); paramsDirty = true; }
        
        /** Frequency at which the low-pass filter starts attenuating higher frequencies (0 to 1) */
        public function get lpFilterCutoff():Number { return _lpFilterCutoff; }
        public function set lpFilterCutoff(value:Number):void { _lpFilterCutoff = clamp1(value); paramsDirty = true; }
        
        /** Sweeps the low-pass cutoff up or down (-1 to 1) */
        public function get lpFilterCutoffSweep():Number { return _lpFilterCutoffSweep; }
        public function set lpFilterCutoffSweep(value:Number):void { _lpFilterCutoffSweep = clamp2(value); paramsDirty = true; }
        
        /** Changes the attenuation rate for the low-pass filter, changing the timbre (0 to 1) */
        public function get lpFilterResonance():Number { return _lpFilterResonance; }
        public function set lpFilterResonance(value:Number):void { _lpFilterResonance = clamp1(value); paramsDirty = true; }
        
        /** Frequency at which the high-pass filter starts attenuating lower frequencies (0 to 1) */
        public function get hpFilterCutoff():Number { return _hpFilterCutoff; }
        public function set hpFilterCutoff(value:Number):void { _hpFilterCutoff = clamp1(value); paramsDirty = true; }
        
        /** Sweeps the high-pass cutoff up or down (-1 to 1) */
        public function get hpFilterCutoffSweep():Number { return _hpFilterCutoffSweep; }
        public function set hpFilterCutoffSweep(value:Number):void { _hpFilterCutoffSweep = clamp2(value); paramsDirty = true; }
        
        //--------------------------------------------------------------------------
        //
        //  Generator Methods
        //
        //--------------------------------------------------------------------------
        
        /**
         * Sets the parameters to generate a pickup/coin sound
         */
        public function generatePickupCoin():void
        {
            resetParams();
            
            _startFrequency = 0.4 + Math.random() * 0.5;
            
            _sustainTime = Math.random() * 0.1;
            _decayTime = 0.1 + Math.random() * 0.4;
            _sustainPunch = 0.3 + Math.random() * 0.3;
            
            if(Math.random() < 0.5) 
            {
                _changeSpeed = 0.5 + Math.random() * 0.2;
                _changeAmount = 0.2 + Math.random() * 0.4;
            }
        }
        
        /**
         * Sets the parameters to generate a laser/shoot sound
         */
        public function generateLaserShoot():void
        {
            resetParams();
            
            _waveType = uint(Math.random() * 3);
            if(_waveType == 2 && Math.random() < 0.5) _waveType = uint(Math.random() * 2);
            
            _startFrequency = 0.5 + Math.random() * 0.5;
            _minFrequency = _startFrequency - 0.2 - Math.random() * 0.6;
            if(_minFrequency < 0.2) _minFrequency = 0.2;
            
            _slide = -0.15 - Math.random() * 0.2;
            
            if(Math.random() < 0.33)
            {
                _startFrequency = 0.3 + Math.random() * 0.6;
                _minFrequency = Math.random() * 0.1;
                _slide = -0.35 - Math.random() * 0.3;
            }
            
            if(Math.random() < 0.5) 
            {
                _squareDuty = Math.random() * 0.5;
                _dutySweep = Math.random() * 0.2;
            }
            else
            {
                _squareDuty = 0.4 + Math.random() * 0.5;
                _dutySweep =- Math.random() * 0.7;    
            }
            
            _sustainTime = 0.1 + Math.random() * 0.2;
            _decayTime = Math.random() * 0.4;
            if(Math.random() < 0.5) _sustainPunch = Math.random() * 0.3;
            
            if(Math.random() < 0.33)
            {
                _phaserOffset = Math.random() * 0.2;
                _phaserSweep = -Math.random() * 0.2;
            }
            
            if(Math.random() < 0.5) _hpFilterCutoff = Math.random() * 0.3;
        }
        
        /**
         * Sets the parameters to generate an explosion sound
         */
        public function generateExplosion():void
        {
            resetParams();
            _waveType = 3;
            
            if(Math.random() < 0.5)
            {
                _startFrequency = 0.1 + Math.random() * 0.4;
                _slide = -0.1 + Math.random() * 0.4;
            }
            else
            {
                _startFrequency = 0.2 + Math.random() * 0.7;
                _slide = -0.2 - Math.random() * 0.2;
            }
            
            _startFrequency *= _startFrequency;
            
            if(Math.random() < 0.2) _slide = 0.0;
            if(Math.random() < 0.33) _repeatSpeed = 0.3 + Math.random() * 0.5;
            
            _sustainTime = 0.1 + Math.random() * 0.3;
            _decayTime = Math.random() * 0.5;
            _sustainPunch = 0.2 + Math.random() * 0.6;
            
            if(Math.random() < 0.5)
            {
                _phaserOffset = -0.3 + Math.random() * 0.9;
                _phaserSweep = -Math.random() * 0.3;
            }
            
            if(Math.random() < 0.33)
            {
                _changeSpeed = 0.6 + Math.random() * 0.3;
                _changeAmount = 0.8 - Math.random() * 1.6;
            }
        }
        
        /**
         * Sets the parameters to generate a powerup sound
         */
        public function generatePowerup():void
        {
            resetParams();
            
            if(Math.random() < 0.5) _waveType = 1;
            else                     _squareDuty = Math.random() * 0.6;
            
            if(Math.random() < 0.5)
            {
                _startFrequency = 0.2 + Math.random() * 0.3;
                _slide = 0.1 + Math.random() * 0.4;
                _repeatSpeed = 0.4 + Math.random() * 0.4;
            }
            else
            {
                _startFrequency = 0.2 + Math.random() * 0.3;
                _slide = 0.05 + Math.random() * 0.2;
                
                if(Math.random() < 0.5)
                {
                    _vibratoDepth = Math.random() * 0.7;
                    _vibratoSpeed = Math.random() * 0.6;
                }
            }
            
            _sustainTime = Math.random() * 0.4;
            _decayTime = 0.1 + Math.random() * 0.4;
        }
        
        /**
         * Sets the parameters to generate a hit/hurt sound
         */
        public function generateHitHurt():void
        {
            resetParams();
            
            _waveType = uint(Math.random() * 3);
            if(_waveType == 2) _waveType = 3;
            else if(_waveType == 0) _squareDuty = Math.random() * 0.6;
            
            _startFrequency = 0.2 + Math.random() * 0.6;
            _slide = -0.3 - Math.random() * 0.4;
            
            _sustainTime = Math.random() * 0.1;
            _decayTime = 0.1 + Math.random() * 0.2;
            
            if(Math.random() < 0.5) _hpFilterCutoff = Math.random() * 0.3;
        }
        
        /**
         * Sets the parameters to generate a jump sound
         */
        public function generateJump():void
        {
            resetParams();
            
            _waveType = 0;
            _squareDuty = Math.random() * 0.6;
            _startFrequency = 0.3 + Math.random() * 0.3;
            _slide = 0.1 + Math.random() * 0.2;
            
            _sustainTime = 0.1 + Math.random() * 0.3;
            _decayTime = 0.1 + Math.random() * 0.2;
            
            if(Math.random() < 0.5) _hpFilterCutoff = Math.random() * 0.3;
            if(Math.random() < 0.5) _lpFilterCutoff = 1.0 - Math.random() * 0.6;
        }
        
        /**
         * Sets the parameters to generate a blip/select sound
         */
        public function generateBlipSelect():void
        {
            resetParams();
            
            _waveType = uint(Math.random() * 2);
            if(_waveType == 0) _squareDuty = Math.random() * 0.6;
            
            _startFrequency = 0.2 + Math.random() * 0.4;
            
            _sustainTime = 0.1 + Math.random() * 0.1;
            _decayTime = Math.random() * 0.2;
            _hpFilterCutoff = 0.1;
        }
        
        /**
         * Resets the parameters, used at the start of each generate function
         */
        protected function resetParams():void
        {
            paramsDirty = true;
            
            _waveType = 0;
            _startFrequency = 0.3;
            _minFrequency = 0.0;
            _slide = 0.0;
            _deltaSlide = 0.0;
            _squareDuty = 0.0;
            _dutySweep = 0.0;
            
            _vibratoDepth = 0.0;
            _vibratoSpeed = 0.0;
            
            _attackTime = 0.0;
            _sustainTime = 0.3;
            _decayTime = 0.4;
            _sustainPunch = 0.0;
            
            _lpFilterResonance = 0.0;
            _lpFilterCutoff = 1.0;
            _lpFilterCutoffSweep = 0.0;
            _hpFilterCutoff = 0.0;
            _hpFilterCutoffSweep = 0.0;
            
            _phaserOffset = 0.0;
            _phaserSweep = 0.0;
            
            _repeatSpeed = 0.0;
            
            _changeSpeed = 0.0;
            _changeAmount = 0.0;
        }
        
        //--------------------------------------------------------------------------
        //
        //  Randomize Methods
        //
        //--------------------------------------------------------------------------
        
        /**
         * Randomly adjusts the parameters ever so slightly
         */
        public function mutate(mutation:Number = 0.05):void
        {
            if (Math.random() < 0.5) startFrequency +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) minFrequency +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) slide +=                 Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) deltaSlide +=             Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) squareDuty +=             Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) dutySweep +=             Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) vibratoDepth +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) vibratoSpeed +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) attackTime +=             Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) sustainTime +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) decayTime +=             Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) sustainPunch +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) lpFilterCutoff +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) lpFilterCutoffSweep += Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) lpFilterResonance +=     Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) hpFilterCutoff +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) hpFilterCutoffSweep += Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) phaserOffset +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) phaserSweep +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) repeatSpeed +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) changeSpeed +=         Math.random() * mutation*2 - mutation;
            if (Math.random() < 0.5) changeAmount +=         Math.random() * mutation*2 - mutation;
        }
        
        /**
         * Sets all parameters to random values
         */
        public function randomize():void
        {
            paramsDirty = true;
            
            _waveType = uint(Math.random() * 4);
            
            _attackTime =          pow(Math.random()*2-1, 4);
            _sustainTime =      pow(Math.random()*2-1, 2);
            _sustainPunch =      pow(Math.random()*0.8, 2);
            _decayTime =          Math.random();

            _startFrequency =      (Math.random() < 0.5) ? pow(Math.random()*2-1, 2) : (pow(Math.random() * 0.5, 3) + 0.5);
            _minFrequency =      0.0;
            
            _slide =              pow(Math.random()*2-1, 5);
            _deltaSlide =          pow(Math.random()*2-1, 3);
            
            _vibratoDepth =      pow(Math.random()*2-1, 3);
            _vibratoSpeed =      Math.random()*2-1;
            
            _changeAmount =      Math.random()*2-1;
            _changeSpeed =      Math.random()*2-1;
            
            _squareDuty =          Math.random()*2-1;
            _dutySweep =          pow(Math.random()*2-1, 3);
            
            _repeatSpeed =      Math.random()*2-1;
            
            _phaserOffset =      pow(Math.random()*2-1, 3);
            _phaserSweep =      pow(Math.random()*2-1, 3);
            
            _lpFilterCutoff =          1 - pow(Math.random(), 3);
            _lpFilterCutoffSweep =     pow(Math.random()*2-1, 3);
            _lpFilterResonance =      Math.random()*2-1;
            
            _hpFilterCutoff =          pow(Math.random(), 5);
            _hpFilterCutoffSweep =     pow(Math.random()*2-1, 5);
            
            if(_attackTime + _sustainTime + _decayTime < 0.2)
            {
                _sustainTime = 0.2 + Math.random() * 0.3;
                _decayTime = 0.2 + Math.random() * 0.3;
            }
            
            if((_startFrequency > 0.7 && _slide > 0.2) || (_startFrequency < 0.2 && _slide < -0.05)) 
            {
                _slide = -_slide;
            }
            
            if(_lpFilterCutoff < 0.1 && _lpFilterCutoffSweep < -0.05) 
            {
                _lpFilterCutoffSweep = -_lpFilterCutoffSweep;
            }
        }
        
        //--------------------------------------------------------------------------
        //    
        //  Settings String Methods
        //
        //--------------------------------------------------------------------------
        
        /**
         * Returns a string representation of the parameters for copy/paste sharing
         * @return    A comma-delimited list of parameter values
         */
        public function getSettingsString():String
        {
            var string:String = String(waveType);
            string += "," + to4DP(_attackTime) +             "," + to4DP(_sustainTime) 
                    + "," + to4DP(_sustainPunch) +             "," + to4DP(_decayTime) 
                    + "," + to4DP(_startFrequency) +         "," + to4DP(_minFrequency)
                    + "," + to4DP(_slide) +                 "," + to4DP(_deltaSlide)
                    + "," + to4DP(_vibratoDepth) +             "," + to4DP(_vibratoSpeed)
                    + "," + to4DP(_changeAmount) +             "," + to4DP(_changeSpeed)
                    + "," + to4DP(_squareDuty) +             "," + to4DP(_dutySweep)
                    + "," + to4DP(_repeatSpeed) +             "," + to4DP(_phaserOffset)
                    + "," + to4DP(_phaserSweep) +             "," + to4DP(_lpFilterCutoff)
                    + "," + to4DP(_lpFilterCutoffSweep) +     "," + to4DP(_lpFilterResonance)
                    + "," + to4DP(_hpFilterCutoff)+         "," + to4DP(_hpFilterCutoffSweep)
                    + "," + to4DP(_masterVolume);        
            
            return string;
        }
        
        /**
         * Parses a settings string into the parameters
         * @param    string    Settings string to parse
         * @return            If the string successfully parsed
         */
        public function setSettingsString(string:String):Boolean
        {
            var values:Array = string.split(",");
            
            if (values.length != 24) return false;
            
            waveType =                 uint(values[0]) || 0;
            attackTime =              Number(values[1]) || 0;
            sustainTime =              Number(values[2]) || 0;
            sustainPunch =          Number(values[3]) || 0;
            decayTime =              Number(values[4]) || 0;
            startFrequency =          Number(values[5]) || 0;
            minFrequency =          Number(values[6]) || 0;
            slide =                  Number(values[7]) || 0;
            deltaSlide =              Number(values[8]) || 0;
            vibratoDepth =          Number(values[9]) || 0;
            vibratoSpeed =          Number(values[10]) || 0;
            changeAmount =          Number(values[11]) || 0;
            changeSpeed =              Number(values[12]) || 0;
            squareDuty =              Number(values[13]) || 0;
            dutySweep =              Number(values[14]) || 0;
            repeatSpeed =              Number(values[15]) || 0;
            phaserOffset =          Number(values[16]) || 0;
            phaserSweep =              Number(values[17]) || 0;
            lpFilterCutoff =          Number(values[18]) || 0;
            lpFilterCutoffSweep =      Number(values[19]) || 0;
            lpFilterResonance =      Number(values[20]) || 0;
            hpFilterCutoff =          Number(values[21]) || 0;
            hpFilterCutoffSweep =      Number(values[22]) || 0;
            masterVolume =             Number(values[23]) || 0;
            
            return true;
        }   
        
        
        //--------------------------------------------------------------------------
        //    
        //  Copying Methods
        //
        //--------------------------------------------------------------------------
        
        /**
         * Returns a copy of this SfxrParams with all settings duplicated
         * @return    A copy of this SfxrParams
         */
        public function clone():SfxrParams
        {
            var out:SfxrParams = new SfxrParams();
            out.copyFrom(this);        
            
            return out;
        }
        
        /**
         * Copies parameters from another instance
         * @param    params    Instance to copy parameters from
         */
        public function copyFrom(params:SfxrParams, makeDirty:Boolean = false):void
        {
            _waveType =             params.waveType;
            _attackTime =           params.attackTime;
            _sustainTime =          params.sustainTime;
            _sustainPunch =         params.sustainPunch;
            _decayTime =            params.decayTime;
            _startFrequency =         params.startFrequency;
            _minFrequency =         params.minFrequency;
            _slide =                 params.slide;
            _deltaSlide =             params.deltaSlide;
            _vibratoDepth =         params.vibratoDepth;
            _vibratoSpeed =         params.vibratoSpeed;
            _changeAmount =         params.changeAmount;
            _changeSpeed =             params.changeSpeed;
            _squareDuty =             params.squareDuty;
            _dutySweep =             params.dutySweep;
            _repeatSpeed =             params.repeatSpeed;
            _phaserOffset =         params.phaserOffset;
            _phaserSweep =             params.phaserSweep;
            _lpFilterCutoff =         params.lpFilterCutoff;
            _lpFilterCutoffSweep =     params.lpFilterCutoffSweep;
            _lpFilterResonance =     params.lpFilterResonance;
            _hpFilterCutoff =         params.hpFilterCutoff;
            _hpFilterCutoffSweep =     params.hpFilterCutoffSweep;
            _masterVolume =         params.masterVolume;
            
            if (makeDirty) paramsDirty = true;
        }   
        
        
        //--------------------------------------------------------------------------
        //
        //  Util Methods
        //
        //--------------------------------------------------------------------------
        
        /**
         * Clams a value to betwen 0 and 1
         * @param    value    Input value
         * @return            The value clamped between 0 and 1
         */
        private function clamp1(value:Number):Number { return (value > 1.0) ? 1.0 : ((value < 0.0) ? 0.0 : value); }
        
        /**
         * Clams a value to betwen -1 and 1
         * @param    value    Input value
         * @return            The value clamped between -1 and 1
         */
        private function clamp2(value:Number):Number { return (value > 1.0) ? 1.0 : ((value < -1.0) ? -1.0 : value); }
        
        /**
         * Quick power function
         * @param    base        Base to raise to power
         * @param    power        Power to raise base by
         * @return                The calculated power
         */
        private function pow(base:Number, power:int):Number
        {
            switch(power)
            {
                case 2: return base*base;
                case 3: return base*base*base;
                case 4: return base*base*base*base;
                case 5: return base*base*base*base*base;
            }
            
            return 1.0;
        }
        
        
        /**
         * Returns the number as a string to 4 decimal places
         * @param    value    Number to convert
         * @return            Number to 4dp as a string
         */
        private function to4DP(value:Number):String
        {
            if (value < 0.0001 && value > -0.0001) return "";
            
            var string:String = String(value);
            var split:Array = string.split(".");
            if (split.length == 1)     
            {
                return string;
            }
            else                     
            {
                var out:String = split[0] + "." + split[1].substr(0, 4);
                while (out.substr(out.length - 1, 1) == "0") out = out.substr(0, out.length - 1);
                
                return out;
            }
        }
    }