Hi, thanks everyone for the replies. Gen[n] and CurveTable are useful I will give them a try. If i'm not mistaken the curves generated this way pass through the intermediate points, so I was thinking of bezier curves because they pass in between the intermediate points and meet only the edges and they are smoother. Thanks for the code Mike! I looked at your technique and I have a couple of observations/questions. I guess you disconnect the envelope to save cpu when not needed. But you have the phasor in ( .op() == 0 ) - probably for the same reason - which I haven't verified it but according to the manual should still be active but giving output of 0 - so it wastes cpu, no? And shouldn't be needed to block the input since you use the multiplier's gain for it, no? I usually use the passthru status ( .op() == -1 ) which shouldn't use any cpu. I post part of my envelope class in case anybody would be interested in this way. Maybe too much for just an envelope but in long complicated code I find it really time saving to use this kind of 'secure' code: public class XEnvelope { Envelope envelope; UGen @ inputRef; UGen @ outputRef; // default status: passthru -1 => envelope.op; int isChucked; // 1 if connected both ways (left-right) int isOn; // 1 if envelope.op() == 1 int isRunning; // 1 while envelope is running 5 => int isBlocked; // if( isBlocked == 5 ) it is not blocked // otherwise it indicates the op status before blocked // connect input // if already connected, disconnect and connect the new one fun void leftChuck( UGen input ) { if( inputRef != NULL ) { leftUnchuck(); } input => envelope; input @=> inputRef; if( outputRef != NULL ) { 1 => isChucked; } } // connect to output // if already connected, disconnect and connect the new one fun void rightChuck( UGen output ) { if( outputRef != NULL ) { rightUnchuck(); } envelope => output; output @=> outputRef; if( inputRef != NULL ) { 1 => isChucked; } } // disconnect input fun void leftUnchuck() { if( inputRef != NULL ) { inputRef =< envelope; NULL @=> inputRef; 0 => isChucked; } } // disconnect output fun void rightUnchuck() { if( outputRef != NULL ) { envelope =< outputRef; NULL @=> outputRef; 0 => isChucked; } } // when blocking the envelope be careful not to change envelope.op // elsewhere. security will be enhanced in the future fun void block() { if( isBlocked == 5 ) { envelope.op() => isBlocked; 0 => envelope.op; } } fun void unblock() { if( isBlocked != 5 ) { isBlocked => envelope.op; 5 => isBlocked; } } // being OFF, turn on, run and hold // needs to be turned off in the end with 'off' fun void on( float start, float target, int milliseconds ) { if( isChucked && !isOn ) { 1 => isRunning => isOn => envelope.op; milliseconds::ms => envelope.duration; start => envelope.value; target => envelope.target; milliseconds::ms => now; 0 => isRunning; } else if( !isChucked ) { <<< "ERROR: can't turn the envelope on - not connected" >>>; } else if( isOn ) { <<< "ERROR: can't turn the envelope on - already on" >>>; } } // being OFF, turn on, run and hold // needs to be turned off in the end with 'off' fun void on( float start, float target, int milliseconds ) { if( isChucked && !isOn ) { 1 => isRunning => isOn => envelope.op; milliseconds::ms => envelope.duration; start => envelope.value; target => envelope.target; milliseconds::ms => now; 0 => isRunning; } else if( !isChucked ) { <<< "ERROR: can't turn the envelope on - not connected" >>>; } else if( isOn ) { <<< "ERROR: can't turn the envelope on - already on" >>>; } } // being ON, run to target and turn off fun void off( float target, int milliseconds ) { if( isOn && !isRunning ) { 1 => isRunning; milliseconds::ms => envelope.duration; target => envelope.target; milliseconds::ms => now; 0 => isRunning; -1 => envelope.op; 0 => isOn; } else if( !isOn ) { <<< "ERROR: can't turn the envelope off - already off" >>>; } else if( isRunning ) { <<< "ERROR: can't turn the envelope off - running" >>>; } } // being ON, move to next target fun void to( float target, int milliseconds ) { if( isOn && !isRunning ) { 1 => isRunning; milliseconds::ms => envelope.duration; target => envelope.target; milliseconds::ms => now; 0 => isRunning; } else if( !isOn ) { <<< "ERROR: can't move the envelope - envelope off" >>>; } else if( isRunning ) { <<< "ERROR: can't move the envelope - running" >>>; } } // being OFF, turn on, run and turn off fun void onOff( float start, float target, int milliseconds ) { if( isChucked && !isOn ) { 1 => isRunning => isOn => envelope.op; milliseconds::ms => envelope.duration; start => envelope.value; target => envelope.target; milliseconds::ms => now; -1 => envelope.op; 0 => isOn; 0 => isRunning; } else if( !isChucked ) { <<< "ERROR: can't turn the envelope on/off - not connected" >>>; } else if( isOn ) { <<< "ERROR: can't turn the envelope on/off - already on" >>>; } } } |