View Single Post
Old 09-24-2015, 01:18 PM   #18
Smashed Transistors
Human being with feelings
 
Smashed Transistors's Avatar
 
Join Date: Jul 2014
Location: Là bas les huîtres (FR)
Posts: 424
Default

Quote:
Originally Posted by SaulT View Post
Thank you for the explanation, it really helps. It's making more sense to me now, the question for me is whether I can take this concept and run any further with it. E.g. if there's a way to apply saturation within the algorithm (is "analytically" the correct term?) rather than just tacking it on after the fact, e.g. similar to the tanh stages in a Moog.
Hi SaulT,
here is my first attempt to do such a thing.
The non linearities are evaluated once per sample. I do not use them to modify the internal variables, i use them to change the integrators behavior
(non linear input gains). The aliasing seem low to me (as the saturated signals are integrated they are transformed into triangle waves... just like in the analog filters).

See the comments for details.

Maybe other input functions can be more interesting...
Code:
desc:Ze Nasty Little Filter 02
slider1:sl_pitch1=120<0,150>Pitch1
slider2:sl_pitch0=60<0,150>Pitch0
slider3:sl_D1=1<0.001,1>D1
slider4:sl_D0=1<0.001,1>D0
slider5:sl_rate=4<0,20>rate
slider6:sl_mode=0<0,2,1{LP,BP,HP}>Mode
slider7:sl_drive=0<-12,36>Drive (dB)
slider8:sl_outGain=0<-36,12>Output Gain (dB)
slider9:sl_satType=0<0,3,1{None,Sat3,Tanh,Sat1}>Sat Type

/*
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
                                            Template Filter Structure
                                                   
I use a Chamberlin filter as the filter template.
It is unstable under certain conditions but it offers good resonance
and frequency behavior (sort of "zero delay feedback" thanks to a
combo of backward and forward Euler integrators).
Matrix exponentiations are equivalent to step invariant oversampling.
They solve the stability issues and enforce the "ZDF" properties of
the filter. 

     -1_____________________________
      /___________________          \   Filter
  -D /                    \          \  feedbacks
    v  HP               BP \          \       LP
--> + --->F1-- + -->[Z-1]----->F2-- + --->[Z-1]----->
               ^           /        ^            /
                \_________/          \__________/   Integrator 
                                                    feedbacks


F1: BP integrator gain,  F2: LP integrator gain, D = 1/2Q
for a Chamberlin filter F1 = F2 = F = 2sin(pi*f/2) f:normalized freq      
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
                                                      Non linearities
      
I model non linearities at integrator inputs as non linear gains.
I modulate the integrator gains by non linear functions that depend on
their inputs:

F1 = F * g(HP)
F2 = F * g(BP)
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
                                                    Matrix iterations

The matrix is exponentiated to obtain "step invariant oversampled"
matrixes.
Note: The iterations change the structure of the filter. Note that the
LP integrator is fed with the input signal. This is not a topology
preserving method.
                                                    
Matrix for Chamberlin SVF      Iterated Matrix      Matrix iteration
i.e. Matrix0                                        M <- M^2

    x   LP    BP                  x    LP    BP     a <- a^2 - b*d;
x   1    0    0               x   1     0    0      b <- b * (a+c);
LP  0    1    F2              LP (1-a)  a    d      c <- c^2 - b*d;
BP  F1 -F1    1-DF1-F1F2      BP  b    -b    c      d <- d * (a+c);
                                     |
                                     V
                     LP = (1-a) * x + a * LP + d * BP
                     BP =     b * x - b * LP + c * BP
*/
//____________________________________________________________________
@init
ZNF_iter = 2;
ZNF_coef = (2^(-ZNF_iter-69/12))*440*$pi/srate;
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
// Non linearities seen as gains
// g = cubic soft sat divided by x  --> bell shaped
// todo: tabulate
function tanh(x) ( x = exp(2*x); (x - 1) / (x + 1) );

 function ZNF_gSat1(x)( abs(x) > 1 ? 1 / abs(x) : 1;  );
 function ZNF_gSat3(x)( abs(x) > 1.5 ? 1 / abs(x) : 1 - x * x * (4/27);  );
 function ZNF_gTanh(x)( x == 0 ? 1 : tanh(x) / x;  );
function ZNF_g(x)(
  sl_satType === 0 ? 1
: sl_satType === 1 ? ZNF_gSat3(x)
: sl_satType === 2 ? ZNF_gTanh(x)
: sl_satType === 3 ? ZNF_gSat1(x)
;
);
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
// audio rate process
function ZNF_proc(x pitch _2Q)
local(ac bd x_LP)
instance(LP BP HP F F1 F2 a b c d)(
//                                   once tabulated --> 3 adds 3 muls
  F = 2 * sin(min($pi/2,ZNF_coef*2^(pitch*(1/12)))); // todo: tabulate
  F1 = F * ZNF_g(HP); // gain for BP integrator (its input is HP)
  F2 = F * ZNF_g(BP); // gain for LP integrator (its input is BP)
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
//                                         Matrix init and iterations
//                                         2 + 3i adds    1 + 5i muls
  a = 1;
  b = F1;
  c = 1 - F1 * (_2Q + F2);
  d = F2;
  loop(ZNF_iter,
    ac = a + c;
    bd = b * d;
    a = a*a - bd;
    b = b * ac;
    c = c*c - bd;
    d = d * ac;
  );
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
//                                                        Filter calc
//                                              6 adds         5 muls
  x_LP = x - LP;
  LP = x - a * x_LP + d * BP;
  HP = x - _2Q * BP - LP;
  BP = b * x_LP + c * BP;
);
//____________________________________________________________________
function sat3(x)local(x2)(
  x = min(215/104, max(-215/104,x));
   x2 = x*x;
         x * (1
      + x2 * (     ( -411008.0/1987675.0)
      + x2 * ( ( 11581599744.0/459401384375.0)
      + x2 *( -5061276073984.0/4247165798546875.0))));
);//____________________________________________________________________
@slider
dp = -sl_rate/srate; // positive rate for down ramp
gain = 2^(sl_drive/6);  // input gain
_gain = 2^(sl_outGain/6);     // output gain
//____________________________________________________________________
@sample
p += dp; p -= (p >= 1); p += (p < 0); // lfo phase inc and modulo

pitch = sl_pitch0 + p * (sl_pitch1 - sl_pitch0);
_2Q   =     sl_D0 + p * (    sl_D1 -     sl_D0);

l.ZNF_proc(gain * spl0, pitch,_2Q);
r.ZNF_proc(gain * spl1, pitch,_2Q);

  sl_mode === 0 ? (spl0 = l.LP; spl1 = r.LP; )
: sl_mode === 1 ? (spl0 = l.BP; spl1 = r.BP; )
: sl_mode === 2 ? (spl0 = l.HP; spl1 = r.HP; );
spl0 *= _gain;
spl1 *= _gain;
spl0 = sat3(spl0);
spl1 = sat3(spl1);
__________________
JSFX plugins and synths. See you here and there: SoundCloud, Youtube, Google Play...

Last edited by Smashed Transistors; 09-24-2015 at 04:18 PM.
Smashed Transistors is offline   Reply With Quote