Re: [Faudiostream-users] "ZDF" SVF in C++, could this be converted to FAUST?
Ok, sounds like they should be compared to the normalized ladder filter. In Faust / filters.lib, the second order case is called tf2sn ("transfer function, order 2, s-plane, normalized). I tend to use tf2snp which adds "p" for "protected". The ladder form provides easy bounding of the poles away from the unit circle by any small margin. Another contender is the "modified coupled form" - same basic recursion as the "magic circle algorithm". It saves multiplies at the cost of giving up exact energy normalization. I'm not sure what you mean by "nonlinearity", but there's a large literature on nonlinear filters as well. I am familiar with some of it. I lean toward filters having a physical interpretation, since then it is usually straightforward to make them do the right thing when time-varying and nonlinear. The hard part is avoiding aliasing when fundamentally there is no physically accurate band-limiting available. Fortunately, there are always various tradeoffs that can be used to get good sonic results. - Julius On Thu, Aug 23, 2018 at 12:54 AM pdowling wrote: > > By the way, I don't know why they are called "zero-delay filters". I > just see second-order digital filters, > > > they are *not* called 'zero-delay filters'. they are called 'zero-delay > feedback (filters)' - 'zdf filters' - the f stands for feedback, as of course > there is no such thing as a filter with no delay :-) > > There's no bell filter, > however, because I don't know what that is. > > > 'bell' is just a fun terminology for 'peaknotch'. > > in the most recent version of the paper simper makes the comparison with > coefficients worked for df1 / df2, and coefficients worked for this zdf svf. > they produce identical (linear) filters. > > they come into their own when 1) modulated - they perform far superior to > df1/2 and 2) when solved for nonlinear behaviour - what the zdF is > essentially for - no unit delay in the feedback path if done correctly, > behave complete differently. > > > thanks, > pete . > > > > On 22 Aug 2018, at 16:49, Julius Smith wrote: > > 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 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) = >
Re: [Faudiostream-users] "ZDF" SVF in C++, could this be converted to FAUST?
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 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 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
Re: [Faudiostream-users] "ZDF" SVF in C++, could this be converted to FAUST?
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); }; -- 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