Im creating an effect plugin with different kinds of reverb and wish to create a reverse reverb effect, similar to those you would find in rack-effects or certain multifx guitar pedals. What would be the best way to go about making this?
Any way to create a reverse reverb?
Hi Zobban. Yes. Perhaps the easiest way is to write the reverb output to an ftable & play that backwards, not sure if there are other options. Here’s an example of realtime writing to a table:
https://flossmanual.csound.com/csound-language/function-tables#a-rate-example
(see 03D08_RecPlay_ak_signals.csd)
It seems necessary to window that to avoid clicks if you’re playing back the table in reverse. The example below uses a custom window shape (GEN16 works well for this, you can create a very wide, flat shape with steep exponential fade in/out). A standard sinc or Hanning window seemed too invasive.
An example:
[https://www.dropbox.com/scl/fi/gm2s9l0hvpzq1575asqm0/reverse_reverb.mp3?rlkey=02spbmxca15b947l1a423tw4n&dl=0]
Could you also write the dry signal to a table and then play that back backwards through a reverb? I’m not sure, but would that give you the same effect? If so, here is a UDO from Victor Lazzarini from ages back that will handle the reversing of the dry signal:
/*
SigReverse - A table-based reversing opcode.
DESCRIPTION
SigReverse takes short snapshots of a signal and then plays then back in reverse.
SYNTAX
asig SigReverse ain, kfade, ifn1, ifn2
INITIALIZATION
ifn1 - table to be used to hold the recorded signal. The size of the table will determine the length of the recorded snapshot.
inf2 - window used to smooth the edges of the recorded snapshot (1/2 sine, hanning or triangle window, etc.)
PERFORMANCE
asig - reversed output
ain - input signal
kfade - this can be used to fade in/out the second playback tap, which is offset by 1/2 table in relation to the first. The second tap provides a more continuous signal, but also some echoes as side-effect
CREDITS
Victor Lazzarini, 2005
*/
opcode SigReverse, a, akii
setksmps 1
asig,kfd,ifn,iwin xin
kwp init 0
awp = kwp
ilen = ftlen(ifn) /* size of delay */
tablew asig, awp, ifn /* delay writing*/
as1 table -kwp, ifn, 0, 0, 1 /* reverse tap 1 */
as2 table -kwp, ifn, 0, ilen/2, 1 /* reverse tap 2 */
kenv table kwp*2,iwin, 0, 0, 1 /* crossfade envelope */
amix = as1*kenv + as2*(kenv-1)*kfd /* mix */
kwp = kwp + 1
if kwp > ilen then
kwp = 0
endif
xout amix
endop
@rorywalsh FWIW, that won’t provide the same type of effect. Think of a short note reversed & thru reverb, a fast rise & ambient reverb tail that might last a few seconds. Which also sounds really cool:
[https://www.dropbox.com/scl/fi/ko9rxjdz6hvel902usebe/reverse_delay.mp3?rlkey=0t4x6lwhoe5lqcowko2bn73l4&dl=0]
A reverse reverb can give you a long ambient swell that cuts off sharply, sometimes leading into the played note.
A few issues with that code you posted in regards to using for reverse delay or reverb, although I know it’s primarily intended as a foundation. For one, writing in realtime with tablew will cause random single sample or multi-sample dropouts, even at setksmps = 1. I documented that here:
[https://discord.com/channels/784849854270537790/786239959342121021/1217409861784961085]
If tabw/tab are used, and a phasor to read/write the tables, you can use any size ksmps without issue & it’s still sample accurate. A bit more efficient I think (?), as are tab/tabw. I’m not sure they were available in 2005(?). I suppose the phasor could also run at k-rate and be converted using a(kPhs):
ex. tab(aSig, a(kPhs), iTab, 1)
but I’m not sure that would be any more efficient(?).
Also, there’s no protection to write silence to the table when the instr stops playing, so if you extend the UDO with xtratime to allow the last delays to continue after the instr is finished playing it can be problematic, depending on how it’s implemented (UDO in the instr vs in a seperate send instr vs used in a live playing situation, always on etc.).
Another issue is declick enveloping. A Hanning or triangle can be really invasive. Often reverse delays/reverb use long delay times, like > 3 seconds, so you get nice phrases, like Hendrix “Are You Experienced” . So if you have a delay time of say 3 seconds with a Hanning, you can lose much of the detail, especially with plucky timbres. It would take 1.5 sec each for attack and decay. With GEN16 you can create a long flat table with att/dec around 10ms without aliasing. Here’s a few pics to illustrate Hanning/sinc win vs GEN16 with a 2 sec delay. In the second pic you can see how the env decays over 10ms.
One other thing, it’s nice to have the read/write tables inside the UDO and setup to just accept the delay time (loop length) as a variable in seconds. Here’s an example, in this case a reverse reverb which goes thru another reverb: Sorry for the long post but some (relatively) important considerations for anyone attempting this.
Don’t apologise, this is super useful info. It’s a long time since I used that UDO, and I’ve a feeling it popped up some time in the early 2000s. However, I do remember getting a lot of mileage out of it! The sndloop opcodes probably deserves a mention here too.
Have you considered using convolution techniques for this? A different approach than the algorithmic-type reverbs, but for something like reverse or other special effects it might be easier to implement successfully.
More here: https://flossmanual.csound.com/sound-modification/convolution
There’s also some good discussion here: https://www.kvraudio.com/forum/viewtopic.php?t=599376
@Bryan_T Hi Bryan. Thanks for the links, I did check them out; I am somewhat familiar with convolution.
Certainly using convolution could be an interesting option, although I’m not sure easier to implement, just different. I think both have their pros & cons & for me the devil is in the details:
• optionally allowing the dry signal to be delayed/time shifted - having the reverb precede notes, or not
• adapting that concept to allow for different use cases, such as real-time use vs offline rendering
• optionally running the reversed reverb and/or dry input thru a second reverb
• allowing control of the sends/returns/levels of the 3 signals (reversed rvb, post rvb, input)
• windowing if necessary
• allowing flexibility of the default declick window shape & the option to instead allow the user to use their own (currently the default window shape is the long primarily flat one but allows for optionally altering the attack/decay slopes, similar to transeg)
By the last point I mean that if the reverb tail is roughly 5 seconds (reverbsc doesn’t have the option to set reverb length by time) but you want it to be a 2 second swell upwards you might want a specific window shape, like a linear or exponential rise so the reverb doesn’t come in loud right away - no swell. The env might optionally be applied directly to the reverb tail before reversing instead of applying after reading the reverse audio.
In some cases convolution would make things easier (reading the impulse response length at init). And there is large amount of quality impulses out there. One tradeoff being one would have to already have reverse reverb impulses or take the time to do that manually, not a big deal but extra steps involved. And if distributing in a plugin/synth make sure they’re clear to share. I’m also unsure of any potential differences in performance (cpu usage).
One approach (algorithmic) is slightly more useful right out of the box, the other probably more flexible but a bit more hands on for the user (finding, choosing & loading ir’s).
As it stands, I’m pretty happy with the implementation although there’s still some fine-tuning to do (moving everything into a single UDO which wouldn’t be necessary in a Cabbage plugin). And it will accept Csounds reverb opcodes (mono/stereo) or if one wants to instead use convolution they could. Without the necessity of using reverse reverb impulses, the UDO would do that automatically. But that would currently still require using the read/write tables. If it was written to specifically use existing reverse reverb ir’s there could possibly be performance benefits.
Hello,
You need to follow these steps:
- Capture the Input Signal: Record a buffer of the incoming audio signal.
- Apply Reverb: Process this buffer with a standard reverb algorithm.
- Reverse the Buffer: Reverse the processed reverb buffer.
- Playback: Blend this reversed reverb buffer with the original signal, aligning it appropriately.
I hope this will help you.