Share your delay/reverb designs!

Hello everyone

Something I have always struggled with in any DSP work is the design of nice sounding delay effects.

I would like to see and hear your delay / echo designs for inspiration - so please share it here if you feel like it!

Below is one of mine which is a stereo (actually multichannel, but with “stereo” effects) delay with feedback, lpf in the feedback loop and modulation among other things. All parameters are normalized to 0.0-1.0.

(
~numchans = 2;

~delay = {|in, delay=0.1, delayfb=0.33, decaytime=0.5, delaywidth=0.1, modFreq=0.1, modAmount=0.25, fblowcut=0.5|
	var localIn = LocalIn.ar(numChannels: ~numchans,  default: 0.0);
	var output = Array.fill(~numchans, {|cNum|
		var sig, fb;

		// Random scalar to add variation
		var randScale = Rand(0.95,1.0);

		// Every other channel, scale the delay value according to the delaywidth arg
		var delayScale = if(cNum.even, { delaywidth.linlin(0.0,1.0,0.5,1.5) }, { 1.0 });

		// The final, scaled delayVal to be fed to the modulator 
		var delayVal = lag3(delayScale * randScale * delay.linlin(0.0,1.0,0.0001,2.0));

		// Delaytime modulator
		var phase = cNum.linlin(0,~numchans-1,-8pi, 8pi);
		var lfofreq = (randScale * modFreq.linexp(0.0,1.0,0.0001,10.0)).lag3;
		var minModamount = modAmount.linlin(0.0,1.0,1.0,0.001).lag * delayVal;
		var maxModamount = delayVal;

		delayVal = LFTri.kr(
			Rand(0.99,1.0) * lfofreq, 
			phase
		).linlin(-1.0,1.0, minModamount, maxModamount);

		// Feedback 
		// goes from 0 to 110%
		fb = (delayfb * 1.1 * localIn[cNum]).tanh; // tanh for "limiting"
		fb = DelayL.ar(fb, 0.2, delaytime: Rand(0.1,0.2)); // Avoid phase problems that sound "flat"
		fb = LPF.ar(fb, Rand(0.99,1.0)*fblowcut.linexp(0.0,1.0,40.0,12000.0));

		// The final delay
		sig = AllpassC.ar(
			in[cNum] + fb, 
			2, 
			delayVal,
			decaytime.linlin(0.0,1.0, 0.1,3.0).lag3
		);

		// Filter out potential dc
		LeakDC.ar(sig)
	});

	LocalOut.ar(output);

	output
};

// Play some bullshit testsounds
Pdef(\testy, Pbind(\dur, 0.125, \pan, Pwhite(-1.0,1.0), \degree, Pwhite((-7),7), \amp, 0.75));
Ndef(\testoutput).source = Pdef(\testy);
Ndef(\testoutput).mold(2, 'audio').play;
Ndef(\testoutput)[1] = \filter -> ~delay;
// Normalize all parameters in gui (a hack)
Ndef(\testoutput).controlKeys.do{|k|
	Spec.add(k, [0.0,1.0]);
};
Ndef(\testoutput).gui;

Ndef(\testoutput).play;
)
7 Likes

Here is some inspiration:

Valhalla documentation:
https://valhalladsp.com/category/documentation/

Sean Costello of Valhalla talking about reverbs:

2 Likes

Hey Mads, thanks for sharing!
I have some questions about your code, but i’ll stick with 2:
-why is phase going from -8 to 8pi?(i assumed it was -2 to 2pi)
-why are you not wrapping the functions in a SynthDef?
Thanks a lot

Bumping this thread with some further inspiration:

Tom Erbe describing how he designed his Erbe-Verb eurorack module, with his design goals, constraints, and various examples other historical reverb designs.

The sound isn’t the best but a very good history and practical explanation of reverb algorithms. Good counterpoint to Sean Costello’s I think.

1 Like

An interesting creative idea about reverberation is proposed by Miller Puckette on Pd’s examples (I.08 pvoc reverb).

Piano Reverb
This is a phase vocoder acting as a reverberator. The sound is more coherent (less “whispered”) than a real room or a standard delay-based reverberator.
The technique is to “punch” the incoming sound into channels where (1) there’s a peak, and (2) the incoming sound drowns out whatever might already be there. If the sound already in any channel is louder than the input the input for that channel is ignored.
For each window, the amplitude in each channel is propagated by a constant phase increment and multiplied downward by a gain that determines the “reverb time”.

This is more tricky (and also less efficient) to implement on the language side because you will need to re-window the FFT stream in order to access and manipulate the previous window bins. I hope someday someone implement this as an UGen!

PV_SpectralMap → into a reverb can do this (and I do it a lot) - It takes the spectrum of one sound (either continuous or frozen) and uses it to filter the second input. I often capture a soloist or group playing a chord (for instance), then use that sound as a filter that the performers continue to play through. Feed it into a GVerb with a long decay and it’s magic.

9 Likes

Delicious idea Josh !! I have to try this…

The “reverb” episodes of Reflectives are great, especially this one:

https://youtu.be/AnmY5LFHSVk

Sam

4 Likes

My (rough) implementation of Dattorro’s reverb (mentioned in the videos linked above) in SuperCollider is here:

If I remember correctly, it is NOT true to the paper in terms of where the taps are (and I never bothered to figure out). The code is 3 years old and I don’t think I’ve ever had an example of it as a stand-alone thing. But you might be able to get something out of how i implemented it :slight_smile:

2 Likes