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;
}
}
