grame-cncm / faustlibraries

The Faust libraries
https://faustlibraries.grame.fr
183 stars 59 forks source link

Add bpf step functions #178

Closed DBraun closed 5 months ago

DBraun commented 5 months ago

This adds a step function feature to the bpf environment.

Demo (not for listening):

ba = library("basics.lib");
if = ba.if;

os = library("oscillators.lib");

bpf = environment
{
    // Start a break-point function
    start(x0,y0) = \(x).(x0,y0,x,y0);
    // Add a break-point
    point(x1,y1) = \(x0,y0,x,y).(x1, y1, x, if(x < x0, y, if(x < x1, y0 + (x-x0)*(y1-y0)/(x1-x0), y1)));
    // End a break-point function
    end(x1,y1) = \(x0,y0,x,y).(if(x < x0, y, if(x < x1, y0 + (x-x0)*(y1-y0)/(x1-x0), y1)));

    // Add a stepped "flat" section
    step(x1,y1) = \(x0,y0,x,y).(x1, y1, x, if(x < x0, y, if(x < x1, y0, y1)));
    // End with a stepped "flat" section
    step_end(x1,y1) = \(x0,y0,x,y).(if(x < x0, y, if(x < x1, y0, y1)));

    // Add a curve-point. `B` (compile-time constant) must be in range (0,1]
    curve(B,x1,y1) = \(x0,y0,x,y).(x1, y1, x, if(x < x0, y, if(x < x1, _curve_util(x0,x1,y0,y1,B,x), y1)));
    // End with a curve-point. `B` (compile-time constant) must be in range (0,1]
    curve_end(B,x1,y1) = \(x0,y0,x,y).(if(x < x0, y, if(x < x1, _curve_util(x0,x1,y0,y1,B,x), y1)));

    /*
    In the functions below, we use the equation `y=bias_curve(b,x)`.
    * `b`: bias in range (0,1]. Bias of 0.5 results in `y=x`. Bias above 0.5 pulls y upward. Bias below 0.5 pulls y downward.
    * `x`: input in range [0,1] that needs to be remapped/biased into `y`
    * `y`: `x` after it has been biased. Note that `(y==0 iff x==0) AND (y==1 iff x==1)`.
    */

    _bias_curve(b,x) = (x / ((((1.0/b) - 2.0)*(1.0 - x))+1.0));

    _curve_util(x0,x1,y0,y1,b,x) = y
    with {
        x_norm = (x-x0)/(x1-x0); // x_norm is in [0-1]
        y_norm = _bias_curve(b, x_norm); // y_norm is in [0-1]
        y = (1-y_norm)*y0 + y_norm*y1;  // linear interpolation between y0 and y1
    };
};

f(x) = x : bpf.start(0,0) : bpf.step(.2,.3) : bpf.step(.4,.6) : bpf.step_end(1,1);

process = os.lf_triangle(10*44100/8192) : _*.5+.5 : f;

Am I overloading the bpf environment too much? Or would anyone prefer doing this differently?

sletz commented 5 months ago

Merged, don't forget to raise version numbers in the concerned library and version.lib file. Thanks.