From e120e2c440f92512d11bbe3fa4ec4655fd4a9ee2 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Mon, 29 Jun 2020 14:29:39 +0200 Subject: [PATCH 01/13] Use ma.EPSILON instead of 1.0e-7. --- analyzers.lib | 4 ++-- compressors.lib | 2 +- filters.lib | 2 +- maths.lib | 1 + old/oscillator.lib | 2 +- oscillators.lib | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/analyzers.lib b/analyzers.lib index d013f8ce..2233d7bd 100644 --- a/analyzers.lib +++ b/analyzers.lib @@ -512,7 +512,7 @@ mth_octave_spectral_level6e(M,ftop,N,tau,dB_offset) = _<: _,mth_octave_analyzer6e(M,ftop,N) : _,(display:>_):attach with { display = par(i,N,dbmeter(i)); - dbmeter(i) = abs : si.smooth(ba.tau2pole(tau)) : max(1.0e-7) : ba.linear2db : +(dB_offset) : + dbmeter(i) = abs : si.smooth(ba.tau2pole(tau)) : max(ma.EPSILON) : ba.linear2db : +(dB_offset) : meter(N-i-1); meter(i) = speclevel_group(vbargraph("[%2i] [unit:dB] [tooltip: Spectral Band Level in dB]", -50, 10)); @@ -696,7 +696,7 @@ goertzel = goertzelOpt; // Undocumented utility functions used by fft and ifft: c_magsq(N) = si.cbus(N) : par(i,N,(par(j,2,abs<:_*_):>_)) :> si.bus(N); -c_magdb(N) = si.cbus(N) : an.c_magsq(N) : par(i,N,(max(1.0e-7):log10:*(10.0))); +c_magdb(N) = si.cbus(N) : an.c_magsq(N) : par(i,N,(max(ma.EPSILON):log10:*(10.0))); c_select_pos_freqs(2) = (_,_), (_,_); // both dc and SR/2 included with "positive frequencies" c_select_pos_freqs(N) = si.cbus(N) : par(i,N/2+1,(_,_)),par(i,N/2-1,(!,!)) : si.cbus(N/2+1); // for complex spectra select_pos_freqs(2) = _,_; // both dc and SR/2 included diff --git a/compressors.lib b/compressors.lib index de022715..c4b0ccd6 100644 --- a/compressors.lib +++ b/compressors.lib @@ -712,7 +712,7 @@ with { // A general 'knee' parameter could be used instead of tying it to att/2: kneesmooth(att) = si.smooth(ba.tau2pole(att/2.0)); // compression gain in dB: - outminusindb(ratio,thresh,level) = max(level-thresh,0.0) * (1.0/max(1.0e-7,float(ratio))-1.0); + outminusindb(ratio,thresh,level) = max(level-thresh,0.0) * (1.0/max(ma.EPSILON,float(ratio))-1.0); // Note: "float(ratio)" REQUIRED when ratio is an integer > 1! }; diff --git a/filters.lib b/filters.lib index 5b276e3f..e5d61e6d 100644 --- a/filters.lib +++ b/filters.lib @@ -2310,7 +2310,7 @@ spectral_tilt(N,f0,bw,alpha) = seq(i,N,sec(i)) with { prewarp(w,SR,wp) = wp * tan(w*T/2) / tan(wp*T/2) with { T = 1/ma.SR; }; mz(i) = w0 * r ^ (-alpha+i); // minus zero i in s plane mp(i) = w0 * r ^ i; // minus pole i in s plane - f0p = max(f0,1.0e-7); // cannot go to zero + f0p = max(f0,ma.EPSILON); // cannot go to zero w0 = 2 * ma.PI * f0p; // radian frequency of first pole f1 = f0p + bw; // upper band limit r = (f1/f0p)^(1.0/float(N-1)); // pole ratio (2 => octave spacing) diff --git a/maths.lib b/maths.lib index 760ba903..bb0b66f4 100644 --- a/maths.lib +++ b/maths.lib @@ -75,6 +75,7 @@ ma = library("maths.lib"); // for compatible copy/paste out of this file //----------------------------------------------------------------------------- SR = pl.SR; + //---------------------------------`(ma.)BS`--------------------------------------- // Current block-size. Can change during the execution. // diff --git a/old/oscillator.lib b/old/oscillator.lib index 8553be0f..10b110b2 100644 --- a/old/oscillator.lib +++ b/old/oscillator.lib @@ -133,7 +133,7 @@ saw3 = sawN(3); saw4 = sawN(4); saw5 = sawN(5); saw6 = sawN(6); saw2(freq) = y with { // newer PTR version (stateless - freq can vary at any speed) - p0 = float(ml.SR)/float(max(1.0e-7,abs(freq))); // period in samples + p0 = float(ml.SR)/float(max(ma.EPSILON,abs(freq))); // period in samples t0 = 1.0/p0; // phase increment p = ((_<:(-(1)<:_,_),_) <: selector1,selector2) ~(+(t0)):!,_; selector1 = select2(<(0)); // for feedback diff --git a/oscillators.lib b/oscillators.lib index 7060f175..aab8ec8d 100644 --- a/oscillators.lib +++ b/oscillators.lib @@ -585,7 +585,7 @@ saw3 = sawN(3); saw4 = sawN(4); saw5 = sawN(5); saw6 = sawN(6); // * `freq`: frequency //-------------------------------------------------------- saw2(freq) = y with { // newer PTR version (stateless - freq can vary at any speed) - p0 = float(ma.SR)/float(max(1.0e-7,abs(freq))); // period in samples + p0 = float(ma.SR)/float(max(ma.EPSILON,abs(freq))); // period in samples t0 = 1.0/p0; // phase increment p = ((_<:(-(1)<:_,_),_) <: selector1,selector2) ~(+(t0)):!,_; selector1 = select2(<(0)); // for feedback From feca522b839dd19c4ac6ae93dc9ece2a57c90f8b Mon Sep 17 00:00:00 2001 From: Bart Brouns Date: Fri, 3 Jul 2020 16:47:36 +0200 Subject: [PATCH 02/13] CZ oscillators: refactor and add phase aligned versions --- oscillators.lib | 256 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 220 insertions(+), 36 deletions(-) diff --git a/oscillators.lib b/oscillators.lib index aab8ec8d..3efe12e7 100644 --- a/oscillators.lib +++ b/oscillators.lib @@ -986,7 +986,19 @@ released under LGPL, STK-4.3, MIT, BSD, or a similar FOSS license. ************************************************************************/ //===================== Casio CZ Oscillators ========================== -// Oscillators that mimics some of the Casio CZ oscillators. +// Oscillators that mimic some of the Casio CZ oscillators. +// +// There are two sets: +// - A set with an index parameter +// - A set with a res parameter +// +// The "index oscillators" outputs a sine wave at index=0 and gets brighter with a higher index. +// There are two versions of the "index oscillators": +// - with P appended to the name: is phase aligned with 'fund:sin' +// - without P appended to the name: has the phase of the original CZ oscillators +// +// The "res oscillators" have a resonant frequency. +// "res" is the frequency of resonance as a factor of the fundamental pitch. //===================================================================== //----------`(os.)CZsaw`---------- @@ -1006,12 +1018,35 @@ released under LGPL, STK-4.3, MIT, BSD, or a similar FOSS license. //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZsaw(fund, index) = (((fund*((.5-tmp)/tmp)),(-1*fund+1)*((.5-tmp)/(1-tmp))):min+fund)*2*ma.PI:cos -with { - tmp = (.5-(index*.5)):max(0.01):min(0.5); -}; +CZsaw(fund, index) = CZ.sawChooseP(fund, index, 0); + +//----------`(os.)CZsawP`---------- +// Oscillator that mimics the Casio CZ saw oscillator, +// with it's phase aligned to `fund:sin`. +// `CZsawP` is a standard Faust function. +// +// #### Usage +// +// ``` +// CZsawP(fund,index) : _ +// ``` +// +// Where: +// +// * `fund`: a saw-tooth waveform between 0 and 1 that the oscillator slaves to +// * `index`: the brightness of the oscillator, 0 to 1. 0 = sine-wave, 1 = saw-wave +//------------------------------------------------------------ +// Author: Bart Brouns +// License: GPLv3 +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZsawP(fund, index) = CZ.sawChooseP(fund, index, 1); //----------`(os.)CZsquare`---------- // Oscillator that mimics the Casio CZ square oscillator @@ -1030,12 +1065,35 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZsquare(fund, index) = (fund>=0.5), (ma.decimal((fund*2)+1)<:_-min(_,(-1*_+1)*((INDEX)/(1-INDEX)))) :+ *ma.PI:cos*0.5 -with { - INDEX = (index:pow(0.25)) * 0.98; -}; +CZsquare(fund, index) = CZ.squareChooseP(fund, index, 0); + +//----------`(os.)CZsquareP`---------- +// Oscillator that mimics the Casio CZ square oscillator, +// with it's phase aligned to `fund:sin`. +// `CZsquareP` is a standard Faust function. +// +// #### Usage +// +// ``` +// CZsquareP(fund,index) : _ +// ``` +// +// Where: +// +// * `fund`: a saw-tooth waveform between 0 and 1 that the oscillator slaves to +// * `index`: the brightness of the oscillator, 0 to 1. 0 = sine-wave, 1 = square-wave +//------------------------------------------------------------ +// Author: Bart Brouns +// License: GPLv3 +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZsquareP(fund, index) = CZ.squareChooseP(fund, index, 1); //----------`(os.)CZpulse`---------- // Oscillator that mimics the Casio CZ pulse oscillator @@ -1054,12 +1112,35 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZpulse(fund, index) = ((fund-min(fund,((-1*fund+1)*(INDEX/(1-INDEX)))))*2*ma.PI):cos -with { - INDEX = index:min(0.99):max(0); -}; +CZpulse(fund, index) = CZ.pulseChooseP(fund, index, 0); + +//----------`(os.)CZpulseP`---------- +// Oscillator that mimics the Casio CZ pulse oscillator, +// with it's phase aligned to `fund:sin`. +// `CZpulseP` is a standard Faust function. +// +// #### Usage +// +// ``` +// CZpulseP(fund,index) : _ +// ``` +// +// Where: +// +// * `fund`: a saw-tooth waveform between 0 and 1 that the oscillator slaves to +// * `index`: the brightness of the oscillator, 0 gives a sine-wave, 1 is closer to a pulse +//------------------------------------------------------------ +// Author: Bart Brouns +// License: GPLv3 +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZpulseP(fund, index) = CZ.pulseChooseP(fund, index, 1); //----------`(os.)CZsinePulse`---------- // Oscillator that mimics the Casio CZ sine/pulse oscillator @@ -1078,12 +1159,35 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZsinePulse(fund, index) = (min(fund*((0.5-INDEX)/INDEX),(-1*fund+1)*((.5-INDEX)/(1-INDEX)))+fund)*4*ma.PI:cos -with { - INDEX = ((index*-0.49)+0.5); -}; +CZsinePulse(fund, index) = CZ.sinePulseChooseP(fund, index, 0); + +//----------`(os.)CZsinePulseP`---------- +// Oscillator that mimics the Casio CZ sine/pulse oscillator, +// with it's phase aligned to `fund:sin`. +// `CZsinePulseP` is a standard Faust function. +// +// #### Usage +// +// ``` +// CZsinePulseP(fund,index) : _ +// ``` +// +// Where: +// +// * `fund`: a saw-tooth waveform between 0 and 1 that the oscillator slaves to +// * `index`: the brightness of the oscillator, 0 gives a sine-wave, 1 is a sine minus a pulse +//------------------------------------------------------------ +// Author: Bart Brouns +// License: GPLv3 +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZsinePulseP(fund, index) = CZ.sinePulseChooseP(fund, index, 1); //----------`(os.)CZhalfSine`---------- // Oscillator that mimics the Casio CZ half sine oscillator @@ -1102,12 +1206,35 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZhalfSine(fund, index) = (select2(fund<.5, .5*(fund-.5)/INDEX+.5, fund):min(1))*2*ma.PI:cos -with { - INDEX = (.5-(index*0.5)):min(.5):max(.01); -}; +CZhalfSine(fund, index) = CZ.halfSineChooseP(fund, index, 0); + +//----------`(os.)CZhalfSineP`---------- +// Oscillator that mimics the Casio CZ half sine oscillator, +// with it's phase aligned to `fund:sin`. +// `CZhalfSineP` is a standard Faust function. +// +// #### Usage +// +// ``` +// CZhalfSineP(fund,index) : _ +// ``` +// +// Where: +// +// * `fund`: a saw-tooth waveform between 0 and 1 that the oscillator slaves to +// * `index`: the brightness of the oscillator, 0 gives a sine-wave, 1 is somewhere between a saw and a square +//------------------------------------------------------------ +// Author: Bart Brouns +// License: GPLv3 +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZhalfSineP(fund, index) = CZ.halfSineChooseP(fund, index, 1); //----------`(os.)CZresSaw`---------- // Oscillator that mimics the Casio CZ resonant saw-tooth oscillator @@ -1126,9 +1253,11 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZresSaw(fund,res) = (((-1*(1-fund))*((cos((ma.decimal((max(1,res)*fund)+1))*2*ma.PI)*-.5)+.5))*2)+1; +CZresSaw(fund,res) = CZ.resSaw(fund,res); //----------`(os.)CZresTriangle`---------- // Oscillator that mimics the Casio CZ resonant triangle oscillator @@ -1147,12 +1276,11 @@ CZresSaw(fund,res) = (((-1*(1-fund))*((cos((ma.decimal((max(1,res)*fund)+1))*2*m //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns -CZresTriangle(fund,res) = select2(fund<.5, 2-(fund*2), fund*2)*tmp*2-1 -with { - tmp = ((fund*(res:max(1)))+1:ma.decimal)*2*ma.PI:cos*.5+.5; -}; +CZresTriangle(fund,res) = CZ.resTriangle(fund,res); //----------`(os.)CZresTrap`---------- // Oscillator that mimics the Casio CZ resonant trapeze oscillator @@ -1171,9 +1299,65 @@ with { //------------------------------------------------------------ // Author: Bart Brouns // License: GPLv3 -// CZ oscilators by Mike Moser-Booth. ported from pd to Faust by Bart Brouns - -CZresTrap(fund, res) = (((1-fund)*2):min(1)*sin(ma.decimal(fund*(res:max(1)))*2*ma.PI)); +// CZ oscillators by Mike Moser-Booth: +// https://forum.pdpatchrepo.info/topic/5992/casio-cz-oscillators +// Ported from pd to Faust by Bart Brouns + +CZresTrap(fund, res) = CZ.resTrap(fund, res); + +CZ = + environment { + saw(fund, index) = sawChooseP(fund, index, 0); + sawP(fund, index) = sawChooseP(fund, index, 1); + sawChooseP(fund, index, p) = + (((FUND(fund,allign,p)*((.5-INDEX)/INDEX)),(-1*FUND(fund,allign,p)+1)*((.5-INDEX)/(1-INDEX))):min+FUND(fund,allign,p))*2*ma.PI:cos + with { + INDEX = (.5-(index*.5)):max(0.01):min(0.5); + allign = si.interpolate(index, 0.75, 0.5); + }; + square(fund, index) = squareChooseP(fund, index, 0); + squareP(fund, index) = squareChooseP(fund, index, 1); + squareChooseP(fund, index, p) = (FUND(fund,allign,p)>=0.5), (ma.decimal((FUND(fund,allign,p)*2)+1)<:_-min(_,(-1*_+1)*((INDEX)/(1-INDEX)))) :+ *ma.PI:cos + with { + INDEX = (index:pow(0.25)):max(0):min(1); + allign = si.interpolate(INDEX, -0.25, 0); + }; + + pulse(fund, index) = pulseChooseP(fund, index, 0); + pulseP(fund, index) = pulseChooseP(fund, index, 1); + pulseChooseP(fund, index, p) = ((FUND(fund,allign,p)-min(FUND(fund,allign,p),((-1*FUND(fund,allign,p)+1)*(INDEX/(1-INDEX)))))*2*ma.PI):cos + with { + INDEX = index:min(0.99):max(0); + allign = si.interpolate(index, -0.25, 0.0); + }; + + sinePulse(fund, index) = sinePulseChooseP(fund, index, 0); + sinePulseP(fund, index) = sinePulseChooseP(fund, index, 1); + sinePulseChooseP(fund, index, p) = (min(FUND(fund,allign,p)*((0.5-INDEX)/INDEX),(-1*FUND(fund,allign,p)+1)*((.5-INDEX)/(1-INDEX)))+FUND(fund,allign,p))*4*ma.PI:cos + with { + INDEX = ((index*-0.49)+0.5); + allign = si.interpolate(index, -0.125, -0.25); + }; + + halfSine(fund, index) = halfSineChooseP(fund, index, 0); + halfSineP(fund, index) = halfSineChooseP(fund, index, 1); + halfSineChooseP(fund, index, p) = (select2(FUND(fund,allign,p)<.5, .5*(FUND(fund,allign,p)-.5)/INDEX+.5, FUND(fund,allign,p)):min(1))*2*ma.PI:cos + with { + INDEX = (.5-(index*0.5)):min(.5):max(.01); + allign = si.interpolate(index:min(0.975), -0.25, -0.5); + }; + FUND = + case { + (fund,allign,0) => fund; + (fund,allign,1) => (fund+allign) : ma.frac; // allign phase with fund + }; + resSaw(fund,res) = (((-1*(1-fund))*((cos((ma.decimal((max(1,res)*fund)+1))*2*ma.PI)*-.5)+.5))*2)+1; + resTriangle(fund,res) = select2(fund<.5, 2-(fund*2), fund*2)*INDEX*2-1 + with { + INDEX = ((fund*(res:max(1)))+1:ma.decimal)*2*ma.PI:cos*.5+.5; + }; + resTrap(fund, res) = (((1-fund)*2):min(1)*sin(ma.decimal(fund*(res:max(1)))*2*ma.PI)); + }; //===============================PolyBLEP-Based Oscillators================================= From c3cdf038115c4f1b8f808b098cb1aa813fb37480 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Fri, 3 Jul 2020 22:20:20 +0200 Subject: [PATCH 03/13] Cleanup. --- oscillators.lib | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/oscillators.lib b/oscillators.lib index 3efe12e7..6f9b33a6 100644 --- a/oscillators.lib +++ b/oscillators.lib @@ -1307,57 +1307,60 @@ CZresTrap(fund, res) = CZ.resTrap(fund, res); CZ = environment { + saw(fund, index) = sawChooseP(fund, index, 0); sawP(fund, index) = sawChooseP(fund, index, 1); sawChooseP(fund, index, p) = - (((FUND(fund,allign,p)*((.5-INDEX)/INDEX)),(-1*FUND(fund,allign,p)+1)*((.5-INDEX)/(1-INDEX))):min+FUND(fund,allign,p))*2*ma.PI:cos + (((FUND(fund,align,p)*((.5-INDEX)/INDEX)),(-1*FUND(fund,align,p)+1)*((.5-INDEX)/(1-INDEX))):min+FUND(fund,align,p))*2*ma.PI:cos with { INDEX = (.5-(index*.5)):max(0.01):min(0.5); - allign = si.interpolate(index, 0.75, 0.5); + align = si.interpolate(index, 0.75, 0.5); }; + square(fund, index) = squareChooseP(fund, index, 0); squareP(fund, index) = squareChooseP(fund, index, 1); - squareChooseP(fund, index, p) = (FUND(fund,allign,p)>=0.5), (ma.decimal((FUND(fund,allign,p)*2)+1)<:_-min(_,(-1*_+1)*((INDEX)/(1-INDEX)))) :+ *ma.PI:cos + squareChooseP(fund, index, p) = (FUND(fund,align,p)>=0.5), (ma.decimal((FUND(fund,align,p)*2)+1)<:_-min(_,(-1*_+1)*((INDEX)/(1-INDEX)))) :+ *ma.PI:cos with { INDEX = (index:pow(0.25)):max(0):min(1); - allign = si.interpolate(INDEX, -0.25, 0); + align = si.interpolate(INDEX, -0.25, 0); }; pulse(fund, index) = pulseChooseP(fund, index, 0); pulseP(fund, index) = pulseChooseP(fund, index, 1); - pulseChooseP(fund, index, p) = ((FUND(fund,allign,p)-min(FUND(fund,allign,p),((-1*FUND(fund,allign,p)+1)*(INDEX/(1-INDEX)))))*2*ma.PI):cos + pulseChooseP(fund, index, p) = ((FUND(fund,align,p)-min(FUND(fund,align,p),((-1*FUND(fund,align,p)+1)*(INDEX/(1-INDEX)))))*2*ma.PI):cos with { INDEX = index:min(0.99):max(0); - allign = si.interpolate(index, -0.25, 0.0); + align = si.interpolate(index, -0.25, 0.0); }; sinePulse(fund, index) = sinePulseChooseP(fund, index, 0); sinePulseP(fund, index) = sinePulseChooseP(fund, index, 1); - sinePulseChooseP(fund, index, p) = (min(FUND(fund,allign,p)*((0.5-INDEX)/INDEX),(-1*FUND(fund,allign,p)+1)*((.5-INDEX)/(1-INDEX)))+FUND(fund,allign,p))*4*ma.PI:cos + sinePulseChooseP(fund, index, p) = (min(FUND(fund,align,p)*((0.5-INDEX)/INDEX),(-1*FUND(fund,align,p)+1)*((.5-INDEX)/(1-INDEX)))+FUND(fund,align,p))*4*ma.PI:cos with { INDEX = ((index*-0.49)+0.5); - allign = si.interpolate(index, -0.125, -0.25); + align = si.interpolate(index, -0.125, -0.25); }; halfSine(fund, index) = halfSineChooseP(fund, index, 0); halfSineP(fund, index) = halfSineChooseP(fund, index, 1); - halfSineChooseP(fund, index, p) = (select2(FUND(fund,allign,p)<.5, .5*(FUND(fund,allign,p)-.5)/INDEX+.5, FUND(fund,allign,p)):min(1))*2*ma.PI:cos + halfSineChooseP(fund, index, p) = (select2(FUND(fund,align,p)<.5, .5*(FUND(fund,align,p)-.5)/INDEX+.5, FUND(fund,align,p)):min(1))*2*ma.PI:cos with { INDEX = (.5-(index*0.5)):min(.5):max(.01); - allign = si.interpolate(index:min(0.975), -0.25, -0.5); + align = si.interpolate(index:min(0.975), -0.25, -0.5); }; + FUND = case { - (fund,allign,0) => fund; - (fund,allign,1) => (fund+allign) : ma.frac; // allign phase with fund + (fund,align,0) => fund; + (fund,align,1) => (fund+align) : ma.frac; // align phase with fund }; resSaw(fund,res) = (((-1*(1-fund))*((cos((ma.decimal((max(1,res)*fund)+1))*2*ma.PI)*-.5)+.5))*2)+1; resTriangle(fund,res) = select2(fund<.5, 2-(fund*2), fund*2)*INDEX*2-1 with { - INDEX = ((fund*(res:max(1)))+1:ma.decimal)*2*ma.PI:cos*.5+.5; + INDEX = ((fund*(res:max(1)))+1:ma.decimal)*2*ma.PI:cos*.5+.5; }; resTrap(fund, res) = (((1-fund)*2):min(1)*sin(ma.decimal(fund*(res:max(1)))*2*ma.PI)); - }; +}; //===============================PolyBLEP-Based Oscillators================================= From 63afed0d4e54981b62b1563da3a81a2f4347ef99 Mon Sep 17 00:00:00 2001 From: Bart Brouns Date: Sun, 5 Jul 2020 00:15:09 +0200 Subject: [PATCH 04/13] adsre: don't skip the decay phase when attack==0 --- envelopes.lib | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/envelopes.lib b/envelopes.lib index 2f91a4d2..4cc309df 100644 --- a/envelopes.lib +++ b/envelopes.lib @@ -297,14 +297,15 @@ adsre(attT60,decT60,susLvl,relT60,gate) = envelope with { ugate = gate>0; samps = ugate : +~(*(ugate)); // ramp time in samples attSamps = int(attT60 * ma.SR); + // if attSamps==0, go straight into the decay phase + attPhase = (samps Date: Mon, 13 Jul 2020 20:18:38 +0200 Subject: [PATCH 05/13] Cleanup. --- basics.lib | 32 ++++++++++++++++++++------------ delays.lib | 26 +++++++++++++------------- interpolators.lib | 2 +- oscillators.lib | 16 ++++++++-------- version.lib | 2 +- webaudio.lib | 4 ++-- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/basics.lib b/basics.lib index 200fb107..c16db574 100644 --- a/basics.lib +++ b/basics.lib @@ -72,7 +72,7 @@ declare version "0.1"; // // * `n`: number of samples //---------------------------- -samp2sec = /(ma.SR); +samp2sec(n) = n/ma.SR; //-------`(ba.)sec2samp`---------- @@ -89,7 +89,7 @@ samp2sec = /(ma.SR); // // * `d`: duration in seconds //---------------------------- -sec2samp = *(ma.SR); +sec2samp(d) = d*ma.SR; //-------`(ba.)db2linear`---------- @@ -123,7 +123,7 @@ db2linear(l) = pow(10, l/20.0); // // * `g`: a linear gain //----------------------------- -linear2db(g) = 20*log10(g); +linear2db(g) = 20.0*log10(g); //----------`(ba.)lin2LogGain`------------------ @@ -1025,8 +1025,8 @@ listInterp(v) = //-------------------`(ba.)bypass1`------------------------- -// Takes a mono input signal, route it to `e` and bypass it if `bpc = 1`. When bypassed, `e` is feed with zeros -// so that its state is cleanup up. +// Takes a mono input signal, route it to `e` and bypass it if `bpc = 1`. +// When bypassed, `e` is feed with zeros so that its state is cleanup up. // `bypass1` is a standard Faust function. // // #### Usage @@ -1049,8 +1049,8 @@ with { //-------------------`(ba.)bypass2`------------------------- -// Takes a stereo input signal, route it to `e` and bypass it if `bpc = 1`. When bypassed, `e` is feed with zeros -// so that its state is cleanup up. +// Takes a stereo input signal, route it to `e` and bypass it if `bpc = 1`. +// When bypassed, `e` is feed with zeros so that its state is cleanup up. // `bypass2` is a standard Faust function. // // #### Usage @@ -1098,9 +1098,11 @@ with { //-------------------`(ba.)bypass_fade`------------------------- -// Bypass an arbitrary (N x N) circuit with 'n' samples crossfade. Inputs and outputs signals are faded -// out when 'e' is bypassed, so that 'e' state is cleanup up. -// Once bypassed the effect is replaced by par(i,N,_). Bypassed circuits can be chained. +// Bypass an arbitrary (N x N) circuit with 'n' samples crossfade. +// Inputs and outputs signals are faded out when 'e' is bypassed, +// so that 'e' state is cleanup up. +// Once bypassed the effect is replaced by par(i,N,_). +// Bypassed circuits can be chained. // // #### Usage // @@ -1451,6 +1453,7 @@ with { int2nrOfBits(maxN) = int(floor(log(maxN)/log(2))+1); }; + //------------------------------`(ba.)slidingSum`------------------------------ // The sliding sum of the last n input samples. // @@ -1469,6 +1472,7 @@ with { //------------------------------------------------------------------------------ slidingSum(n) = fi.integrator <: _, _@int(max(0,n)) :> -; + //------------------------------`(ba.)slidingSump`------------------------------ // The sliding sum of the last n input samples. // @@ -1504,6 +1508,7 @@ slidingSump(n,maxn) = slidingReduce(+,n,maxn,0); //------------------------------------------------------------------------------ slidingMax(n,maxn) = slidingReduce(max,n,maxn,-(ma.INFINITY)); + //----------------------------`(ba.)slidingMin`-------------------------------- // The sliding minimum of the last n input samples. // @@ -1538,6 +1543,7 @@ slidingMin(n,maxn) = slidingReduce(min,n,maxn,ma.INFINITY); //------------------------------------------------------------------------------ slidingMean(n) = slidingSum(n)/n; + //----------------------------`(ba.)slidingMeanp`------------------------------- // The sliding mean of the last n input samples. // @@ -1574,7 +1580,8 @@ slidingMeanp(n,maxn) = slidingSump(n,maxn)/n; // // * `N`: the number of values to process //------------------------------------------------------------------------------ -slidingRMS(n) = pow(2):slidingMean(n) : sqrt; +slidingRMS(n) = pow(2) : slidingMean(n) : sqrt; + //---------------------------`(ba.)slidingRMSp`--------------------------------- // The root mean square of the last n input samples. @@ -1592,7 +1599,8 @@ slidingRMS(n) = pow(2):slidingMean(n) : sqrt; // * `N`: the number of values to process // * `maxN`: the maximum number of values to process, needs to be a power of 2 //------------------------------------------------------------------------------ -slidingRMSp(n,maxn) = pow(2):slidingMeanp(n,maxn) : sqrt; +slidingRMSp(n,maxn) = pow(2) : slidingMeanp(n,maxn) : sqrt; + //////////////////////////////////Deprecated Functions//////////////////////////////////// // This section implements functions that used to be in music.lib but that are now diff --git a/delays.lib b/delays.lib index 0597fc2b..4801ae5a 100644 --- a/delays.lib +++ b/delays.lib @@ -371,16 +371,16 @@ with { // considered as "deprecated". ////////////////////////////////////////////////////////////////////////////////////////// -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); +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); diff --git a/interpolators.lib b/interpolators.lib index b3ffbfdc..a4f970a0 100644 --- a/interpolators.lib +++ b/interpolators.lib @@ -270,7 +270,7 @@ interpolate_cosine(dv,v0,v1) = v0 + a2*(v1-v0) with { a2 = 0.5 * (1.0 - cos(dv*m //-------------------------------------------- interpolate_cubic(dv,v0,v1,v2,v3) - = v1 + 0.5 *dv*(v2 - v0 + dv*(2.0*v0 - 5.0*v1 + 4.0*v2 - v3 + dv*(3.0*(v1 - v2) + v3 - v0))); + = v1 + 0.5*dv*(v2 - v0 + dv*(2.0*v0 - 5.0*v1 + 4.0*v2 - v3 + dv*(3.0*(v1 - v2) + v3 - v0))); //=========================Two points interpolators======================================= diff --git a/oscillators.lib b/oscillators.lib index 6f9b33a6..2debb374 100644 --- a/oscillators.lib +++ b/oscillators.lib @@ -141,9 +141,9 @@ with { // Author: Christophe Lebreton hsp_phasor(tablesize,freq,p,c) = inc : (+ : d)~(-(_<:(_,*(_,clk))):+(clk*p)) : *(tablesize) with { - clk = c>0; - d = ma.decimal; - inc = freq/float(ma.SR); + clk = c>0; + d = ma.decimal; + inc = freq/float(ma.SR); }; //-----------------------`(os.)oscsin`------------------------ @@ -198,7 +198,7 @@ with { // // * `freq`: the frequency of the wave (Hz) //------------------------------------------------------------ -osccos(freq) = rdtable(tablesize, coswaveform(tablesize), int(phasor(tablesize,freq)) ) +osccos(freq) = rdtable(tablesize, coswaveform(tablesize), int(phasor(tablesize,freq))) with { tablesize = pl.tablesize; }; @@ -209,15 +209,15 @@ with { // #### Usage // // ``` -// oscp(freq,p) : _ +// oscp(freq,phase) : _ // ``` // // Where: // // * `freq`: the frequency of the wave (Hz) -// * `p`: the phase in radian +// * `phase`: the phase in radian //------------------------------------------------------------ -oscp(freq,p) = oscsin(freq) * cos(p) + osccos(freq) * sin(p); +oscp(freq,phase) = oscsin(freq) * cos(phase) + osccos(freq) * sin(phase); //-----------------------`(os.)osci`------------------------ // Interpolated phase sine wave oscillator. @@ -422,8 +422,8 @@ lf_rawsaw(periodsamps) = (_,periodsamps : fmod) ~ +(1.0); // // Where: // -// * `freq`: frequency // * `phase`: phase +// * `freq`: frequency //--------------------------------------------------------- lf_sawpos_phase(phase,freq) = (+(phase-phase') : ma.frac) ~ +(freq/ma.SR); diff --git a/version.lib b/version.lib index f8366638..94ac218b 100644 --- a/version.lib +++ b/version.lib @@ -15,6 +15,6 @@ //------------------------------------------------------------ version = 1, // MAJOR version when we make incompatible API changes, 2, // MINOR version when we add functionality in a backwards compatible manner, - 0; // PATCH version when we make backwards compatible bug fixes. + 1; // PATCH version when we make backwards compatible bug fixes. diff --git a/webaudio.lib b/webaudio.lib index 28d459ec..cf34c6cf 100644 --- a/webaudio.lib +++ b/webaudio.lib @@ -45,10 +45,10 @@ declare license "LGPL with exception"; ma = library("maths.lib"); fi = library("filters.lib"); -//---------------------------------------- +//--------------------------------------------------- // biquad coeffs for various filters // usage : BiquadFilter(f0, dBgain, Q, aDetune).xxx -//---------------------------------------- +//--------------------------------------------------- BiquadFilter(f0, dBgain, Q, aDetune) = environment { From 008db29e2caa1402d1e35695cea4fa03ddafc0b6 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Thu, 3 Sep 2020 19:35:28 +0200 Subject: [PATCH 06/13] Oleg Nesterov SVF filters. --- filters.lib | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++- version.lib | 4 +-- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/filters.lib b/filters.lib index e5d61e6d..d96c02cf 100644 --- a/filters.lib +++ b/filters.lib @@ -1,7 +1,7 @@ //##################################### filters.lib ######################################## // Faust Filters library. Its official prefix is `fi`. // -// The Filters library is organized into 18 sections: +// The Filters library is organized into 19 sections: // // * Basic Filters // * Comb Filters @@ -21,6 +21,7 @@ // * Parametric Equalizers (Shelf, Peaking) // * Mth-Octave Filter-Banks // * Arbitrary-Crossover Filter-Banks and Spectrum Analyzers +// * SVF filters // //######################################################################################## @@ -38,6 +39,7 @@ si = library("signals.lib"); fi = library("filters.lib"); // for compatible copy/paste out of this file declare name "Faust Filters Library"; +declare version "0.2"; //===============================Basic Filters============================================ //======================================================================================== @@ -2573,6 +2575,84 @@ filterbanki(O,lfreqs) = _ <: bsplit(nb) with delayeq(i) = ap(i) : delayeq(i-1); }; + +//===============SVF Filters========================================================= +// #### References +// Solving the continuous SVF equations using trapezoidal integration +// * +//======================================================================================== + +//-----------------`(fi.)svf`---------------------- +// An environment with lp, bp, hp, notch, peak, ap, bell, ls, hs SVF based filters +// +// #### Usage +// +// ``` +// _ : svf.xx(freq, Q, [gain]) : _ +// ``` +// +// Where: +// +// * `freq`: cut frequency +// * `Q`: quality factor +// * `[gain]`: gain +// +/// ``` +//--------------------------------------------------- +declare svf author "Oleg Nesterov"; +declare svf copyright "Copyright (C) 2020 Oleg Nesterov "; +declare svf license "TODO"; + +svf = environment { + svf(T,F,Q,G) = tick ~ (_,_) : !,!,si.dot(3, mix) + with { + tick(ic1eq, ic2eq, v0) = + 2*v1 - ic1eq, + 2*v2 - ic2eq, + v0, v1, v2 + with { + v1 = ic1eq + g *(v0-ic2eq) : /(1 + g*(g+k)); + v2 = ic2eq + g * v1; + }; + + A = pow(10.0, G/40.0); + + g = tan(F * ma.PI/ma.SR) : case { + (7) => /(sqrt(A)); + (8) => *(sqrt(A)); + (t) => _; + } (T); + + k = case { + (6) => 1/(Q*A); + (t) => 1/Q; + } (T); + + mix = case { + (0) => 0, 0, 1; + (1) => 0, 1, 0; + (2) => 1, -k, -1; + (3) => 1, -k, 0; + (4) => 1, -k, -2; + (5) => 1, -2*k, 0; + (6) => 1, k*(A*A-1), 0; + (7) => 1, k*(A-1), A*A-1; + (8) => A*A, k*(1-A)*A, 1-A*A; + } (T); + }; + + lp(f,q) = svf(0, f, q, 0); + bp(f,q) = svf(1, f, q, 0); + hp(f,q) = svf(2, f, q, 0); + notch(f,q) = svf(3, f, q, 0); + peak(f,q) = svf(4, f, q, 0); + ap(f,q) = svf(5, f, q, 0); + bell(f,q,g) = svf(6, f, q, g); + ls(f,q,g) = svf(7, f, q, g); + hs(f,q,g) = svf(8, f, q, g); +}; + + /******************************************************************************* # Licenses diff --git a/version.lib b/version.lib index 94ac218b..2a42bbf0 100644 --- a/version.lib +++ b/version.lib @@ -14,7 +14,7 @@ // //------------------------------------------------------------ version = 1, // MAJOR version when we make incompatible API changes, - 2, // MINOR version when we add functionality in a backwards compatible manner, - 1; // PATCH version when we make backwards compatible bug fixes. + 3, // MINOR version when we add functionality in a backwards compatible manner, + 0; // PATCH version when we make backwards compatible bug fixes. From 72a134c9b22adba0662a75f260845cdabe813ab2 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Thu, 3 Sep 2020 22:18:05 +0200 Subject: [PATCH 07/13] More documentation for SVF filters. --- filters.lib | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/filters.lib b/filters.lib index d96c02cf..19baa8d2 100644 --- a/filters.lib +++ b/filters.lib @@ -2583,7 +2583,8 @@ filterbanki(O,lfreqs) = _ <: bsplit(nb) with //======================================================================================== //-----------------`(fi.)svf`---------------------- -// An environment with lp, bp, hp, notch, peak, ap, bell, ls, hs SVF based filters +// An environment with `lp`, `bp`, `hp`, `notch`, `peak`, `ap`, `bell`, `ls`, `hs` SVF based filters. +// All filters have `freq` and `Q` parameters, the `bell`, `ls`, `hs` ones also have a `gain` third parameter. // // #### Usage // @@ -2595,7 +2596,7 @@ filterbanki(O,lfreqs) = _ <: bsplit(nb) with // // * `freq`: cut frequency // * `Q`: quality factor -// * `[gain]`: gain +// * `[gain]`: gain in dB // /// ``` //--------------------------------------------------- @@ -2604,6 +2605,8 @@ declare svf copyright "Copyright (C) 2020 Oleg Nesterov "; declare svf license "TODO"; svf = environment { + + // Internal implementation svf(T,F,Q,G) = tick ~ (_,_) : !,!,si.dot(3, mix) with { tick(ic1eq, ic2eq, v0) = @@ -2641,12 +2644,13 @@ svf = environment { } (T); }; + // External API lp(f,q) = svf(0, f, q, 0); bp(f,q) = svf(1, f, q, 0); hp(f,q) = svf(2, f, q, 0); notch(f,q) = svf(3, f, q, 0); peak(f,q) = svf(4, f, q, 0); - ap(f,q) = svf(5, f, q, 0); + ap(f,q) = svf(5, f, q, 0); bell(f,q,g) = svf(6, f, q, g); ls(f,q,g) = svf(7, f, q, g); hs(f,q,g) = svf(8, f, q, g); From 810f414c68dbef83921d4cccb88aafb0d5616f60 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Fri, 4 Sep 2020 11:31:04 +0200 Subject: [PATCH 08/13] Add licence for SVF filters. --- filters.lib | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/filters.lib b/filters.lib index 19baa8d2..e9819611 100644 --- a/filters.lib +++ b/filters.lib @@ -431,6 +431,7 @@ declare allpass_fcomb1a copyright "Copyright (C) 2003-2019 by Julius O. Smith II declare allpass_fcomb1a license "MIT-style STK-4.3 license"; allpass_fcomb1a(maxdel,N,aN) = (+ <: de.fdelay1a(maxdel,N-1),*(aN)) ~ *(-aN) : mem,_ : +; + //========================Direct-Form Digital Filter Sections============================= //======================================================================================== @@ -1604,6 +1605,7 @@ with { }; }; + //================Special Filter-Bank Delay-Equalizing Allpass Filters==================== // These special allpass filters are needed by filterbank et al. below. // They are equivalent to (`lowpass(N,fc)` +|- `highpass(N,fc))/2`, but with @@ -1666,6 +1668,7 @@ declare highpass_plus_lowpass_odd license "MIT-style STK-4.3 license"; // to eliminate pole-zero cancellations: highpass_minus_lowpass_odd(N,fc) = highpass(N,fc) - lowpass(N,fc); + //==========================Elliptic (Cauer) Lowpass Filters============================== // Elliptic (Cauer) Lowpass Filters // @@ -1763,6 +1766,7 @@ with { w1 = 2*ma.PI*fc; }; + //=========================Elliptic Highpass Filters====================================== //======================================================================================== @@ -1838,6 +1842,7 @@ with { w1 = 2*ma.PI*fc; }; + //========================Butterworth Bandpass/Bandstop Filters=========================== //======================================================================================== @@ -1922,6 +1927,7 @@ with { }; }; + //===========================Elliptic Bandpass Filters==================================== //======================================================================================== @@ -2058,6 +2064,7 @@ pospass0(lpf) = unmodulate : lpf, lpf : modulate with { modulate(x,y) = c*x-s*y, c*y + s*x; // add SR/4 to all frequencies }; + //=================Parametric Equalizers (Shelf, Peaking)================================= // Parametric Equalizers (Shelf, Peaking). // @@ -2602,7 +2609,7 @@ filterbanki(O,lfreqs) = _ <: bsplit(nb) with //--------------------------------------------------- declare svf author "Oleg Nesterov"; declare svf copyright "Copyright (C) 2020 Oleg Nesterov "; -declare svf license "TODO"; +declare svf license "MIT-style STK-4.3 license"; svf = environment { From c671fb10d0ddc077176c3fbbfe50d8e5339ca773 Mon Sep 17 00:00:00 2001 From: Stephane Letz Date: Sun, 6 Sep 2020 00:11:10 +0200 Subject: [PATCH 09/13] Make allpassnt and allpassn1mt compile again, cleanup. --- filters.lib | 63 +++++++++++++++++++++++-------------------------- oscillators.lib | 21 ++++++++--------- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/filters.lib b/filters.lib index e9819611..5df120c9 100644 --- a/filters.lib +++ b/filters.lib @@ -32,6 +32,7 @@ ma = library("maths.lib"); ba = library("basics.lib"); +ro = library("routes.lib"); de = library("delays.lib"); an = library("analyzers.lib"); ef = library("misceffects.lib"); @@ -200,7 +201,7 @@ lpt19(tN, x) = lptN(19, tN, x); // T19 constant, i.e., 1/e^2.2 atten. after tN s declare ff_comb author "Julius O. Smith III"; declare ff_comb copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare ff_comb license "MIT-style STK-4.3 license"; -ff_comb(maxdel,M,b0,bM) = _ <: *(b0), bM * de.delay(maxdel,M) : + ; +ff_comb(maxdel,M,b0,bM) = _ <: *(b0), bM * de.delay(maxdel,M) : +; //------`(fi.)ff_fcomb`-------- // Feed-Forward Comb Filter. Note that `ff_fcomb` takes floating-point delays @@ -262,7 +263,7 @@ ffcombfilter(maxdel,del,g) = ff_comb(maxdel,del,1,g); declare fb_comb author "Julius O. Smith III"; declare fb_comb copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare fb_comb license "MIT-style STK-4.3 license"; -fb_comb(maxdel,N,b0,aN) = (+ <: de.delay(maxdel,N-1),_) ~ *(-aN) : !,*(b0):mem; +fb_comb(maxdel,N,b0,aN) = (+ <: de.delay(maxdel,N-1),_) ~ *(-aN) : !,*(b0) : mem; //-----------------------`(fi.)fb_fcomb`----------------------- @@ -289,7 +290,7 @@ fb_comb(maxdel,N,b0,aN) = (+ <: de.delay(maxdel,N-1),_) ~ *(-aN) : !,*(b0):mem; declare fb_fcomb author "Julius O. Smith III"; declare fb_fcomb copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare fb_fcomb license "MIT-style STK-4.3 license"; -fb_fcomb(maxdel,N,b0,aN) = (+ <: de.fdelay(maxdel,float(N)-1.0),_) ~ *(-aN) : !,*(b0):mem; +fb_fcomb(maxdel,N,b0,aN) = (+ <: de.fdelay(maxdel,float(N)-1.0),_) ~ *(-aN) : !,*(b0) : mem; //-----------------------`(fi.)rev1`----------------------- // Special case of `fb_comb` (`rev1(maxdel,N,g)`). @@ -505,7 +506,7 @@ declare fir copyright "Copyright (C) 2003-2019 by Julius O. Smith III _ with { R(n,(bn,bv)) = (@(n):*(bn)), R(n+1,bv); - R(n, bn) = (@(n):*(bn)); }; + R(n, bn) = (@(n):*(bn)); }; fir(b0) = *(b0); //---------------`(fi.)conv` and `(fi.)convN`------------------------------- @@ -796,9 +797,7 @@ declare allpassnt author "Julius O. Smith III"; declare allpassnt copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare allpassnt license "MIT-style STK-4.3 license"; allpassnt(0,sv) = _; -allpassnt(n,sv) = -//0: x <: ((+ <: (allpassnt(n-1,sv)),*(s))~(*(-s))) : _',_ :+ - _ : ((+ <: (allpassnt(n-1,sv),*(s)))~*(-s)) : fsec(n) +allpassnt(n,sv) = _ : ((+ <: (allpassnt(n-1,sv),*(s)))~*(-s)) : fsec(n) with { fsec(1) = ro.crossnn(1) : _, (_<:mem,_) : +,_; fsec(n) = ro.crossn1(n) : _, (_<:mem,_),par(i,n-1,_) : +, par(i,n,_); @@ -895,22 +894,21 @@ with { // #### Usage // // ``` -// _ : allpassn1mt(n,sv) : _ +// _ : allpassn1mt(N,sv) : _ // ``` // // Where: // -// * `n`: the order of the filter +// * `N`: the order of the filter (fixed at compile time) // * `sv`: the reflection coefficients (-1 1) //------------------------------------------------------------ declare allpassn1mt author "Julius O. Smith III"; declare allpassn1mt copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare allpassn1mt license "MIT-style STK-4.3 license"; allpassn1mt(0,sv) = _; -allpassn1mt(n,sv)= _ <: _,_ : ((+:*(s) <: _,_),_ : _,+ : ro.crossnn(1) +allpassn1mt(n,sv) = _ <: _,_ : ((+:*(s) <: _,_),_ : _,+ : ro.crossnn(1) : allpassn1mt(n-1,sv),_)~(*(-1)) : fsec(n) with { -//0: fsec(n) = _',_ : + fsec(1) = ro.crossnn(1) : _, (_<:mem,_) : +,_; fsec(n) = ro.crossn1(n) : _, (_<:mem,_),par(i,n-1,_) : +, par(i,n,_); innertaps(n) = par(i,n,_); @@ -957,12 +955,12 @@ with { // #### Usage: // // ``` -// _ : allpassnnlt(n,sv) : _ +// _ : allpassnnlt(N,sv) : _ // ``` // // Where: // -// * `n`: the order of the filter +// * `N`: the order of the filter (fixed at compile time) // * `sv`: the reflection coefficients (-1,1) // // #### References @@ -1049,7 +1047,7 @@ wgr(f,r,x) = (*(G),_<:_,((+:*(C))<:_,_),_:+,_,_:+(x),-) ~ cross : _,*(0-gi) with { C = cos(2*ma.PI*f/ma.SR); gi = sqrt(max(0,(1+C)/(1-C))); // compensate amplitude (only needed when - G = r*(1-1' + gi')/gi; // frequency changes substantially) + G = r*(1-1' + gi')/gi; // frequency changes substantially) cross = _,_ <: !,_,_,!; }; @@ -1314,7 +1312,7 @@ declare tf3slf license "MIT-style STK-4.3 license"; tf3slf(b3,b2,b1,b0,a3,a2,a1,a0) = tf3(b0d,b1d,b2d,b3d,a1d,a2d,a3d) with { c = 2.0 * ma.SR; // bilinear-transform scale-factor ("lf" case) csq = c*c; - cc = csq*c; + cc = csq*c; // Thank you maxima: b3d = (b3*c^3-b2*c^2+b1*c-b0)/d; b2d = (-3*b3*c^3+b2*c^2+b1*c-3*b0)/d; @@ -2458,13 +2456,12 @@ levelfilterN(N,freq,L) = seq(i,N,levelfilter((L/N),freq)); declare mth_octave_filterbank author "Julius O. Smith III"; declare mth_octave_filterbank copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare mth_octave_filterbank license "MIT-style STK-4.3 license"; -mth_octave_filterbank(O,M,ftop,N) = - an.mth_octave_analyzer(O,M,ftop,N) : - delayeq(N) with { - fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies - ap(n) = highpass_plus_lowpass(O,fc(n)); // delay-equalizing allpass - delayeq(N) = par(i,N-2,apchain(i+1)), _, _; - apchain(i) = seq(j,N-1-i,ap(j+1)); +mth_octave_filterbank(O,M,ftop,N) = an.mth_octave_analyzer(O,M,ftop,N) : delayeq(N) +with { + fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies + ap(n) = highpass_plus_lowpass(O,fc(n)); // delay-equalizing allpass + delayeq(N) = par(i,N-2,apchain(i+1)), _, _; + apchain(i) = seq(j,N-1-i,ap(j+1)); }; // dc-inverted version. This reduces the delay-equalizer order for odd O. @@ -2473,12 +2470,12 @@ mth_octave_filterbank(O,M,ftop,N) = declare mth_octave_filterbank_alt author "Julius O. Smith III"; declare mth_octave_filterbank_alt copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare mth_octave_filterbank_alt license "MIT-style STK-4.3 license"; -mth_octave_filterbank_alt(O,M,ftop,N) = - an.mth_octave_analyzer(O,M,ftop,N) : delayeqi(O,N) with { - fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies - ap(n) = highpass_minus_lowpass(O,fc(n)); // half the order of 'plus' case - delayeqi(N) = par(i,N-2,apchain(i+1)), _, *(-1.0); - apchain(i) = seq(j,N-1-i,ap(j+1)); +mth_octave_filterbank_alt(O,M,ftop,N) = an.mth_octave_analyzer(O,M,ftop,N) : delayeqi(O,N) +with { + fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies + ap(n) = highpass_minus_lowpass(O,fc(n)); // half the order of 'plus' case + delayeqi(N) = par(i,N-2,apchain(i+1)), _, *(-1.0); + apchain(i) = seq(j,N-1-i,ap(j+1)); }; // Note that even-order cases require complex coefficients. @@ -2533,15 +2530,15 @@ mth_octave_filterbank_default = mth_octave_filterbank5; declare filterbank author "Julius O. Smith III"; declare filterbank copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare filterbank license "MIT-style STK-4.3 license"; -filterbank(O,lfreqs) = an.analyzer(O,lfreqs) : delayeq(nb) with -{ +filterbank(O,lfreqs) = an.analyzer(O,lfreqs) : delayeq(nb) +with { nb = ba.count(lfreqs); fc(n) = ba.take(n, lfreqs); ap(n) = highpass_plus_lowpass(O,fc(n)); delayeq(1) = _,_; // par(i,0,...) does not fly delayeq(nb) = par(i,nb-1,apchain(nb-1-i)),_,_; apchain(0) = _; - apchain(i) = ap(i) : apchain(i-1); + apchain(i) = ap(i) : apchain(i-1); }; //-----------------`(fi.)filterbanki`---------------------- @@ -2569,8 +2566,8 @@ filterbank(O,lfreqs) = an.analyzer(O,lfreqs) : delayeq(nb) with declare filterbanki author "Julius O. Smith III"; declare filterbanki copyright "Copyright (C) 2003-2019 by Julius O. Smith III "; declare filterbanki license "MIT-style STK-4.3 license"; -filterbanki(O,lfreqs) = _ <: bsplit(nb) with -{ +filterbanki(O,lfreqs) = _ <: bsplit(nb) +with { nb = ba.count(lfreqs); fc(n) = ba.take(n, lfreqs); lp(n) = lowpass(O,fc(n)); diff --git a/oscillators.lib b/oscillators.lib index 2debb374..46875db3 100644 --- a/oscillators.lib +++ b/oscillators.lib @@ -1305,8 +1305,7 @@ CZresTriangle(fund,res) = CZ.resTriangle(fund,res); CZresTrap(fund, res) = CZ.resTrap(fund, res); -CZ = - environment { +CZ = environment { saw(fund, index) = sawChooseP(fund, index, 0); sawP(fund, index) = sawChooseP(fund, index, 1); @@ -1466,16 +1465,16 @@ polyblep_triangle(f) = polyblep_square(f) : fi.pole(0.999) : *(4 * f / ma.SR); // Authors: // Dario Sanfilippo // and Oleg Nesterov (jos ed.) -quadosc(f) = tick ~ (_ , _) +quadosc(f) = tick ~ (_,_) with { - k1 = tan(f * ma.PI / ma.SR); - k2 = 2 * k1 / (1 + k1 * k1); - tick(u_0, v_0) = u_1 , v_1 - with { - tmp = u_0 - k1 * v_0; - v_1 = v_0 + k2 * tmp; - u_1 = tmp - k1 * v_1 : select2(1', 1); - }; + k1 = tan(f * ma.PI / ma.SR); + k2 = 2 * k1 / (1 + k1 * k1); + tick(u_0,v_0) = u_1,v_1 + with { + tmp = u_0 - k1 * v_0; + v_1 = v_0 + k2 * tmp; + u_1 = tmp - k1 * v_1 : select2(1',1); + }; }; // end further contributions section From d28e2059539d78c27347f1353eba73c73f3db2ad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 4 Oct 2020 14:37:43 +0200 Subject: [PATCH 10/13] Fix pm.openStringPickUp --- physmodels.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/physmodels.lib b/physmodels.lib index ee16a75d..ff647155 100644 --- a/physmodels.lib +++ b/physmodels.lib @@ -606,7 +606,7 @@ with{ oti = nti*(1-pickupPosition); // pickup to excitation length itb = length*(1-pluckPosition); // pickup to bottom length strChain = chain(stringSegment(maxStringLength,nto) : out : - stringSegment(maxStringLength,oti) : in(excitation) : dispersion : + stringSegment(maxStringLength,oti) : in(excitation) : dispersionFilters : stringSegment(maxStringLength,itb)); }; From 938389463f4f88adeab80232376171b7fd476d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Chaussinand?= <44905254+CesarChaussinand@users.noreply.github.com> Date: Wed, 7 Oct 2020 17:45:40 +0200 Subject: [PATCH 11/13] added quantizer library --- all.lib | 1 + 1 file changed, 1 insertion(+) diff --git a/all.lib b/all.lib index b18c0eda..a0907d33 100644 --- a/all.lib +++ b/all.lib @@ -20,6 +20,7 @@ import("oscillators.lib"); import("noises.lib"); import("phaflangers.lib"); import("physmodels.lib"); +import("quantizer.lib"); import("reducemaps.lib"); import("reverbs.lib"); import("routes.lib"); From b8cafd8182ffe3e8db2cf95a631e93341ea21971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Chaussinand?= <44905254+CesarChaussinand@users.noreply.github.com> Date: Wed, 7 Oct 2020 17:47:07 +0200 Subject: [PATCH 12/13] add quantizer library --- quantizer.lib | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 quantizer.lib diff --git a/quantizer.lib b/quantizer.lib new file mode 100644 index 00000000..27f19e00 --- /dev/null +++ b/quantizer.lib @@ -0,0 +1,225 @@ +//##################################### quantizer.lib ######################################## +// Faust Frequency Quantization Library. Its official prefix is `qu`. +//######################################################################################## + +ba = library("basics.lib"); + +declare name "Faust Frequency Quantization Library"; +declare version "0.0"; + +//=============================Functions Reference======================================== +//======================================================================================== + +/************************************************************************ +************************************************************************ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +************************************************************************ +************************************************************************/ + + +//-------`(qu.)quantize`---------- +// Configurable frequency quantization tool. Outputs only the frenquencies that are part of the specified scale. +// +// Doesn't work as intended for frequencies between -1 and 1. +// +// #### Usage +// +// ``` +// _ : quantize(rf,nl) : _ +// nl = (1,1.2,1.4,1.7); +// ``` +// Where : +// +// * `rf` : frequency of the root note of the scale. +// * `nl` : list of the ratio of the frequencies of each note in relation to the root frequency. +//------------------------ +quantize(rf,nl) = _<: max(-1*_,_):max(1,_)<: octave, _ <: _, !, noteRatio(nN) : rf * _ * _ +with{ + octave = log(_/rf)/log(2)<: + (_<0)*(1/(pow(2,max(0,(-1*(_-1)):int))))+ + (_>=0)*(pow(2,_:int)); + nN = ba.count(nl); + noteRatio(1,oct) = 1; + noteRatio(n,oct) = _ <: (ba.take(n,nl)<((_/oct)/rf))*ba.take(n,nl)+ + (ba.take(n,nl)>((_/oct)/rf))*(noteRatio(n-1,oct)); +}; + + +//-------`(qu.)quantizeSmoothed`---------- +// Configurable frequency quantization tool. Outputs frenquencies that are closer to the frequencies of the notes of the specified scale. +// +// Doesn't work as intended for frequencies between -1 and 1. +// +// +// #### Usage +// +// ``` +// _ : quantizeSmoothed(rf,nl) : _ +// nl = (1,1.2,1.4,1.7); +// ``` +// Where : +// +// * `rf` : frequency of the root note of the scale. +// * `nl` : list of the ratio of the frequencies of each note in relation to the root frequency. +//------------------------ +quantizeSmoothed(rf,nl) = _<: max(-1*_,_):max(1,_)<: octave, _ <: _, !, noteRatio(nN) : rf * _ * _ +with{ + octave = log(_/rf)/log(2)<: + (_<0)*(1/(pow(2,max(0,(-1*(_-1)):int))))+ + (_>0)*(pow(2,_:int))+ + (_==0)*2; + nN = ba.count(nl); + noteRatio(1,oct) = findValue(1,oct); + noteRatio(n,oct) = _ <: (ba.take(n,nl)<((_/oct)/rf))*findValue(n,oct)+ + (ba.take(n,nl)>((_/oct)/rf))*(noteRatio(n-1,oct)); + + findValue(n,oct) = _<: (n Date: Wed, 7 Oct 2020 19:01:14 +0200 Subject: [PATCH 13/13] Update quantizer.lib --- quantizer.lib | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/quantizer.lib b/quantizer.lib index 27f19e00..f7f378cb 100644 --- a/quantizer.lib +++ b/quantizer.lib @@ -49,7 +49,6 @@ For more information, please refer to // // ``` // _ : quantize(rf,nl) : _ -// nl = (1,1.2,1.4,1.7); // ``` // Where : // @@ -143,18 +142,18 @@ pentanat = (1,32/27,4/3,3/2,16/9); // // #### Usage // ``` -// _ : quantize(rf,dimin) : _ +// _ : quantize(rf,kumoi) : _ // ``` // // Where: // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -kumoi = (1,1.0594,1.1892,1.2599,1.4142,1.4983,1.6818,1.7818); +kumoi = (1,16/15,4/3,3/2,8/5); //---------------------`(qu.)natural`-------------------------- -// List of the frequency ratios of the notes of the natural scale. +// List of the frequency ratios of the notes of the natural major scale. // // #### Usage // ``` @@ -165,7 +164,7 @@ kumoi = (1,1.0594,1.1892,1.2599,1.4142,1.4983,1.6818,1.7818); // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -natural = (1,1.125,1.25,1.3333,1.5,1.6667,1.875); +natural = (1,9/8,5/4,4/3,3/2,5/3,15/8); //---------------------`(qu.)dodeca`-------------------------- @@ -180,7 +179,7 @@ natural = (1,1.125,1.25,1.3333,1.5,1.6667,1.875); // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -dodeca = (1,1.0594,1.1225,1.1892,1.2599,1.3348,1.4142,1.4983,1.5874,1.6818,1.7818,1.8877); +dodeca = (1,pow(2,1/12),pow(2,2/12),pow(2,3/12),pow(2,4/12),pow(2,5/12),pow(2,6/12),pow(2,7/12),pow(2,8/12),pow(2,9/12),pow(2,10/12),pow(2,11/12)); //---------------------`(qu.)dimin`-------------------------- // List of the frequency ratios of the notes of the diminished scale. @@ -194,7 +193,7 @@ dodeca = (1,1.0594,1.1225,1.1892,1.2599,1.3348,1.4142,1.4983,1.5874,1.6818,1.781 // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -dimin = (1,1.0594,1.1892,1.2599,1.4142,1.4983,1.6818,1.7818); +dimin = (1,pow(2,1/12),pow(2,3/12),pow(2,4/12),pow(2,6/12),pow(2,7/12),pow(2,9/12),pow(2,10/12)); //---------------------`(qu.)penta`-------------------------- // List of the frequency ratios of the notes of the minor pentatonic scale. @@ -208,7 +207,7 @@ dimin = (1,1.0594,1.1892,1.2599,1.4142,1.4983,1.6818,1.7818); // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -penta = (1,1.1892,1.3348,1.4983,1.7818); +penta = (1,pow(2,3/12),pow(2,5/12),pow(2,7/12),pow(2,10/12)); //---------------------`(qu.)dorian`-------------------------- // List of the frequency ratios of the notes of the dorian mode. @@ -222,4 +221,4 @@ penta = (1,1.1892,1.3348,1.4983,1.7818); // // * `rf`: frequency of the root note of the scale. //------------------------------------------------------------- -dorian = (1,1.1225,1.1892,1.3348,1.4983,1.6818,1.7818); +dorian = (1,pow(2,2/12),pow(2,3/12),pow(2,5/12),pow(2,7/12),pow(2,8/12),pow(2,10/12));