View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide

Computing exponential curve factor given midpoint y value

Home   How To   Code Pool   Public Library   Theory   Events
The question was raised on the sc-users list how to calculate the curve factor for a ControlSpec or envelope segment, given 3 values:

(Here, considering mapping a [0..1] value by a ControlSpec, c)

y1 = c.map(0) – i.e., minval in the ControlSpec
y = c.map(0.5)
y2 = c.map(1) – i.e., maxval in the ControlSpec

If c = ControlSpec(0, 1, -2) (curve factor = -2), c.map(0.5) = 0.73105857863. What was desired is a way to calculate the curve factor given y1 = 0, y2 = 1, and y = 0.73105857863.

The way the curve factor is incorporated into the CurveWarp formula is not very obvious, but eventually it can be reduced to a quadratic equation. This function uses the quadratic formula to solve that equation for any y1, y and y2 where y1 < y < y2.

Some additional code had to be added because of numeric instability just above the midpoint between y1 and y2. If y < ((y1 + y2) * 0.5), everything works. Just slightly above, and the result can't be trusted. So the function compensates by mirroring values above the 2-point mean to the respective position below.

f = { |minval, midval, maxval|
    var a, b, c, sqrterm, qresult, sgn = sign(maxval - minval);
       // the formula is unstable just above the average of minval and maxval
       // so mirror the midval around the average
    (midval > ((maxval + minval) * 0.5)).if({
       midval = minval + maxval - midval;
       sgn = sgn.neg;
    });
    a = midval - minval;
    b = minval - maxval;
    c = maxval - midval;
    sqrterm = sqrt(b.squared - (4 * a * c));
    (((qresult = (sqrterm - b) / (2 * a))).abs != 1).if({
       log(qresult.squared).abs * sgn
    }, {
       log(((b.neg - sqrterm) / (2 * a)).squared).abs * sgn
    });
};

f.(0, 0.73105857863, 1) == -2

hjh

Links to this Page