Digital Reverberation

In continuing to explore the many areas of digital signal processing, reverb has cropped up many times as an area of great interest, so I’ve decided to dedicate a series of future posts on this topic.  I’m going to start at the beginning, looking at Schroeder’s design, the first digital reverberator solution, and proceed forward looking at how it’s design was improved upon by Moorer, leading eventually to Feedback Delay Networks (FDN) and other types of artificial reverbs.  All of these stages will include actual implementation, with code/algorithms, and possibly some plug-ins as a result.  However, my goal is not to develop any kind of high-end, competetive product at this point, as some commercial reverb algorithms are closely guarded secrets.  Moreover, digital reverb remains as one of the foremost challenges in DSP.  This process will, however, provide greater understanding of digital audio in addition to honing my skills in DSP coding and design.

Reverberation is of course just a dense series of echoes.  There is also a loss of energy in particular frequency ranges that depend on the material the sound bounces off of.  When all the complexities of natural reverb are accounted for, calculations to simulate this reach into the hundreds of billions or more per second!  Human ears cannot fully perceive the full compelxity of natural reverb, however, so this makes the calculations required much more manageable for many reverb designs (convolution is still very computationally expensive, though).

One of the fundamental building blocks of digital reverb is the comb filter, which Schroeder used in his design.  It circulates a signal through a delay line, adding the delayed version, scaled with a constant, g, to the original.

Comb filter design

The constant g is given by the formula:

where tau (t) is the delay time, or loop time, of the comb filter and RVT is the reverb time desired, which is defined as the time it takes for the delayed signal to reach -60dB (considered silence).

When analyzing the impulse response of natural reverberation, however, we see many dense series of echoes that are not equally spaced out with apparently random amplitudes.  Additionally, the echoes become more diffuse as the amplitudes decrease as the delayed signals build up in the space.  This leads to one of the most important properties of good reverb design, which is the diffusion of the delayed signal’s echoes — in other words it would be unnatural to hear individual pulses as the signal becomes reverberated.  Schroeder proposed the use of four comb filters (in parallel) as one of his solutions to this problem, each with it’s own distinct loop time.  To further ensure the diffusion of echoes, the four loop times should be relatively prime, otherwise the delayed signals would match up too frequently in phase to create a pumping or puffing sound, especially noticeable in the decay.

Another important property of reverb is for the decay to be exponential.  This is satisfied by the comb filter, as can be seen in the above diagram, whereby the impulse response will start out at 1 (assuming an impulse at amplitude 1) and then subsequently being scaled by g, then g2, g3, etc.

To further thicken up the sound of his reverberator, Schroeder fed the summed signals from the four comb filters through two all-pass filters in series.  These filters allow all frequencies to pass, but alter the phase of varying frequencies.  Their design is very much like a comb filter but with a feed-forward section, as can be seen below.

All-pass filter design

The two all-pass filters Schroeder uses also have their own unique loop times just as the comb filters. Unlike the comb filters, however, the reverb time specified for the all-pass filters are different because their purpose is to thicken and diffuse the echoes of the signal, not to apply additional reverberation.

Schroeder accompanied his design with suggested values to simulate a concert hall.  These values are given below (source: Dodge & Jerse, “Computer Music”, pg. 301):

Values for Schroeder’s Reverberator, simulating a concert hall

The RVT value of the comb filters is variable and can be specified by the user, but is normally around the order of 1.o second.

The actual implementation of these two filters is fairly straightforward in C++.  The code is given below:

Code implementing a comb filter

Code implementing an all-pass filter

Now let’s look at some audio samples to hear how this all sounds.  All the code was written by me, including implementation of the comb filters and all-pass filters as well as the mix.  Furthermore, I implemented a wet/dry option into the mixing stage as well as an output level due to the fact that the processed audio can increase in levels quite a bit depending on the source audio.  As far as mixing goes, at its most basic it is just adding signals together, but when mixing several audio buffers (as in the four parallel comb filters) it is a good idea to scale each sample by a factor of 1/N, where N = number of audio buffers being mixed ( 1/(sqrt(N) can also be used in some cases).

Guitar strum, original audio

Guitar strum, single comb filter

In the above example with the single comb filter applied (with a loop time of 29.7 msec) we can hear the distinct echoes/delays of the signal at the beginning.  As the audio decays we can also hear some unnatural pulsation happening (some pulsation is present in the original audio, but the comb filter augments it).

Guitar strum, 4 comb filters & 2 all-pass filters, 100% wet

Adding in all the comb filters and the 2 all-pass networks as per Schroeder’s design diffuses the echoes noticeably and the tail sounds a little more natural as well.  But for a more realistic sound we of course need the dry signal in the mix as well.

Guitar strum, 30% wet mix

It’s worth listening to a more percussive sound to hear the reverb’s effect on it.  Here is a short piano riff and a single comb filter applied to it, and the echo effect is very noticeable and quite disturbing.

Piano riff, original audio

Piano riff, single comb filter

Now applying the reverb in its entirety onto the piano riff with a 30% wet mix results in a more natural reverb.

Piano riff, 30% wet mix

It is, however, not perfect by any means.  We can still hear a slight echo after each attack, and the reverb sound is a little bright and metallic sounding.  As stated at the beginning, the echoes from reverberation lose energy as well as amplitude as they reflect off surfaces and travel through air, and this has not been accounted for in this design.  To improve on this, adding in a simple low-pass filter in the comb filters was used as a solution.  This will be one of the things I’ll be looking at going forward as well as more elaborate reverb designs that attempt to more realistically simulate natural reverberation.

11 thoughts on “Digital Reverberation

  1. Pingback: Programming Algorithmic Reverbs | Creating Sound

  2. Pingback: ASSG – Programming Algorithmic Reverbs

  3. Keith

    Hi There, Great blog and Im loving reading the stuff about plugin and reverb design as Im just getting into that stuff myself. Im currently trying to do Schroeder and Moorer reverbs in VST using JUCE. I was wondering if it would be possible to get a copy of your code from the above? I have implemented the same thing but Im obviously doing something wrong as my reverb sounds very metalic and almost like distinct echos rather than a reverb but having trouble tracking down what I have done wrong in my implementation. Would love to be able to compare with what you did.

    Reply
    1. Christian Post author

      Thanks. Glad you’re finding it helpful.
      Regarding the code, it is unfortunately over 2 years old, and parts of it have since been lost and/or reworked completely.

      Fine-tuning a reverb is tedious business. As long as your delay line(s) are working as exptected, try tweaking your values for the delay/reverb times. You can also add additional comb filters and/or smear the reverb tail with an additional all-pass filter.

      You also want to make sure that your delay times are as mutually exclusive as possible so that the delays intersect as little as possible (i.e. overlap and thus enhance the echo effect).

      Reply
      1. Keith Hearne

        Thanks for the info. I designed it according to the design laid out in schroeder references and the table you have above with the 4 combs in series and the 2 allpasses in series feeding from the combs and instantiated them all with the times given. But sound is nothing like you manage to get. As i mentioned its alot more like slap delay with a tail im getting.
        When calculating result for combs in series is that just an accumulated result adding each result?
        And then just using that result as the input to the allpasses process function? And then again?
        Or is there some other form of calculation for components in series and parallel?

        Thanks for your time and help.

      2. Christian Post author

        Your comb filters should be in parallel, not in series. That would be your problem.

        To process the combs in parallel, pass the original signal into each comb filter, then mix together the four results. This summed signal is then passed through the two all-passes in series. I believe I have a diagram of this in where I discuss the Moorer design (it’s slightly different, but look at the late reflections network where it has 6 combs in parallel that feed into an all-pass).

        Also, watch out for how you mix the four signals from the comb filters together. A trivial way is just to divide each by 4, but this will likely attenuate your final signal by too much. I think I divided by the square root of 4, which seemed to do the trick in my case.

  4. mviljamaa

    Do you happen to have any good resources to share on digital reverbation basics? Have been googling around but much of the information does seem to be a bit scattered and not very constructive.

    Reply
    1. Christian Post author

      It is fairly scattered around from what I recall. The best is to start with a basic Schroeder or Moorer reverb, and build from there.

      For a slightly better look at reverbs (and DSP in general), I would look into some books. A good one to start with is “Designing Audio Effect Plug-Ins in C++” by Pirkle.

      Reply
  5. Jefferson Allan

    Hey Christian,
    Really interesting post (even though it’s a few years old)! Just wanted to mention, the audio examples wouldn’t work for me (“server not found”, apparently).

    Cheers,

    Jefferson

    Reply
    1. Christian Post author

      Thanks. Unfortunately the server they were stored on shut down, so I lost the files. I plan on trying to find a few days I can earmark for fixing up the broken links sometime soon.

      Reply

Leave a comment