Gearslutz.com - View Single Post - Reverb Subculture
View Single Post
Old 8th April 2009   #5
dale116dot7
Lives for gear
 
Joined: Dec 2003
Location: Calgary, Alberta
Posts: 816

Thread Starter
In a sample-by-sample processor, probably it is most efficient to be implemented as a lattice structure:

Harmony Central - Digital Allpass Filter

I can't speak for any professional reverb implementer, but after spending a bunch of time with the block diagrams of the Schroeder reverberators and my 'DSP for Dummies book' and the AL3201 programmer's guide, the lattice seems to be the easiest way to do it. In AL3201 assembler, it looks like this:

MEM diff 48
RAPB diff' k=-0.726
WBP diff k=0.726

and takes two clock cycles (or 325 nanoseconds).

The first instruction reads the end of the delay line, stores that value in B (a temporary register), and also takes that value times -0.726 and adds it to the accumulator. Note that the accumulator holds the input.

The second instruction stores the result from the previous multiply into the start of the allpass delay line, and takes the output of the delay line (that was in the B register), and adds the result of the first instruction times 0.726 to that, and the output is now in the accumulator.

If you are cascading allpasses, then you do this:

MEM diff1 48
MEM diff2 109
RAPB diff1' k=-0.726
WBP diff1 k=0.726
RAPB diff2' k=-0.726
WBP diff2 k=0.726

And if you want a time delay in between, you can do this:
MEM diff1 48
MEM diff2 109
MEM dly1 960

RZP ADCL k=0.5 ' read input registers
RZP ADCR k=0.5
RAPB diff1' k=-0.726
WBP diff1 k=0.726
WZP dly1
RZPB dly1'
RBPB diff2' k=-0.726
WBP diff2 k=0.726

and then to mix in a little of in between the allpasses into the output you can add to the end:
RAP dly1" k=-0.15
WAP DACL k=0 ' write to output

This line takes the halfway point between the two allpasses and adds it to the output of the allpass - then sends it to the D-A converter. In terms of a simple reverberator, what this does is take the first early reflections (allpass 1), runs that through a predelay (dly1), then the later reverberator (allpass 2), and sum a bit of the earlier reflections to the output of the second allpass. This reverb will sound awful, but you get the idea. You need to add some filtering... a first-order lag filter after an allpass will look like this:

RBPB diff3' k=-0.726
WBP diff3 k=0.726
WAP dummy k=0.750
RAP dly3+1 k=0.250
WAP dly3 k=0

You can have fun cascading and summing allpasses, filters, combs (which are an allpass with not identical coefficients), delays, and multiple delay taps. Most of the time you get something that sounds awful (except maybe for a sci-fi special effect), but sometimes you get something useful. You can implement a Schroeder reverb quite easily. Although it doesn't sound excellent, it does sound ok. Adding more stages can smooth it out.

Sometimes a creation you make sounds awful but if you know where it rings, you can add a chorus to that allpass to break that up, or you can retune the delay line lengths to move the ringing where it is pretty even. Doing reverb development this way (what I call the 'crash and burn' software development method) is time consuming. It would be far better to implement the algorithm using 'C' or Java or Fortran or something like that, listen to it on a PC, then once it's working, write it for the DSP you're using.

Even though allpasses are nominally flat, they still can 'ring' since in a reverberator, allpasses are usually relatively long and on an impulse you can hear ringing as 'bunching' of the impulses when you look at it in the time domain. If it 'bunches' on an impulse, it will ring when you put audio through it. Another bad artifact is 'repetition' - where you hear a repeating 'tape loop' pattern in the reverb tail. From what I can tell, it means that you have too much long allpass and not enough short allpass.

An interesting thing about the lattice implementation of an allpass is that the audio signal within the allpass is useable, too, where in the middle of a comb filter or probably another allpass implementation it may not be.

A 'z' is a unit delay, if I run the AL3201 at its nominal design frequency (48 kHz sample rate), then a z-1 is 20.8 microseconds, or z-48 is one millisecond. I've occasionally seen the delays specified in milliseconds, too.

The 'crash and burn' software method is an oldie but a goodie. You try running your box (whether it's a reverb or a mobile data terminal or whatever), and when it crashes, you pull out the EPROM chip and burn another one. I'm sure the reverb developers here have been through it. I picked the AL3201 to show the code since it is a very reverb-centered instruction set and it is pretty easy to understand how it works.

Now, Casey will probably correct me on a bunch of points, but that's what I've learned so far.
dale116dot7 is offline   Reply With Quote