+++ /dev/null
-//instrument.lib - Faust function of various types usefull for building physical model instruments
-
-declare name "Faust-STK Tools Library";
-declare author "Romain Michon (rmichon@ccrma.stanford.edu)";
-declare copyright "Romain Michon";
-declare version "1.0";
-declare licence "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license);
-
-import("math.lib");
-import("filter.lib");
-import("effect.lib");
-
-//========================= ENVELOPE GENERATORS ===============================
-
-//----------------------- VIBRATO ENVELOPE ----------------------------
-// 4 phases envelope to control vibrato gain
-//
-// USAGE:
-// _ : *(envVibrato(b,a,s,r,t)) : _
-// where
-// b = beginning duration (silence) in seconds
-// a = attack duration in seconds
-// s = sustain as a percentage of the amplitude to be modified
-// r = release duration in seconds
-// t = trigger signal
-
-envVibrato(b,a,s,r,t) = env ~ (_,_,_) : (!,!,_) // the 3 'state' signals are fed back
-with {
- env (p2,cnt,y) =
- (t>0) & (p2|(y>=1)),
- (cnt + 1)*(t>0), // counter for the first step "b"
- (y + p1*p3*u*(s/100) - p4*w*y)*((p4==0)|(y>=eps)) // y = envelop signal
- //*(y>=eps) // cut off tails to prevent denormals
- with {
- p1 = (p2==0) & (t>0) & (y<1) & (cnt>(b*SR)); // p1 = attack phase
- p3 = 1-(cnt<(nb)); // p3 = beginning phase
- p4 = (t<=0) & (y>0); // p4 = release phase
- // #samples in attack, release, must be >0
- nb = SR*b+(b==0.0) ; na = SR*a+(a==0.0); nr = SR*r+(r==0.0);
- // attack and (-60dB) release rates
- z = s+(s==0.0)*db2linear(-60);
- u = 1/na; w = 1-1/pow(z*db2linear(60), 1/nr);
- // values below this threshold are considered zero in the release phase
- eps = db2linear(-120);
- };
-};
-
-//----------------------- ATTACK - SUSTAIN - RELEASE ----------------------------
-// Attack - Sustain - Release envelope
-//
-// USAGE:
-// _ : *(asr(a,s,r,t)) : _
-// where
-// a = attack duration in seconds
-// s = sustain as a percentage of the amplitude to be modified
-// r = release duration in seconds
-// t = trigger signal
-
-asr(a,s,r,t) = env ~ (_,_) : (!,_) // the 2 'state' signals are fed back
-with {
- env (p2,y) =
- (t>0) & (p2|(y>=1)),
- (y + p1*u*(s/100) - 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, release, must be >0
- na = SR*a+(a==0.0); nr = SR*r+(r==0.0);
- // correct zero sustain level
- z = s+(s==0.0)*db2linear(-60);
- // attack and (-60dB) release rates
- u = 1/na; w = 1-1/pow(z*db2linear(60), 1/nr);
- // values below this threshold are considered zero in the release phase
- eps = db2linear(-120);
- };
-};
-
-//----------------------- ASYMPT60 ----------------------------
-// Envelope generator which asymptotically approaches a target value.
-//
-// USAGE:
-// asympT60(value,trgt,T60,trig) : _
-// where
-// value = starting value
-// trgt = target value
-// T60 = ramping time
-// trig = trigger signal
-
-asympT60(value,trgt,T60,trig) = (_*factor + constant)~_
- with{
- cntSample = *(trig) + 1~_ : -(1);
- attDur = float(2);
- cndFirst = ((cntSample < attDur) & (trig > 0));
- target = value*cndFirst + trgt*(cndFirst < 1);
- factorAtt = exp(-7/attDur);
- factorT60 = exp(-7/(T60*float(SR)));
- factor = factorAtt*((cntSample < attDur) & (trig > 0)) +
- ((cntSample >= attDur) | (trig < 1))*factorT60;
- constant = (1 - factor)*target;
- };
-
-//========================= TABLES ===============================
-
-//----------------------- CLIPPING FUNCTION ----------------------------
-// Positive and negative clipping functions.
-//
-// USAGE:
-// _ : saturationPos : _
-// _ : saturationNeg : _
-// _ : saturationPos : saturationNeg : _
-
-saturationPos(x) = x <: (_>1),(_<=1 : *(x)) :> +;
-saturationNeg(x) = x <: (_<-1),(_>=-1 : *(x)) :> *(-1) + _;
-
-//----------------------- BOW TABLE ----------------------------
-// Simple bow table.
-//
-// USAGE:
-// index : bow(offset,slope) : _
-// where
-// 0 <= index <= 1
-
-bow(offset,slope) = pow(abs(sample) + 0.75, -4) : saturationPos
- with{
- sample(y) = (y + offset)*slope;
- };
-
-//----------------------- REED TABLE ----------------------------
-// Simple reed table to be used with waveguide models of clanrinet, saxophone, etc.
-//
-// USAGE:
-// _ : reed(offset,slope) : _
-// where
-// offset = offset between 0 and 1
-// slope = slope between 0 and 1
-// REFERENCE:
-// https://ccrma.stanford.edu/~jos/pasp/View_Single_Reed_Oscillation.html
-
-reed(offset,slope) = reedTable : saturationPos : saturationNeg
- with{
- reedTable = offset + (slope*_);
- };
-
-//========================= FILTERS ===============================
-
-//----------------------- ONE POLE ----------------------------
-
-onePole(b0,a1,x) = (b0*x - a1*_)~_;
-
-//----------------------- ONE POLE SWEPT ----------------------------
-
-onePoleSwep(a1,x) = (1 + a1)*x - a1*x';
-
-//----------------------- POLE ZERO ----------------------------
-
-poleZero(b0,b1,a1,x) = (b0*x + b1*x' - a1*_)~_;
-
-//----------------------- ONE ZEROS ----------------------------
-// Simple One zero and One zero recursive filters
-//
-// USAGE:
-// _ : oneZero0(b0,b1) : _
-// _ : oneZero1(b0,b1) : _
-// REFERENCE:
-// https://ccrma.stanford.edu/~jos/fp2/One_Zero.html
-
-oneZero0(b0,b1,x) = (*(b1) + x*b0)~_;
-oneZero1(b0,b1,x) = (x'*b1 + x*b0);
-
-//----------------------- BANDPASS FILTER WITH CONSTANT UNITY PEAK GAIN BASED ON A BIQUAD ----------------------------
-
-bandPass(resonance,radius) = TF2(b0,b1,b2,a1,a2)
- with{
- a2 = radius*radius;
- a1 = -2*radius*cos(PI*2*resonance/SR);
- b0 = 0.5-0.5*a2;
- b1 = 0;
- b2 = -b0;
- };
-
-//----------------------- BANDPASS FILTER BASED ON A BIQUAD ----------------------------
-// Band pass filter using a biquad (TF2 is declared in filter.lib)
-//
-// USAGE:
-// _ : bandPassH(resonance,radius) : _
-// where
-// resonance = center frequency
-// radius = radius
-
-bandPassH(resonance,radius) = TF2(b0,b1,b2,a1,a2)
- with{
- a2 = radius*radius;
- a1 = -2*radius*cos(PI*2*resonance/SR);
- b0 = 1;
- b1 = 0;
- b2 = 0;
- };
-
-//----------------------- FLUE JET NON-LINEAR FUNCTION ----------------------------
-// Jet Table: flue jet non-linear function, computed by a polynomial calculation
-
-jetTable(x) = x <: _*(_*_-1) : saturationPos : saturationNeg;
-
-//----------------------- NON LINEAR MODULATOR ----------------------------
-// nonLinearModulator adapts the function allpassnn from filter.lib for using it with waveguide instruments
-//
-// USAGE:
-// _ : nonLinearModulator(nonlinearity,env,freq,typeMod,freqMod,order) : _
-// where
-// nonlinearity = nonlinearity coefficient between 0 and 1
-// env = input to connect any kind of envelope
-// freq = current tone frequency
-// typeMod = if 0: theta is modulated by the incoming signal;
-// if 1: theta is modulated by the averaged incoming signal;
-// if 2: theta is modulated by the squared incoming signal;
-// if 3: theta is modulated by a sine wave of frequency freqMod;
-// if 4: theta is modulated by a sine wave of frequency freq;
-// freqMod = frequency of the sine wave modulation
-// order = order of the filter
-
-nonLinearModulator(nonlinearity,env,freq,typeMod,freqMod,order) =
- //theta is modulated by a sine wave
- _ <: nonLinearFilterOsc*(typeMod >= 3),
- //theta is modulated by the incoming signal
- (_ <: nonLinearFilterSig*nonlinearity,_*(1 - nonlinearity) :> +)*(typeMod < 3)
- :> +
- with{
- //which frequency to use for the sine wave oscillator?
- freqOscMod = (typeMod == 4)*freq + (typeMod != 4)*freqMod;
-
- //the incoming signal is scaled and the envelope is applied
- tsignorm(x) = nonlinearity*PI*x*env;
- tsigsquared(x) = nonlinearity*PI*x*x*env; //incoming signal is squared
- tsigav(x) = nonlinearity*PI*((x + x')/2)*env; //incoming signal is averaged with its previous sample
-
- //select which version of the incoming signal of theta to use
- tsig(x) = tsignorm(x)*(typeMod == 0) + tsigav(x)*(typeMod == 1)
- + tsigsquared(x)*(typeMod == 2);
-
- //theta is modulated by a sine wave generator
- tosc = nonlinearity*PI*osc(freqOscMod)*env;
-
- //incoming signal is sent to the nonlinear passive allpass ladder filter
- nonLinearFilterSig(x) = x <: allpassnn(order,(par(i,order,tsig(x))));
- nonLinearFilterOsc = _ <: allpassnn(order,(par(i,order,tosc)));
- };
-
-//========================= WAVE TABLES ===============================
-
-//----------------------- STICK IMPACT ----------------------------
-// Stick impact table.
-//
-// USAGE:
-// index : readMarmstk1 : _
-
-readMarmstk1 = ffunction(float readMarmstk1 (int), <instrument.h>,"");
-marmstk1TableSize = 246;
-
-//========================= TOOLS ===============================
-
-//----------------------- STEREOIZER ----------------------------
-// This function takes a mono input signal and spacialize it in stereo
-// in function of the period duration of the tone being played.
-//
-// USAGE:
-// _ : stereo(periodDuration) : _,_
-// where
-// periodDuration = period duration of the tone being played in number of samples
-// ACKNOWLEDGMENT
-// Formulation initiated by Julius O. Smith in https://ccrma.stanford.edu/realsimple/faust_strings/
-
-stereoizer(periodDuration) = _ <: _,widthdelay : stereopanner
- with{
- W = hslider("v:Spat/spatial width", 0.5, 0, 1, 0.01);
- A = hslider("v:Spat/pan angle", 0.6, 0, 1, 0.01);
- widthdelay = delay(4096,W*periodDuration/2);
- stereopanner = _,_ : *(1.0-A), *(A);
- };
-
-//----------------------- INSTRREVERB ----------------------------
-// GUI for zita_rev1_stereo from effect.lib
-//
-// USAGE:
-// _,_ : instrRerveb
-
-instrReverb = _,_ <: *(reverbGain),*(reverbGain),*(1 - reverbGain),*(1 - reverbGain) :
-zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax),_,_ <: _,!,_,!,!,_,!,_ : +,+
- with{
- reverbGain = hslider("v:Reverb/reverbGain",0.137,0,1,0.01) : smooth(0.999);
- roomSize = hslider("v:Reverb/roomSize",0.72,0.01,2,0.01);
- rdel = 20;
- f1 = 200;
- f2 = 6000;
- t60dc = roomSize*3;
- t60m = roomSize*2;
- fsmax = 48000;
- };