/************************************************************************ ************************************************************************ FAUST library file Copyright (C) 2003-2012 GRAME, Centre National de Creation Musicale --------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. EXCEPTION TO THE LGPL LICENSE : As a special exception, you may create a larger FAUST program which directly or indirectly imports this library file and still distribute the compiled code generated by the FAUST compiler, or a modified version of this compiled code, under your own copyright and license. This EXCEPTION TO THE LGPL LICENSE explicitly grants you the right to freely choose the license for the resulting compiled code. In particular the resulting compiled code has no obligation to be LGPL or GPL. For example you are free to choose a commercial or closed source license or any other license if you decide so. ************************************************************************ ************************************************************************/ declare name "Music Library"; declare author "GRAME"; declare copyright "GRAME"; declare version "1.0"; declare license "LGPL with exception"; import("math.lib"); //----------------------------------------------- // DELAY LINE //----------------------------------------------- frac(n) = n-int(n); index(n) = &(n-1) ~ +(1); // n = 2**i //delay(n,d,x) = rwtable(n, 0.0, index(n), x, (index(n)-int(d)) & (n-1)); delay(n,d,x) = x@(int(d)&(n-1)); fdelay(n,d,x) = delay(n,int(d),x)*(1 - frac(d)) + delay(n,int(d)+1,x)*frac(d); delay1s(d) = delay(65536,d); delay2s(d) = delay(131072,d); delay5s(d) = delay(262144,d); delay10s(d) = delay(524288,d); delay21s(d) = delay(1048576,d); delay43s(d) = delay(2097152,d); fdelay1s(d) = fdelay(65536,d); fdelay2s(d) = fdelay(131072,d); fdelay5s(d) = fdelay(262144,d); fdelay10s(d) = fdelay(524288,d); fdelay21s(d) = fdelay(1048576,d); fdelay43s(d) = fdelay(2097152,d); millisec = SR/1000.0; time1s = hslider("time", 0, 0, 1000, 0.1)*millisec; time2s = hslider("time", 0, 0, 2000, 0.1)*millisec; time5s = hslider("time", 0, 0, 5000, 0.1)*millisec; time10s = hslider("time", 0, 0, 10000, 0.1)*millisec; time21s = hslider("time", 0, 0, 21000, 0.1)*millisec; time43s = hslider("time", 0, 0, 43000, 0.1)*millisec; echo1s = vgroup("echo 1000", +~(delay(65536, int(hslider("millisecond", 0, 0, 1000, 0.10)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); echo2s = vgroup("echo 2000", +~(delay(131072, int(hslider("millisecond", 0, 0, 2000, 0.25)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); echo5s = vgroup("echo 5000", +~(delay(262144, int(hslider("millisecond", 0, 0, 5000, 0.50)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); echo10s = vgroup("echo 10000", +~(delay(524288, int(hslider("millisecond", 0, 0, 10000, 1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); echo21s = vgroup("echo 21000", +~(delay(1048576, int(hslider("millisecond", 0, 0, 21000, 1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); echo43s = vgroup("echo 43000", +~(delay(2097152, int(hslider("millisecond", 0, 0, 43000, 1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0))); //--------------------------sdelay(N,it,dt)---------------------------- // s(mooth)delay : a mono delay that doesn't click and doesn't // transpose when the delay time is changed. It takes 4 input signals // and produces a delayed output signal // // USAGE : ... : sdelay(N,it,dt) : ... // // Where : // = maximal delay in samples (must be a constant power of 2, for example 65536) // = interpolation time (in samples) for example 1024 //
= delay time (in samples) // < > = input signal we want to delay //-------------------------------------------------------------------------- sdelay(N, it, dt) = ctrl(it,dt),_ : ddi(N) with { //---------------------------ddi(N,i,d0,d1)------------------------------- // DDI (Double Delay with Interpolation) : the input signal is sent to two // delay lines. The outputs of these delay lines are crossfaded with // an interpolation stage. By acting on this interpolation value one // can move smoothly from one delay to another. When is 0 we can // freely change the delay time of line 1, when it is 1 we can freely change // the delay time of line 0. // // = maximal delay in samples (must be a power of 2, for example 65536) // = interpolation value between 0 and 1 used to crossfade the outputs of the // two delay lines (0.0: first delay line, 1.0: second delay line) // = delay time of delay line 0 in samples between 0 and -1 // = delay time of delay line 1 in samples between 0 and -1 // < > = the input signal we want to delay //------------------------------------------------------------------------- ddi(N, i, d0, d1) = _ <: delay(N,d0), delay(N,d1) : interpolate(i); //----------------------------ctrl(it,dt)------------------------------------ // Control logic for a Double Delay with Interpolation according to two // // USAGE : ctrl(it,dt) // where : // an interpolation time (in samples, for example 256) //
a delay time (in samples) // // ctrl produces 3 outputs : an interpolation value and two delay // times and . These signals are used to control a ddi (Double Delay with Interpolation). // The principle is to detect changes in the input delay time dt, then to // change the delay time of the delay line currently unused and then by a // smooth crossfade to remove the first delay line and activate the second one. // // The control logic has an internal state controlled by 4 elements // : the interpolation variation (0, 1/it, -1/it) // : the interpolation value (between 0 and 1) // : the delay time of line 0 // : the delay time of line 1 // // Please note that the last stage (!,_,_,_) cut because it is only // used internally. //------------------------------------------------------------------------- ctrl(it, dt) = \(v,ip,d0,d1).( (nv, nip, nd0, nd1) with { // interpolation variation nv = if (v!=0.0, // if variation we are interpolating if( (ip>0.0) & (ip<1.0), v , 0), // should we continue or not ? if ((ip==0.0) & (dt!=d0), 1.0/it, // if true xfade from dl0 to dl1 if ((ip==1.0) & (dt!=d1), -1.0/it, // if true xfade from dl1 to dl0 0))); // nothing to change // interpolation value nip = ip+nv : min(1.0) : max(0.0); // update delay time of line 0 if needed nd0 = if ((ip >= 1.0) & (d1!=dt), dt, d0); // update delay time of line 0 if needed nd1 = if ((ip <= 0.0) & (d0!=dt), dt, d1); } ) ~ (_,_,_,_) : (!,_,_,_); }; //----------------------------------------------- // Tempo, beats and pulses //----------------------------------------------- tempo(t) = (60*SR)/t; // tempo(t) -> samples period(p) = %(int(p))~+(1); // signal en dent de scie de periode p pulse(t) = period(t)==0; // pulse (10000...) de periode p pulsen(n,t) = period(t)0. //----------------------------------------------- multirandom(n) = randomize(n) ~_ with { randomize (1) = +(12345) : *(1103515245); randomize (n) = randomize(1) <: randomize(n-1),_; }; //----------------------------------------------- // Generates multiple decorrelated noises // in parallel. Expects n>0. //----------------------------------------------- multinoise(n) = multirandom(n) : par(i,n,/(RANDMAX)) with { RANDMAX = 2147483647.0; }; //------------------------------------------------ noises(N,i) = multinoise(N) : selector(i,N); //----------------------------------------------- // osc(freq) : Sinusoidal Oscillator //----------------------------------------------- tablesize = 1 << 16; samplingfreq = SR; time = (+(1)~_ ) - 1; // 0,1,2,3,... sinwaveform = float(time)*(2.0*PI)/float(tablesize) : sin; decimal(x) = x - floor(x); phase(freq) = freq/float(samplingfreq) : (+ : decimal) ~ _ : *(float(tablesize)); osc(freq) = rdtable(tablesize, sinwaveform, int(phase(freq)) ); osci(freq) = s1 + d * (s2 - s1) with { i = int(phase(freq)); d = decimal(phase(freq)); s1 = rdtable(tablesize+1,sinwaveform,i); s2 = rdtable(tablesize+1,sinwaveform,i+1);}; //----------------------------------------------- // ADSR envelop //----------------------------------------------- // a,d,s,r = attack (sec), decay (sec), sustain (percentage of t), release (sec) // t = trigger signal ( >0 for attack, then release is when t back to 0) adsr(a,d,s,r,t) = env ~ (_,_) : (!,_) // the 2 'state' signals are fed back with { env (p2,y) = (t>0) & (p2|(y>=1)), // p2 = decay-sustain phase (y + p1*u - (p2&(y>s))*v*y - p3*w*y) // y = envelop signal *((p3==0)|(y>=eps)) // cut off tails to prevent denormals with { p1 = (p2==0) & (t>0) & (y<1); // p1 = attack phase p3 = (t<=0) & (y>0); // p3 = release phase // #samples in attack, decay, release, must be >0 na = SR*a+(a==0.0); nd = SR*d+(d==0.0); nr = SR*r+(r==0.0); // correct zero sustain level z = s+(s==0.0)*db2linear(-60); // attack, decay and (-60dB) release rates u = 1/na; v = 1-pow(z, 1/nd); w = 1-1/pow(z*db2linear(60), 1/nr); // values below this threshold are considered zero in the release phase eps = db2linear(-120); }; }; //----------------------------------------------- // Spatialisation //----------------------------------------------- panner(c) = _ <: *(1-c), *(c); bus2 = _,_; bus3 = _,_,_; bus4 = _,_,_,_; bus5 = _,_,_,_,_; bus6 = _,_,_,_,_,_; bus7 = _,_,_,_,_,_,_; bus8 = _,_,_,_,_,_,_,_; gain2(g) = *(g),*(g); gain3(g) = *(g),*(g),*(g); gain4(g) = *(g),*(g),*(g),*(g); gain5(g) = *(g),*(g),*(g),*(g),*(g); gain6(g) = *(g),*(g),*(g),*(g),*(g),*(g); gain7(g) = *(g),*(g),*(g),*(g),*(g),*(g),*(g); gain8(g) = *(g),*(g),*(g),*(g),*(g),*(g),*(g),*(g); //------------------------------------------------------ // // GMEM SPAT // n-outputs spatializer // implementation of L. Pottier // //------------------------------------------------------ // // n = number of outputs // r = rotation (between 0 et 1) // d = distance of the source (between 0 et 1) // //------------------------------------------------------ spat(n,a,d) = _ <: par(i, n, *( scaler(i, n, a, d) : smooth(0.9999) )) with { scaler(i,n,a,d) = (d/2.0+0.5) * sqrt( max(0.0, 1.0 - abs(fmod(a+0.5+float(n-i)/n, 1.0) - 0.5) * n * d) ); smooth(c) = *(1-c) : +~*(c); }; //--------------- Second Order Generic Transfert Function ------------------------- // TF2(b0,b1,b2,a1,a2) // //--------------------------------------------------------------------------------- TF2(b0,b1,b2,a1,a2) = sub ~ conv2(a1,a2) : conv3(b0,b1,b2) with { conv3(k0,k1,k2,x) = k0*x + k1*x' + k2*x''; conv2(k0,k1,x) = k0*x + k1*x'; sub(x,y) = y-x; }; /*************************** Break Point Functions *************************** bpf is an environment (a group of related definitions) tha can be used to create break-point functions. It contains three functions : - start(x,y) to start a break-point function - end(x,y) to end a break-point function - point(x,y) to add intermediate points to a break-point function A minimal break-point function must contain at least a start and an end point : f = bpf.start(x0,y0) : bpf.end(x1,y1); A more involved break-point function can contains any number of intermediate points f = bpf.start(x0,y0) : bpf.point(x1,y1) : bpf.point(x2,y2) : bpf.end(x3,y3); In any case the x_{i} must be in increasing order (for all i, x_{i} < x_{i+1}) For example the following definition : f = bpf.start(x0,y0) : ... : bpf.point(xi,yi) : ... : bpf.end(xn,yn); implements a break-point function f such that : f(x) = y_{0} when x < x_{0} f(x) = y_{n} when x > x_{n} f(x) = y_{i} + (y_{i+1}-y_{i})*(x-x_{i})/(x_{i+1}-x_{i}) when x_{i} <= x and x < x_{i+1} ******************************************************************************/ 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))); // definition of if if (c,t,e) = select2(c,e,t); };