Re: [Faudiostream-users] "ZDF" SVF in C++, could this be converted to FAUST?

2018-08-22 Thread Julius Smith
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?

2018-08-22 Thread Julius Smith
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?

2018-08-22 Thread Oleg Nesterov
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