Hi Oleg, I don't yet know what benefits are offered by ZDFs that are not already covered by the existing filter forms in filters.lib. Search for "Parametric Equalizers (Shelf, Peaking)" in that file, and lowpass, highpass, allpass, and so on. There's no bell filter, however, because I don't know what that is. The classic state variable filter cases (lowpass, bandpass, highpass, notch) are immediately obtained using tf2s, as derived in https://ccrma.stanford.edu/~jos/svf/.
So, except for bell, which I'm happy to add if I can get some doc on what it's for, all of these functions are available already. Your zdf forms presumably have different numerical properties in the LSBs, and they might even result in more or less efficient Faust code. Please let us know if you can make a case for them relative to the existing implementations. By the way, I don't know why they are called "zero-delay filters". I just see second-order digital filters, but implemented in what looks like a state-variable-inspired topology. I suppose I need to read the derivation of ZDFs, which I haven't yet, but I will if they do something the other second-order forms can't do. Note that filters.lib does have alternate forms available already (ladder, lattice, etc.), and there is a literature explaining when and how they are better and under what conditions. I try to give my favorite literature pointers in the comments in the Faust source. Is there such a literature for ZDFs? If so, under what conditions do they win over all the others? Thanks, - Julius On Wed, Aug 22, 2018 at 8:44 PM Oleg Nesterov <o...@redhat.com> wrote: > > On 08/22, Julius Smith wrote: > > > > Hey, thanks for posting. I made a faust2octave test program > > (attached). Everything looks good to me, assuming I guessed all the > > names right. > > Great, thanks. > > do you think it can live in filters.lib? If yes, then I think > "svf = environment" makes sense, so that you can use it like > > process = fi.svf.lp(f,q); > > See the code below. Note that this version differs a little bit, it uses > the second version described in that paper (see "algorithm using v1 to > compute v2"). > > iow > > v2 = ic2eq + g*v1; (2) > > instead of > > v2 = ic2eq + a2*ic1eq + a3*v3; (1) > > I think it makes more sense for faust because it is simpler, and because > quite possibly faust will turn (2) into (1) after aterm/mterm normalization > anyway. > > I even verified that "all pass" generates the same code with this change. > > Oleg. > > ------------------------------------------------------------------------------- > svf = environment { > svf(T,F,Q,G) = tick ~ (_,_) : !,!,_,_,_ : si.dot(3, mix) > with { > a1 = 1/(1 + g*(g + k)); > a2 = g*a1; > > tick(ic1eq, ic2eq, v0) = > 2*v1 - ic1eq, > 2*v2 - ic2eq, > v0, v1, v2 > with { > v1 = a1*ic1eq + a2*(v0 - ic2eq); > 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); > }; > > -- Julius O. Smith III <j...@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/ ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/faudiostream-users