flash on 2011-7-9

by ersin
♥0 | Line 158 | Modified 2011-07-09 05:54:35 | MIT License
play

ActionScript3 source code

/**
 * Copyright ersin ( http://wonderfl.net/user/ersin )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/9pfA
 */




package Hyperion.Modules.Envelope {
    
    import Hyperion.*;
    import Hyperion.GUI.*;
    import Hyperion.Modules.*;
    
    import flash.utils.*;
    
    public class Envelope extends Module {
        
        public var outSock_mc:Socket;
        public var lenSock_mc:Socket;
        
        private var outputPin:OutputPin;
        private var lenPin:InputPin;
        
        private var _length:uint;
        
        internal var points:Vector.<EnvelopePoint>;
        internal var sustainPointIndex:uint;
        
        private var progress:uint;
        private var currentPointIndex:uint;
        
        public var leadInEatsTime:Boolean=true;
        public var leadOutEatsTime:Boolean=true;
        
        internal var adsrData:Object;
        
        static var count:uint=0;
        var id:uint;
        
        public function Envelope(s:Synth) {
            super(s);
            
            id=count++;
            
            lenPin=new InputPin(this);
            lenPin.dataType=Pin.Length | Pin.Time | Pin.Pushed;
            lenPin.socket=lenSock_mc;
            lenPin.addEventListener(PinEvent.Pushed,lenPush);
            inputPins.push(lenPin);
            
            outputPin=new OutputPin(this,rend,outputPinReady);
            outputPin.dataType=Pin.SoundWave | Pin.Mono | Pin.FreqWave;
            outputPin.socket=outSock_mc;
            outputPins.push(outputPin);
            
            points=new Vector.<EnvelopePoint>();
            
            initADSR(1200,1,1200,0.6,1200);
        }
        
        public override function get configDialogClass():Class {
            return EnvelopeConfig;
        }
        
        private function lenPush(e:PinEvent):void {
            length=lenPin.value;
        }
        
        public function set length (s:uint) {
            _length=s;
            scalePoints(s);
        }
        
        public function get length ():uint {
            return _length;
        }
        
        public override function reset():void {
            
            trace("reset",id);
            
            progress=0;
            currentPointIndex=0;
            
            if(lenPin.con && lenPin.con.readyToPlay() && !Boolean(lenPin.con.type & Pin.Pushed)) {
                lenPin.con.pullValue();
            }
            
            scalePoints(_length);
            
            super.reset();
        }
        
        public override function get saveData():* {
            if(adsrData) {
                return { mode: "adsr", adsrData: adsrData };
            } else {
                var pointsArray:Array=new Array(points.length);
                for(var i:uint=0;i<points.length;++i) {
                    pointsArray[i]={ value: points[i].value, length: points[i].length };
                }
                return { mode: "points", points: pointsArray };
            }
        }
        
        public override function set saveData(d:*):void {
            if(d.mode=="adsr") {
                initADSR(
                    d.adsrData.attackTime,
                    d.adsrData.attackValue,
                    d.adsrData.decayTime,
                    d.adsrData.holdValue,
                    d.adsrData.releaseTime
                );
            }
        }
        
        public function initADSR(attackTime:uint,attackValue:Number,decayTime:uint,holdValue:Number,releaseTime:uint):void {
            points=new Vector.<EnvelopePoint>(5);
            
            points[0]=new EnvelopePoint(0,0);
            points[1]=new EnvelopePoint(attackValue,attackTime);
            points[2]=new EnvelopePoint(holdValue,decayTime);
            points[3]=new EnvelopePoint(holdValue,42);
            points[4]=new EnvelopePoint(0,releaseTime);
            
            points.fixed=true;
            
            sustainPointIndex=3;
            
            adsrData={ attackTime: attackTime, attackValue: attackValue, decayTime: decayTime, holdValue: holdValue, releaseTime: releaseTime };
        }
        
        internal function scalePoints(timeForSustain:int):void {
            var scaledPosition:uint=0;
            var point:EnvelopePoint;
            var lengthToSustainPoint:uint;
            var lengthFromSustainPoint:uint;
            
            trace("scaling",timeForSustain,id);
            
            for(var i:uint=0;i<points.length;++i) {
                point=points[i];
                
                if(i<sustainPointIndex) {
                    lengthToSustainPoint+=point.length;
                }
                
                if(i>sustainPointIndex) {
                    lengthFromSustainPoint+=point.length;
                }
            }
            
            if(leadInEatsTime) {
                timeForSustain-=lengthToSustainPoint;
            }
            
            if(leadOutEatsTime) {
                timeForSustain-=lengthFromSustainPoint;
            }
            
            if(timeForSustain<0) timeForSustain=0;
            
            var scaledPosition:uint=0;
            
            for(i=0;i<points.length;++i) {
                point=points[i];
                
                if(i==sustainPointIndex) {
                    point.length=timeForSustain;
                }
                
                point.scaledPosition=scaledPosition;
                
                scaledPosition+=point.length;
            }
        }
        
        private function rend(b:ByteArray,s:uint):uint {
            
            trace("process:",progress,id);
            
            rendloop: for(var i:uint=0;i<s;++i) {
                
                var currentPoint:EnvelopePoint;
                var localProgress:uint;
                
                for(;;) {
                    currentPoint=points[currentPointIndex];
                    localProgress=progress-currentPoint.scaledPosition;
                    
                    if(localProgress<currentPoint.length) break;
                    
                    
                    ++currentPointIndex;
                    
                    trace("next point is:",currentPointIndex,progress,id);
                    
                    if(currentPointIndex>=points.length) break rendloop;
                }
                
                var ratio:Number=Number(localProgress)/currentPoint.length;
                
                var prevPoint:EnvelopePoint=points[currentPointIndex-1];
                
                var sample:Number=prevPoint.value*(1-ratio)+currentPoint.value*ratio;
                
                b.writeFloat(sample);
                
                ++progress;
            }
            
            return i;
        }
        
        
        private function outputPinReady() {
            return points.length>1;
        }
        
        public override function destroy():void {
            
            outputPin.destroy();
            outputPin=null;
            
            lenPin.removeEventListener(PinEvent.Pushed,lenPush);
            lenPin.destroy();
            lenPin=null;
            
            points=null;
            
            super.destroy();
        }
    }
}