This applet contains an implementation of a reverb as described by Steiglitz in his book "A Digital Signal Processing Primer with Applications to Digital Audio and Computer Music", pages 290 -- 295.
This patch uses several containing patches and would be best explained in a diagram which eventually I'll produce here.
Here's a home recording of me playing my Persian ney, dry and reverbed using this reverb patch.
The input signal is filtered through 6 parallel comb filters (delay feedback loops) with a lowpass filter in each loop. Each comb filter is characterized by a feedback coefficient, a low-pass filter coefficient g, from the lowpass transfer function H(z) = 1/(1-g/z), and a delay time. The result of summingthe 6 comb filter outputs is fed through an allpass filter, which is characterized by a delay, and a coefficient a. The allpass transfer function is H(z) = (z^-{m}+a)/(1+a*z^{-m}). The final result is mixed with the original signal.
You can reverberate a recording or a mike input (if your security allows mike input through your browser).
All parameters can be set with the sliders. Try increasing the delays to get a Taj-Mahal effect. If you boost the feedback too much the filter will become unstable (negative absorbtion). AGC will then turn things off untill you reset it. You can always get the defaults back by pressing a button. I guess it's clear *which* button...
If you have no mike the AGC will boost the noise in your soundcard and reverberate that. Latency is terrible. Download JASS and reduce the buffersizes if you have low latency JavaSound implementation like Tritonus, if you can't live with it.
Source code:
import java.io.*; import java.net.*; import jass.render.*; import jass.engine.*; import jass.generators.*; import jass.patches.*; /** CombReverb using Moorers reverb. See e.g. @book{Steiglitz96, title = {A Digital Signal Processing Primer with Applications to Digital Audio and Computer Music}, author = {Ken Steiglitz}, publisher = {Addison-Wesley}, address = {New York}, year = {1996}, pages = {290--295}} Defaults are for 25Khz sampling rate from Steiglitz book. @author Kees van den Doel (kvdoel@cs.ubc.ca) */ public class ReverbApplet extends AppletController { int bufferSize = 16; // no feedback loop can have smaller delay than this int bufferSizeJavaSound = 0; // use huge default latency float srate = 44100; SourcePlayer player; AudioIn input; ConstantLoopBuffer loopbuf; // another source String wavfile = "../data/hello.wav"; boolean useMike = false; float impulseT = 1f; //second CombReverb reverb; int nReflections = 6; // Reverb parameters float[] combDelays = {.05f,.056f,.061f,.068f,.072f,.078f}; // delays in seonds float allpassDelay = .006f; // delay in seconds float a = .7071068f; // allpass parameter float[] R = {.4897f,.6142f,.5976f,.5893f,.581f,.5644f}; // feedback comb parameters float[] g = {.24f,.26f,.28f,.29f,.3f,.32f}; // low-pass comb parameters float dryToWet = .1f; // 1 is dry only double minDelay = 1.3*(bufferSize/srate); // smalles feedback delay possible public void setNSliders() { nsliders = nReflections*3 + 3; } public void setNButtons() { nbuttons = 3; } protected void createPatch() { URL wavurl = null; try { wavurl = new URL(getCodeBase(),wavfile); } catch(MalformedURLException e) { System.out.println(e+" Malformed URL: " + wavfile); } player = new SourcePlayer(bufferSize,bufferSizeJavaSound,srate); if(useMike) { input = new AudioIn(srate,bufferSize,bufferSizeJavaSound); } else { loopbuf = new ConstantLoopBuffer(srate,bufferSize,wavurl); } reverb = new CombReverb(bufferSize,srate,nReflections); try { if(useMike) { reverb.addSource(input); } else { reverb.addSource(loopbuf); } player.addSource(reverb); } catch(SinkIsFullException e) { System.out.println(e); System.exit(0); } for(int i=0;i