Why is reverb a black-art?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

mystran wrote:Additional footnote on the above: I'm sure it decomposes into some sort of lattice structure that nests all-pass filters, but last I tried I couldn't figure out how to go from a feedback filter to such a lattice easily.. I'd love to hear suggestions. :P
US Patent 5671287, figure 9b. Note that the concepts in the figure aren't covered in the claims of the patent - it is the stuff in 9c that is the subject of this patent. Similar tricks with allpass delays were first described by Date and Tozuka in 1966.

Note that if you have a filter or some other processing in series with the delay line inside of the allpass, things will be stable as long as the gain doesn't exceed 0 dB for any frequency. The results won't be entirely allpass, but you can use this in the same place as an allpass delay in the context of a reverb (series configurations, inside a feedback loop, etc.). Jot and Dahl have a patent on this from Creative Labs in a patent from the early 2000s, but Jot also published this "absorbent allpass" design in his PhD thesis from 1992, and did not mention it in the 1995 patent linked to his thesis, so these absorbent allpasses are not covered by a valid patent IMO. Plus, putting a linearly interpolated delay line inside of an allpass causes similar filtering, so the earliest Lexicons would have been using this trick. Gerzon also mentioned shelving filters inside of allpass delays (that break the allpass characteristics) in a 1972 paper.

Sean Costello

Post

valhallasound wrote:
mystran wrote:Additional footnote on the above: I'm sure it decomposes into some sort of lattice structure that nests all-pass filters, but last I tried I couldn't figure out how to go from a feedback filter to such a lattice easily.. I'd love to hear suggestions. :P
US Patent 5671287, figure 9b. Note that the concepts in the figure aren't covered in the claims of the patent - it is the stuff in 9c that is the subject of this patent. Similar tricks with allpass delays were first described by Date and Tozuka in 1966.
Thanks. Didn't know about the patent though, and that kind of stuff seems to be rarely cited. Interesting paper in general. :)
Note that if you have a filter or some other processing in series with the delay line inside of the allpass, things will be stable as long as the gain doesn't exceed 0 dB for any frequency. The results won't be entirely allpass, but you can use this in the same place as an allpass delay in the context of a reverb (series configurations, inside a feedback loop, etc.).
Sure, but that's a different thing and pretty much always mentioned everywhere, along with some basic formulas of how to get started with designing the filters for that. In practice you probably want to do both obviously. :)

Post

Oh and a detail regarding absorbent all-pass filters that I learned the hard way: when using elementary first-order shelving filters you probably want to set nominal cutoff to something like the half dB gain (rather than pole angular frequency; both variations are common in cookbooks) when matching decays for different delays. Otherwise you'll probably end up with un-even decay (ie ringing modes an stuff) near the cutoff. Similar considerations apply for higher order filters obviously.

Post

Robin from www.rs-met.com wrote:looking at this:

https://ccrma.stanford.edu/~jos/pasp/Al ... Combs.html

and boldly generalizing - would it be sufficient to just plug the exact same filter (as in the feedback path) into the feedforward path for this compensation?
OK - i tried to derive that it indeed works that way - but it doesn't. the derivation looked promising until the last step. so it's actually useless - you probably don't want to waste your time reading it. i wrote it down anyway because i realized too late that it doesn't work. so here we go:

let the coefficient b0 = aN be replaced with the transfer function G(z). we then have the overall transfer function:

Code: Select all

        G(z) + z^-N
H(z) = ------------------
         1   + G(z)*z^-N

with the magnitude-squared response:

Code: Select all

    
M^2(w) = |H(e^(j*w))*H(e^(-j*w))|
     
          G(w) + e^(-j*N*w)          G(-w) + e^(j*N*w) 
       = ------------------------ * -------------------------
           1   + G(w)*e^(-j*N*w)      1    + G(-w)*e^(j*N*w) 
		 
          G(w)*G(-w) + G(w)*e^(j*N*w) + G(-w)*e^(-j*N*w) + 1
       = -----------------------------------------------------
           1 + G(-w)*e^(j*N*w) + G(w)*e^(-j*N*w) + G(w)*G(-w)

reordering terms:

Code: Select all

		   
           1 + G(w)*G(-w) + G(w)*e^(j*N*w) + G(-w)*e^(-j*N*w)
M^2(w) = -----------------------------------------------------
           1 + G(w)*G(-w) + G(-w)*e^(j*N*w) + G(w)*e^(-j*N*w)	


the first two terms in numerator and denominator agree already, the third and fourth don't. so, in order to ensure that this magnitude response is unity for all w, we need to ensure that sum of the third and fourth term in numerator and denominator also agree. in this case, we must have:

G(w)*e^(j*N*w) + G(-w)*e^(-j*N*w) = G(-w)*e^(j*N*w) + G(w)*e^(-j*N*w)

if this equation can be shown to be true for all G(w) and all w, H(z) would indeed be allpass for any choice of G(z). so let's try it. first, G(w) is assumed to be a transfer function with real coefficients, so it has conjugate symmetry: G(-w) = G'(w) where the prime is used to denote complex conjugation. furthermore, we note that e^(-j*N*w) is the complex conjugate of e^(j*N*w). let G(w) be the complex number z1 and e^(j*N*w) be the complex number z2. with this identification, we can write down the eqution above as:

z1 * z2 + z1' * z2' = z1' * z2 + z1 * z2'

let z1 = a + j*b, z2 = c + j*d. the left hand side is:

(a + j*b)*(c + j*d) + (a - j*b)*(c - j*d)
= a*c + a*j*d + j*b*c - b*d + a*c - a*j*d - j*b*c - b*d
= 2*(a*c - b*d)

the right hand side is:

(a - j*b)*(c + j*d) + (a + j*b)*(c - j*d)
= a*c + a*j*d - j*b*c + b*d + a*c - a*j*d + j*b*c + b*d
= 2*(a*c + b*d)

so our equation is now:

2*(a*c - b*d) = 2*(a*c + b*d)

which is not true for any pair arbitrarily chosen complex numbers. we may still interpret it as a constraint. the equation is true if and only if -b*d = +b*d, so we must have b*d = 0. a product is zero whenever (at least) one of the two factors is zero. the factor d is outside our control since it's given by d = Im(z2) = Im(e^(j*N*w)). the other factor b = Im(z1) = Im(G(w)) is the imaginary part of our transfer function G(z). so, as end result, we have shown that:

Code: Select all

        G(z) + z^-N
H(z) = ------------------
         1   + G(z)*z^-N
is allpass if and only if G(w) has zero imaginary part for all w which is not possible (i think) except for trivial transfer function G(z) = const. so this is all useless. unfortunately. thanks for wasting your time reading that.

edit: so thx mystran for giving a method that actually works.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

mystran wrote:
Note that if you have a filter or some other processing in series with the delay line inside of the allpass, things will be stable as long as the gain doesn't exceed 0 dB for any frequency. The results won't be entirely allpass, but you can use this in the same place as an allpass delay in the context of a reverb (series configurations, inside a feedback loop, etc.).
Sure, but that's a different thing and pretty much always mentioned everywhere, along with some basic formulas of how to get started with designing the filters for that. In practice you probably want to do both obviously. :)
I don't know if you need to do both.

The filter in series with the delay, inside the feedforward/feedback path, will be closest in behavior to the parallel combs w/filters used in an FDN. If you want an initial freq response that is close to allpass, you can use filters to equalize the outputs of the network.

The conjugate filters + allpass trick (or the conjugate filters + delay trick if FIR filters are used) will create a truly allpass response, where the allpass has different decay rates for different frequencies but always has a flat frequency response. Which is cool, but isn't necessarily what you need for reverb. These "fancy" allpass filters are a solution in search of the right problem, IMO.

Sean Costello

Post

valhallasound wrote: These "fancy" allpass filters are a solution in search of the right problem, IMO.
I'd disagree on that(if I understand your sentiment correctly). Diffusion in real rooms - increase with frequency, and a "fancy" allpass could be a solution to that problem.

Andrew

Post

mystran wrote:Additional footnote on the above: I'm sure it decomposes into some sort of lattice structure that nests all-pass filters, but last I tried I couldn't figure out how to go from a feedback filter to such a lattice easily.. I'd love to hear suggestions. :P
I've just tried "reverse" brute force approach: I've calculated response of "second order" nested allpass. Result is:
(b + a*b*z^-N + a*z^-M + z^-N-M)
-----------------------------------
(1 + a*z^-N + a*b*z^-M + b*z^-N-M)

("outer" allpass has coefficient b and delay line constructed from M sample delay in series with "inner" allpass with coef a, N sample dly. )
if you set N=1 you get same thing as last response in your previous post. Furthermore, b = b1, a = a1 and b0 = a*b. Now protofilter you've started with looks like this:

(b0+b1*z^-1)/(1+a1*z^-1) = (a*b + b*z^-1)/(1 + a*z^-1).

This is shelving filter but you loose one degree of freedom with parameters, I haven't checked how will this proto behave versus variation of a (I assume that b is fixed).
What's funny for me is that I've played with nested allpass structures but I've constructed directly desired phase response, I would never guessed that it could have "equalised feedback" interpretation.
Ichad.c wrote:Diffusion in real rooms - increase with frequency, and a "fancy" allpass could be a solution to that problem.
Thing is, I doubt there is a room on this planet that has "perfectly flat" losses (not even that majestic CR in Blackbird Studios). So, if diffusion is not perfectly allpass in real world rooms why insist for such behavior in reverb algo?

OTOH, I remember this thingie called "comb pass" - allpass with intentionally asymetric ff and fb paths. I don't remember details, some of Lexi guys proposed such structure, less perceived ringing? Sean, I guess you know bout this, can you shed some light?

Post

urosh wrote:
Ichad.c wrote:Diffusion in real rooms - increase with frequency, and a "fancy" allpass could be a solution to that problem.
Thing is, I doubt there is a room on this planet that has "perfectly flat" losses (not even that majestic CR in Blackbird Studios). So, if diffusion is not perfectly allpass in real world rooms why insist for such behavior in reverb algo?
That's how I feel. Rooms aren't allpass, and a filter in series with the delay line will give you realistic damping at a MUCH cheaper CPU cost than the "fancy" allpasses.
urosh wrote: OTOH, I remember this thingie called "comb pass" - allpass with intentionally asymetric ff and fb paths. I don't remember details, some of Lexi guys proposed such structure, less perceived ringing? Sean, I guess you know bout this, can you shed some light?
Notchpass. Invented & patented by Barry Blesser. The patent is now assigned to Lexcion, and was used by them in the PCM92/96, PCM plugins, and MPX plugin (I haven't checked the LXP plugin).

The idea behind the notchpass is to equalize the filter, so that the frequencies with the biggest peaks in group delay are notched out. This results in some sort of flatter response or something over time.

I haven't paid attention to the details, as 1) the filter is patented, and I first heard about it from the patent, and 2) at least one reverb notable (Casey Dowdell) has suggested that the long term decay improvements come at the expense of short term coloration.

Back when I worked at Analog Devices, I did some work for a company that I won't name (I can only say that they make Jet Skis, alto saxophones, snowmobiles, power generators, scooters, and golf carts). The company wanted some DSP blocks, and specifically requested 4-coefficient allpass delays. We pointed out that an allpass could be made with 2 multiplies, or 1 multiply and 3 adds, but they insisted on having 4 multiply forms. Now that I think about it, I wonder if they had some specific "non-allpass" way of calculating the allpass, that they used in room/ambience processing.

Sean Costello

Post

valhallasound wrote:
urosh wrote:
Ichad.c wrote:Diffusion in real rooms - increase with frequency, and a "fancy" allpass could be a solution to that problem.
Thing is, I doubt there is a room on this planet that has "perfectly flat" losses (not even that majestic CR in Blackbird Studios). So, if diffusion is not perfectly allpass in real world rooms why insist for such behavior in reverb algo?
That's how I feel. Rooms aren't allpass, and a filter in series with the delay line will give you realistic damping at a MUCH cheaper CPU cost than the "fancy" allpasses.
There has been somewhat of a semantic misunderstanding. I said diffusion, not damping nor losses :wink:
Wasn't thinking of using mystran's approach as is - but something in a similiar vein - should have clarified that, sorry!
Think of a room with a metal chair in it - now add a broadband signal - physics says - high frequencies will be reflected by the chair - and low frequencies will wrap around the chair, now do that a couple million times and in simple terms - diffusion increases with frequency. That's one thing I've always wondered about simulating. I've read somewhere that some reverb "mesh" topologies have that quality, but can't figure out what particulary causes it. I tried recently to code a simple "mesh" but I messed it up badly -> the signal flow confuses the hell out of me :oops:

Post

When you have a single all-pass filter, you'll have essentially exponential decay. When you put bunch of them in series, you'll start getting slower attack too if the decays of the individual all-pass filters are long enough.

If you look back I put "diffusion" in quotation marks. That's actually because "diffusion" wasn't really why I'd want to do it. The real reason is that in a closed loop you can control the envelope of the tail at different frequencies separately, while still having separate control over overall decay.

Oh and I'd like to reiterate that I think putting a (lossy) filter in series with the delay is the first thing to do. The fancy all-pass stuff I'm talking about is rather something you'd add on top of that if you think it's useful (I do).

Post

Anyway, whatever Sean is doing with early energy seems quite interesting. Wouldn't you want to give us some tips? ;)

Post Reply

Return to “DSP and Plugin Development”