curve~ log/exp real values

Peter McCulloch's icon

Does anyone know how the curve factor for curve~ factors into
exponents? I'm working on a something where it would be really handy
to know what it actually translates as, and I'm assuming that curve~
is probably more efficient than pow~ + line~. (esp. since my values
are not 0-1)

The help file thanks Richard Dudas for the curve algorithm, any hints
to what it might be?

thanks,

Peter McCulloch

01ri's icon

I've also been searching on the internet for this. Does anyone know?

Thanks

01ri's icon
ch's icon

Sorry to wake up that old thread.

the link posted by 01ri is broken.

Anyone got some precisions about the formula used by curve~ ?

bazrush's icon

Please - can I bump this thread too. I've got some Max that now sounds great and I need to translate the thing into C++. Knowing the curve equation would be very handy! Anyone... ?
cheers, J.

Donald Undeen's icon

I've been working on this, and with some trial and error I've gotten close:

I think it's something like [apologies for mismatched parens, full code below]:

(1-e ^ (-1 * x( 1/ (1+ curve) ) - 1 ) )) / (1-e ^( -1 * ( 1/ (1+ curve) ) - 1 ) ))

When curve <0 ,and

(1-e ^ ( x( 1/ (1+ curve) ) - 1 ) )) / (1-e ^( ( 1/ (1+ curve) ) - 1 ) ))

when curve > 0

e is the constant 2.71828

The results aren't exactly the same for as the those from the function object, so maybe the value of e needs to be different?

I worked up some arduino test code that can take an input value x and an array representing the listdump from the function table in curve mode, and provide a result y.

my code assumes the function table input and output ranges are 0.0-1.0, not sure what happens if that changes...

// this is the output from the function object, in curve mode
float curvelist1[] = {0., 0.082569, 0., 0.192513, 0.174312, 0., 0.71123, 0.844037, -0.5, 1., 1., -0.65};
float curvelist2[] = {0., 0.082569, 0., 0.192513, 0.174312, 0., 0.71123, 0.844037, -0.75, 1., 1., -0.65}
float curvelist3[] = {0., 0.082569, 0., 0.192513, 0.174312, 0., 0.572193, 0.697248, -0.75, 1., 1., 0.};

void setup() {
  Serial.begin(9600);
  float x = 0.0;
  while (x <= 1.0){
    float y = functioncurve(x, curvelist2, 12);
    Serial.println(y);
    x = x + .01;
  }
}

float functioncurve(float x, float curvelist[] , int length){
  // where is x in the curvelist, ie which segment from the function object?
  int xindex = 0;
  while(xindex < length){
    float curx = curvelist[xindex];
    float nextx = curvelist[xindex + 3];
    if(x >= curx && x <= nextx ){
      break;
    }
    xindex = xindex + 3;
  }
  float minx = curvelist[xindex];
  float maxx = curvelist[xindex + 3];
  float miny = curvelist[xindex+1];
  float maxy = curvelist[xindex + 4];
  float curve = curvelist[xindex + 5];
  if(x == minx){
    return miny;
  }
  if(x == maxx){
    return maxy;
  }
  return curvescale(x, minx, maxx, miny, maxy, curve);

}

float curvescale(float x , float inmin, float inmax, float outmin, float outmax, float curve ){
  // treat input and output like it's scaled 0-1, then do the curve on it, then scale back to the output scaling
  float inscaled = floatmap(x, inmin, inmax, 0.0, 1.0);
  float outscaled = inscaled;
  if(curve < 0){
    outscaled = logscale(inscaled, curve);
  }else if (curve > 0){
    outscaled = expscale(inscaled, curve);
  }
  outscaled = floatmap(outscaled, 0.0, 1.0, outmin, outmax);
  return outscaled;
}

float floatmap(float in, float inmin, float inmax, float outmin, float outmax){
  // assume all values are 0-1
  float inrange = inmax - inmin;
  float outrange = outmax - outmin;
  float ratio = outrange / inrange;
  float inflat = in - inmin;
  float outflat = inflat * ratio;
  float out = outmin + outflat;
  return out;
}

float e = 2.71828; 
float logscale(float x, float curve){
  // assume input is 0-1.0
  float innerpow = (1 / (1+curve)) - 1;
  float pow1 =  pow(e, -1 * x * innerpow) ;
  float pow2 = pow(e, -1 * innerpow);
  float y = (1 - pow1) / (1 - pow2 );  
  return y;
}

float expscale(float x, float curve){
  // assume input is 0-1.0
  float innerpow = (1 / (1-curve)) - 1;
  float pow1 =  pow(e, x * innerpow) ;
  float pow2 = pow(e, innerpow);
  float y = (1 - pow1) / (1 - pow2 );  
  return y;
}

I hope this helps someone, or someone can take this and make it fit the function object output more precisely.

Roman Thilenius's icon


curve parameter 0.5 is about ~log 6, which is very strange (you would expect log2 or log10)

same issue as with kink~, paking... eh... poking around in the dark, as it is not documented.