One lonely delay line

There are a lot of different ways to create a digital algorithmic reverb. Let’s start with a very simple one which is based on the idea of a delay line. Imagine if your friend Jack has just hit a snare drum with a stick, the sound wave would travel from the vibrating drum to your ear, but also it would travel up to the ceiling, reflect from there and arrive to your ear with a slight delay (since it needs to travel a longer distance). It would probably also be a bit less loud since parts of the wave were absorbed by air. Implementing this delayed sound in programming is called a delay line. In real world you would have a lot of delay lines in any room, since sound would reflect from all the walls, from the ceiling, and maybe from your dog’s tail as well.

Creating a single delay line is very straightforward. One just takes samples of the input sound (e.g. microphone) and besides outputting them directly to the output (speaker) one stores them in an array, so these samples can be retrieved a bit later and added to the output simulating an echo.

The diagram below shows the process involving something called a circular buffer, which is basically a fixed length array with a write pointer and a read pointer. Whenever a read pointer reaches the end of the array it starts reading from the beginning again. Whenever a write pointer reaches the end of the array it starts writing to the beginning again. We could have just used an dynamic sized array, but it would mean that its length would grow endlessly while we would be using just a small part of it (tail).

Single delay line

To implement a delay line of 1 second (44100 samples, if our sampling rate is 44100 samples per second) we:

Take a sample form an input signal Take s sample from our circular buffer which was written there a second (or 44100 samples) ago Add those two (multiplying a sample from the buffer by some decay coefficient which is less than 1) Write the result to output signal Write the result to delay buffer (so we can read it again and use it in point 2 later)

Now the JavaScript implementation:

Chopin & Audio Worklet

Ok, so we now have our delay line standing there all alone but how can we actually use it in Web Audio API? The answer is Audio Worklet. To know more about it one could go here and here. In a nutshell it allows you to write custom audio processing code which would run in a separate audio thread in a browser, thus with minimal latency.

In our example we will play a piano recording first without a reverb and then using our beautiful single delay line reverb. So again I really recommend reading the resources above, but basically worklet has 2 parts:

Actual sound processor code in the audio thread (will include our delay line code)

Registering and calling this code in the main thread

Original

With a single delay line (basically echo)

GitHub

How to improve the algorithm

Our single line reverb is great, but it does not sound very interesting. An obvious improvement we could make is adding more delay lines. We would also need to ensure that these delay lines would not interfere with each other (think prime numbers for delay times). This way we won’t hear echoes from different lines appear at the same time, making it sound more like a real life reverb. We can also add so called early echoes, the sharp sounds reflected from nearby surfaces.

The downside of this approach is that to get a really realistic reverb we need way too many delay lines. The same affect can be achieved by a combination of all pass filters and comb filters, at which we’ll take a look in the next section.