Easing interpolation curves for PD and Max/MSP mxj Java proxy
Article, in XXI Colloquio di Informatica Musicale proceedings, Cagliari 2016
Java classes, code, max8 help file
/* easing 1.0 by renato messina. Implemented functions: Linear, easeInBack, easeInBounce, easeInCircular, easeInCubic, easeInElastic, easeInExponential, easeInOutBack, easeInOutBounce, easeInOutCircular, easeInOutCubic, easeInOutElastic, easeInOutExponential, easeInOutQuadratic, easeInOutQuartic, easeInOutQuintic, easeInOutSine, easeInQuadratic, easeInQuartic, easeInQuintic, easeInSine, easeOutBack, easeOutBounce, easeOutCircular, easeOutCubic, easeOutElastic, easeOutExponential, easeOutQuadratic, easeOutQuartic, easeOutQuintic, easeOutSine */ import com.cycling74.max.*; import java.lang.reflect.*; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class easing extends MaxObject{ private static final String[] INLET_ASSIST = new String[]{ "inlet 1 help" }; private static final String[] OUTLET_ASSIST = new String[]{ "outlet 1 help" }; MaxClock nowClock; float begin; float change; float time; float duration=0; float result; float target = 0; float delta = 0; float outNow = 0; float diff = 0; float running=0; float runningNorm=0; double eased=0; String nomeFunzione = "Linear"; // default curve String funClass = "Curves"; Class c = Class.forName(funClass); Object obj = c.newInstance(); Method method; String alt=("stop"); int stopResult = 0; public easing(Atom[] args)throws Exception { declareInlets(new int[]{DataTypes.ALL,DataTypes.ALL}); declareOutlets(new int[]{DataTypes.ALL, DataTypes.ALL, DataTypes.ALL}); setInletAssist(new String[] { "Destination Value", "Ramp Time"}); setOutletAssist(new String[] { "Output Curve", "Normalized Output (0. to 1.)", "Bang When Curve Reaches Destination"}); // createInfoOutlet(false); nowmetro(); nowStop(); try { method = obj.getClass().getMethod(nomeFunzione, double.class); } catch (Throwable e) { System.err.println(e); } post("easing 1.0 by renato messina. Implemented functions: Linear, easeInBack, easeInBounce, easeInCircular, easeInCubic, easeInElastic, easeInExponential, easeInOutBack, easeInOutBounce, easeInOutCircular, easeInOutCubic, easeInOutElastic, easeInOutExponential, easeInOutQuadratic, easeInOutQuartic, easeInOutQuintic, easeInOutSine, easeInQuadratic, easeInQuartic, easeInQuintic, easeInSine, easeOutBack, easeOutBounce, easeOutCircular, easeOutCubic, easeOutElastic, easeOutExponential, easeOutQuadratic, easeOutQuartic, easeOutQuintic, easeOutSine"); } public void bang() { stopResult = 1; time=0; result--; begin = result; change = result+1; nowBang(); //<-----------START readOutput(); } public void inlet (int i) { stopResult=0; int inlet_no; inlet_no = getInlet(); if(inlet_no==0 & change!=i){ time=0; begin = result; change = i; nowBang(); //<-----------START } if(inlet_no==1 & i>=0){ duration = i; } readOutput(); // pick the current output } public void inlet(float f) { stopResult=0; int inlet_no; inlet_no = getInlet(); if(inlet_no==0 & change!=f){ time=0; begin = result; change = f; nowBang(); } if(inlet_no==1 & f>=0){ duration = f; } readOutput(); } ////////////////////////////////////////////////////// public void readOutput(){ outNow = result; diff = change-outNow; } ////////////////////////////////////////////////////// public void anything(String msg, Atom[] args){ nomeFunzione = msg; try{ updateCurve(); } catch (Throwable e) { System.err.println(e); } } public void list(Atom[] argsList){ Atom atomA = argsList[0]; Atom atomB = argsList[1]; Atom atomC = argsList[2]; if(argsList.length==4){ Atom atomD = argsList[3]; if(atomD.isFloat()){ result = atomD.getFloat(); } } if(atomA.isFloat()){ time=0; begin = result; change = atomA.getFloat(); } if(atomA.isInt()){ time=0; begin = result; change = atomA.getInt(); } if(atomB.isInt()){ duration = atomB.getInt(); } if(atomB.isFloat()){ duration = atomB.getFloat(); } if(atomC.isString()){ nomeFunzione = atomC.getString(); try{ updateCurve(); } catch (Throwable e) { System.err.println(e); } } stopResult=0; nowBang(); readOutput(); } public void stop(){ nowStop(); result=0; } public void updateCurve()throws Exception { try { method = obj.getClass().getMethod(nomeFunzione, double.class); } catch (Throwable e) { System.err.println(e); } } /// LINEAR INTERPOLATION START HERE (RIASSEMBLE THE MAX LINE OBJECT) ///////////////////// public void nowmetro() { nowClock = new MaxClock(new Callback(this, "nowBang")); } private void nowBang() { nowClock.delay(1.0); result = begin + (time/(((1/(change-begin)))*duration));//change-begin = target running = result-outNow; //2 runningNorm = running/diff; //3 //interpolation try { eased = ((Number)method.invoke(obj, runningNorm)).doubleValue(); // eased = (double)method.invoke(obj, runningNorm); } catch (Throwable e) { System.err.println(e); } //end interpolation outlet(1, eased); if(result==change){ nowStop();//<-----------------STOP outletBang(2); outlet(1, 1); } //..to avoid overshhoot if( begin<change & result>change){ nowStop();//<-----------------STOP result=change; outletBang(2); outlet(1, 1); } if(begin>change & result<change){ nowStop();//<-----------------STOP result = change; outletBang(2); outlet(1, 1); } time++; target=result; if(stopResult==0){ outlet(0, result); } } public void nowStart() { nowClock.delay(1.0); //set the clock to execute immediately } public void nowStop(){ nowClock.unset(); //stop the clock from executing } } ///////////////////////////////////////////////////// //()()()() ()()()() ()()()() ()()()() ()()()() ()()() ///////////////////////////////////////////////////// class Curves { public void main (double val) throws Exception { } private static final double PI_TIMES_2 = Math.PI * 2.0d; private static final double PI_OVER_2 = Math.PI / 2.0d; // public double easeInBack(double value) { return value * value * ((1.70158d + 1.0d) * value - 1.70158d); } // public double easeInBounce (double value){ return easeIn(value); } // public double easeInCircular (double value){ return -1.0d * (Math.sqrt(1.0d - Math.pow(value, 2.0d)) - 1.0d); } // public double easeInCubic (double value){ return Math.pow(value, 3.0d); } // public double easeInElastic (double value){ double s = 0.3d / 4.0d; double q = value - 1.0d; return -1.0d * (Math.pow(2.0, 10.0d * q) * Math.sin((q - s) * (PI_TIMES_2) / 0.3d)); } // public double easeInExponential (double value){ return Math.pow(2.0d, 10.0d * (value - 1.0d)); } // public double easeInOutBack (double value){ double v = 2.0d * value; double s = 1.70158d * 1.525d; if (v < 1.0d) { return 0.5d * (v * v * ((s + 1.0d) * v - s)); } v -= 2.0d; return 0.5d * (v * v * ((s + 1.0d) * v + s) + 2.0d); } // public double easeInOutBounce (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5d * easeIn(v); } return 0.5d * easeOut(v - 1.0d) + 0.5d; } // public double easeInOutCircular (double value){ double v = 2.0d * value; if (v < 1.0d) { return -0.5d * (Math.sqrt(1.0d - Math.pow(v, 2.0d)) - 1.0d); } v -= 2.0d; return 0.5d * (Math.sqrt(1.0d - Math.pow(v, 2.0d)) + 1.0d); } // public double easeInOutCubic (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5d * Math.pow(v, 3.0d); } v -= 2.0d; return 0.5d * (Math.pow(v, 3.0d) + 2.0d); } // public double easeInOutElastic (double value){ double p = 0.3 * 1.5d; double s = p / 4.0d; double q = 2.0d * value; if (q < 1.0d) { q -= 1.0d; return -0.5d * (Math.pow(2.0d, 10.0d * q) * Math.sin((q - s) * (PI_TIMES_2) / p)); } q -= 1.0d; return 0.5d * Math.pow(2.0, -10.0d * q) * Math.sin((q - s) * (PI_TIMES_2) / p) + 1.0d; } // public double easeInOutExponential (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5 * Math.pow(2.0d, 10.0d * (v - 1.0d)); } v -= 1.0d; return 0.5d * (-1.0d * Math.pow(2.0d, -10.0d * v) + 2.0d); } // public double easeInOutQuadratic (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5d * Math.pow(v, 2.0d); } v -= 1.0d; return -0.5d * (v * (v - 2.0d) - 1.0d); } // public double easeInOutQuartic (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5d * Math.pow(v, 4.0d); } v -= 2.0d; return -0.5d * (Math.pow(v, 4.0d) - 2.0d); } // public double easeInOutQuintic (double value){ double v = 2.0d * value; if (v < 1.0d) { return 0.5d * Math.pow(v, 5.0d); } v -= 2.0d; return 0.5d * (Math.pow(v, 5.0d) + 2.0d); } // public double easeInOutSine (double value){ return -0.5d * (Math.cos(value * Math.PI) - 1.0d); } // public double easeInQuadratic (double value){ return Math.pow(value, 2.0d); } // public double easeInQuartic (double value){ return Math.pow(value, 4.0d); } // public double easeInQuintic (double value){ return Math.pow(value, 5.0d); } // public double easeInSine (double value){ return -1.0d * Math.cos(value * PI_OVER_2) + 1.0d; } // public double easeOutBack (double value){ double v = value - 1.0d; return v * v * ((1.70158d + 1.0d) * v + 1.70158d) + 1.0d; } // public double easeOutBounce (double value){ return easeOut(value); } // public double easeOutCircular (double value){ return Math.sqrt(1.0d - Math.pow(value - 1.0d, 2.0)); } // public double easeOutCubic (double value){ return Math.pow(value - 1.0d, 3.0d) + 1.0d; } // public double easeOutElastic (double value){ double s = 0.3d / 4.0d; return Math.pow(2.0, -10.0d * value) * Math.sin((value - s) * (PI_TIMES_2) / 0.3d) + 1.0d; } // public double easeOutExponential (double value){ return -1.0d * Math.pow(2.0d, -10.0d * value) + 1.0d; } // public double easeOutQuadratic (double value){ return -1.0d * value * (value - 2.0d); } // public double easeOutQuartic (double value){ return -1.0d * (Math.pow(value - 1.0d, 4.0d) - 1.0d); } // public double easeOutQuintic (double value){ return Math.pow(value - 1.0d, 5.0d) + 1.0d; } // public double easeOutSine (double value){ return Math.sin(value * PI_OVER_2); } // public double Linear (double value){ return value; } // easeIn public double easeIn (double value){ return 1.0d - easeOut(1.0d - value); } // easeOut public double easeOut (double value){ if (value < (1.0d / 2.75d)) { return value * value * 7.5625d; } else if (value < (2.0d / 2.75d)) { double v = value - (1.5d / 2.75d); return v * v * 7.5625d + 0.75d; } else if (value < (2.5d / 2.75d)) { double v = value - (2.25d / 2.75d); return v * v * 7.5625d + 0.9375d; } double v = value - (2.625d / 2.75d); return v * v * 7.5625d + 0.984375d; } }