Spring reverb
Moderator: frank
-
- Posts: 53
- Joined: Thu Jan 07, 2010 2:29 pm
- Location: Windsor, Colorado
Spring reverb
Hello all. I haven't been doing FV-1 stuff for a while, but my son asked me if I could do a spring reverb. I was surprised at how little info there was on the forum. Learning more about it, I see why now. It is totally unlike other reverb algorithms, and it is hard to do. Being a retired electrical engineer, I decided to wade through what technical papers I could find on the subject, and then see what I could do on the FV-1. Here is a short tutorial if anyone is still interested:
Spring reverb has unique sound due to the way sound travels down the spring itself. High frequencies travel slower than low frequencies, a characteristic called "dispersion". The classic "boing" of a tapped spring results from the impulse being dispersed into a "chirp".
Simulating the dispersion of the spring requires a "spectral delay filter". It can be implemented with a very large number of unit delay allpass filters. The allpass provides a frequency-dependent phase shift. Put a lot of them in series and the phase shift adds up to a delay.
We need many milliseconds of delay of the high frequencies for the effect to be noticeable - 8ms at 32KHz sample rate is 256 allpasses! All is not lost, though. If we bandwidth-limit the signal, we can "stretch" the allpasses by going from unit delays to longer delays. Not hundreds of samples like conventional "reflection emulating" reverbs - more like 3 or 4 samples. At 4, now we are talking 64 allpasses. The FV-1 does one allpass in two instructions, so this would totally fill the program memory. We need to compromise further to get anything else done, but we are at least in the ballpark.
Add a couple of long simple delays in front of the allpass string, some filtering, and feedback around the whole thing. This is as close as we are going to get to a spring reverb within the confines of the FV-1.
I have coded it up and it indeed sounds "springy". I don't have a real spring reverb to compare it too, though. This has just been an intellectual exercise for me - no intent to develop a product.
I hesitate to share code because I don't want to field questions about what each line of code does or how to change it. I think that the information I have provided here should be enough for any FV-1 jockeys out there to get started.
Good luck,
Don
Spring reverb has unique sound due to the way sound travels down the spring itself. High frequencies travel slower than low frequencies, a characteristic called "dispersion". The classic "boing" of a tapped spring results from the impulse being dispersed into a "chirp".
Simulating the dispersion of the spring requires a "spectral delay filter". It can be implemented with a very large number of unit delay allpass filters. The allpass provides a frequency-dependent phase shift. Put a lot of them in series and the phase shift adds up to a delay.
We need many milliseconds of delay of the high frequencies for the effect to be noticeable - 8ms at 32KHz sample rate is 256 allpasses! All is not lost, though. If we bandwidth-limit the signal, we can "stretch" the allpasses by going from unit delays to longer delays. Not hundreds of samples like conventional "reflection emulating" reverbs - more like 3 or 4 samples. At 4, now we are talking 64 allpasses. The FV-1 does one allpass in two instructions, so this would totally fill the program memory. We need to compromise further to get anything else done, but we are at least in the ballpark.
Add a couple of long simple delays in front of the allpass string, some filtering, and feedback around the whole thing. This is as close as we are going to get to a spring reverb within the confines of the FV-1.
I have coded it up and it indeed sounds "springy". I don't have a real spring reverb to compare it too, though. This has just been an intellectual exercise for me - no intent to develop a product.
I hesitate to share code because I don't want to field questions about what each line of code does or how to change it. I think that the information I have provided here should be enough for any FV-1 jockeys out there to get started.
Good luck,
Don
Don Stavely
-
- Posts: 338
- Joined: Mon Nov 12, 2012 1:12 pm
- Contact:
The "Chirp" block in SpinCAD Designer recent builds was an idea taken from a paper I read about DSP emulation of spring reverb. I did some experiments to see if I could get a spring sound. I got as far as something that sounded pretty wild on percussive material but does not like sustained tones at all.
-
- Posts: 53
- Joined: Thu Jan 07, 2010 2:29 pm
- Location: Windsor, Colorado
Spring reverb
I said I was hesitant to post the code, but what the hell:
Code: Select all
; SPRING REVERB (c) 2016 Don Stavely
; Please, not for commercial use!
; Description:
; Spring reverbs sound "boingy" because of dispersion in the spring -
; higher frequencies travel slower than low frequencies.
; A "spectral delay filter", consisting of many (100's) of unit allpasses
; will produce the desired "chirp" impulse response.
; The number of APs can be reduced by "stretching" the allpass filters,
; using delays larger than one.
; Using different chirp AP lengths spreads the eigentones (?)
; Reverb loop looks like std X-coupled AP-AP-DELAY loops, but inputs
; and outputs moved so first echos straight out of delays, not APs.
;
; +-------------------------------------+
; | |
; in---[+]- | --[ D1 ]--[lp]--+--[AP1a]--[AP1b]-+
; | | |
; | | [+]---------------->[CHIRP APs]--->
; | | |
; in----| -[+]--[ D2 ]--[lp]--+--[AP2a]--[AP2b]-+
; | |
; +-----------------------------------------+
;
; Delay, AP lengths scaled from GA reverb, modded close to Accutronics
; 2-spring delay lengths of 33ms and 41ms.
; Filtering inside the loop and sin/cos LFO smearing of the reverb APs
; also reduces ringing.
; Oh, and it has tremolo so my son can use it for surf rock. You could
; add tone and reverb time controls instead.
;
; Pot0 = Reverb Level
; Pot1 = Tremolo Rate
; pot2 = Tremolo Depth
; Declare constants
equ LEN1 5 ; length of chirp filters
equ LEN2 6
equ LEN3 6
equ LEN4 7
equ LEN5 7
equ LEN6 8
equ KAP -0.6 ; chirp allpass coefficient
equ KLAP 0.6 ; allpass coefficient
equ KRT 0.85 ; reverb time
equ KRF 0.55 ; reverb lpf freq
equ KRS -1 ; reverb lpf shelf
; Memory declarations
mem lap1a 404 ; GA/2 = 404
mem lap1b 967 ; 967
mem d1 1445 ; 41ms=1344 1244.5
mem lap2a 608 ; GA/2 = 508
mem lap2b 893 ; 893.5
mem d2 1013 ; 33ms=1081 1143.5
mem ap1 LEN1 ; chirp allpasses
mem ap2 LEN1
mem ap3 LEN1
mem ap4 LEN1
mem ap5 LEN1
mem ap6 LEN1
mem ap7 LEN1
mem ap8 LEN2
mem ap9 LEN2
mem ap10 LEN2
mem ap11 LEN2
mem ap12 LEN2
mem ap13 LEN2
mem ap14 LEN2
mem ap15 LEN3
mem ap16 LEN3
mem ap17 LEN3
mem ap18 LEN3
mem ap19 LEN3
mem ap20 LEN3
mem ap21 LEN3
mem ap22 LEN4
mem ap23 LEN4
mem ap24 LEN4
mem ap25 LEN4
mem ap26 LEN4
mem ap27 LEN4
mem ap28 LEN4
mem ap29 LEN5
mem ap30 LEN5
mem ap31 LEN5
mem ap32 LEN5
mem ap33 LEN5
mem ap34 LEN5
mem ap35 LEN5
mem ap36 LEN6
mem ap37 LEN6
mem ap38 LEN6
mem ap39 LEN6
mem ap40 LEN6
mem ap41 LEN6
mem ap42 LEN6
; Register equates
equ mono reg0
equ lp1 reg1
equ lp2 reg2
equ trem reg3
equ revout reg4
; Initialize LFOs
skp run, endinit
wlds sin0,15,40 ; to smear reverb
wlds sin1,12,32767 ; for tremolo
endinit:
; Control and get tremelo sinwave
rdax pot1, 1 ; rate
mulx pot1
sof 0.6, 0.1 ; 7:1 range
wrax sin1_rate, 0
cho RDAL, sin1
mulx pot2 ; depth
sof 0.5, 0.5 ; 0 to 1
wrax trem, 0 ; save LFO value
; Sum inputs to mono, apply tremolo
rdax adcl, 0.5
rdax adcr, 0.5
mulx trem ; apply tremolo
wrax mono, 0
; Do reverb loops
rda d1#, KRT ; get 1st delay output, scaled by RT
rdfx lp1, KRF ; shelving lowpass inside loop
wrlx lp1, KRS
rda lap1a#, KLAP ; reverb allpasses
wrap lap1a, -KLAP
rda lap1b#, KLAP
wrap lap1b, -KLAP
rdax mono, 1 ; add input
wra d2, 0 ; put in 2nd spring delay, clear
rda d2#, KRT ; get 2nd delay output, saled by RT
rdfx lp2, KRF ; shelving lowpass inside loop
wrlx lp2, KRS
rda lap2a#, KLAP ; reverb allpasses
wrap lap2a, -KLAP
rda lap2b#, KLAP
wrap lap2b, -KLAP
rdax mono, 1 ; add input
wra d1, 0 ; put in 1st spring delay, clear
; Get reverb output, do chirp filter
rdax lp1,1
rdax lp2,1
wrax revout, 1
rda ap1#, KAP
wrap ap1, -KAP
rda ap2#, KAP
wrap ap2, -KAP
rda ap3#, KAP
wrap ap3, -KAP
rda ap4#, KAP
wrap ap4, -KAP
rda ap5#, KAP
wrap ap5, -KAP
rda ap6#, KAP
wrap ap6, -KAP
rda ap7#, KAP
wrap ap7,-KAP
rda ap8#, KAP
wrap ap8, -KAP
rda ap9#, KAP
wrap ap9, -KAP
rda ap10#, KAP
wrap ap10, -KAP
rda ap11#, KAP
wrap ap11, -KAP
rda ap12#, KAP
wrap ap12, -KAP
rda ap13#, KAP
wrap ap13, -KAP
rda ap14#, KAP
wrap ap14, -KAP
rda ap15#, KAP
wrap ap15, -KAP
rda ap16#, KAP
wrap ap16, -KAP
rda ap17#, KAP
wrap ap17, -KAP
rda ap18#, KAP
wrap ap18, -KAP
rda ap19#, KAP
wrap ap19, -KAP
rda ap20#, KAP
wrap ap20, -KAP
rda ap21#, KAP
wrap ap21, -KAP
rda ap22#, KAP
wrap ap22, -KAP
rda ap23#, KAP
wrap ap23, -KAP
rda ap24#, KAP
wrap ap24, -KAP
rda ap25#, KAP
wrap ap25, -KAP
rda ap26#, KAP
wrap ap26, -KAP
rda ap27#, KAP
wrap ap27, -KAP
rda ap28#, KAP
wrap ap28, -KAP
rda ap29#, KAP
wrap ap29, -KAP
rda ap30#, KAP
wrap ap30, -KAP
rda ap31#, KAP
wrap ap31, -KAP
rda ap32#, KAP
wrap ap32, -KAP
rda ap33#, KAP
wrap ap33, -KAP
rda ap34#, KAP
wrap ap34, -KAP
rda ap35#, KAP
wrap ap35, -KAP
rda ap36#, KAP
wrap ap36, -KAP
rda ap37#, KAP
wrap ap37, -KAP
rda ap38#, KAP
wrap ap38, -KAP
rda ap39#, KAP
wrap ap39, -KAP
rda ap40#, KAP
wrap ap40, -KAP
rda ap41#, KAP
wrap ap41, -KAP
;rda ap42#, KAP ; as many as can fit
;wrap ap42, -KAP
; Chirp out in ACC - add dry, and output it
mulx pot0 ; reverb level
rdax mono, 1 ; add dry signal
wrax dacl, 1
wrax dacr, 0 ; output
; Smooth reverb with LFO modulating APs
cho rda,sin0,sin|reg|compc,lap1b+25
cho rda,sin0,sin,lap1b+26
wra lap1b+50,0
cho rda,sin0,cos|reg|compc,lap2b+25
cho rda,sin0,cos,lap2b+26
wra lap2b+50,0
; End
Don Stavely
Don,
that was very nice of you to share your code. Sounds very good. I saw that in the code you put a question mark after "eigentone". These are the various frequencies that cause resonance in a system. Mechanical systems can have an infinite amount of resonant frequencies. In the spring reverb each spring will have a natural frequency (which will have the largest magnitude) and then a bunch of others with diminishing magnitudes. Spreading these eigentones creates a more pleasant sound as opposed to having them all near each other thus creating a booming response when you play a note that is close to the group of resonant frequencies.
Its 2am I hope I'm making sense.
I.
that was very nice of you to share your code. Sounds very good. I saw that in the code you put a question mark after "eigentone". These are the various frequencies that cause resonance in a system. Mechanical systems can have an infinite amount of resonant frequencies. In the spring reverb each spring will have a natural frequency (which will have the largest magnitude) and then a bunch of others with diminishing magnitudes. Spreading these eigentones creates a more pleasant sound as opposed to having them all near each other thus creating a booming response when you play a note that is close to the group of resonant frequencies.
Its 2am I hope I'm making sense.
I.
How did you get this to assemble? I can't!Iconnu wrote:Don,
that was very nice of you to share your code. Sounds very good. I saw that in the code you put a question mark after "eigentone". These are the various frequencies that cause resonance in a system. Mechanical systems can have an infinite amount of resonant frequencies. In the spring reverb each spring will have a natural frequency (which will have the largest magnitude) and then a bunch of others with diminishing magnitudes. Spreading these eigentones creates a more pleasant sound as opposed to having them all near each other thus creating a booming response when you play a note that is close to the group of resonant frequencies.
Its 2am I hope I'm making sense.
I.
Surely there are too many instructions for the FV-1?
Phil.
I just tried it and it assembled fine. Not too many instructions (128 exactly), mem and equ statements are assembler directives not instructions.
Frank Thomson
Experimental Noize
Experimental Noize
Hi Frank,frank wrote:I just tried it and it assembled fine. Not too many instructions (128 exactly), mem and equ statements are assembler directives not instructions.
I get an error log that says:
<0000>[ Pass 1] [ 1015] Line: 250 "rdax  mono, 1    " - ERROR:Program Length Exceeds Limit -
<0001>[ Pass 1] [ 1031] Line: 250 "rdax  mono, 1    " - ERROR:FAILED On Pass - ONE
Spring Reverb (Don Stavely from Spinsemi Forum).spn [FAILED BUILD] Build Stopped..
2 Log Messages
and that was after commenting out a lot of the AP's.
Phil.
I just copied and pasted the code from Don's post above and get this error when I try to assemble it:
<0000>[ Pass 1] [ 1015] Line: 191 "wrap  ap15, -KAP " - ERROR:Program Length Exceeds Limit -
<0001>[ Pass 1] [ 1031] Line: 191 "wrap  ap15, -KAP " - ERROR:FAILED On Pass - ONE
Spring Reverb (Don Stavely Copied from Spinsemi Forum).spn [FAILED BUILD] Build Stopped..
2 Log Messages
Phil.
<0000>[ Pass 1] [ 1015] Line: 191 "wrap  ap15, -KAP " - ERROR:Program Length Exceeds Limit -
<0001>[ Pass 1] [ 1031] Line: 191 "wrap  ap15, -KAP " - ERROR:FAILED On Pass - ONE
Spring Reverb (Don Stavely Copied from Spinsemi Forum).spn [FAILED BUILD] Build Stopped..
2 Log Messages
Phil.
I just installed SpinAsm on a different computer and tried it and it assembled fine. What is your computer setup?
Frank Thomson
Experimental Noize
Experimental Noize
It's a Windows 10 OS with 16GB ram. All other SpinAsm programs I've tried assemble just fine.frank wrote:I just installed SpinAsm on a different computer and tried it and it assembled fine. What is your computer setup?
Ice9 tells me he's getting the same error as me after copying Don's code from the post above. Are you copying and pasting this into SpinAsm as we are or are you using an older file that you previously saved onto your computer?
I'm just wondering in case Don changed the code in the post.
Thanks for your help anyway,
Phil.
-
- Posts: 338
- Joined: Mon Nov 12, 2012 1:12 pm
- Contact:
Make sure you don't somehow have two copies of the code in the Spin IDE. I'm not 100% sure but I think I've seen that happen with copy-paste.
There was some other issue recently that was traced to locale settings (need to use comma for decimal point - or leading zero on a numeric value dropped, or something like that), so weird things sometimes happen that nobody can reproduce because our environment is not the same.
There was some other issue recently that was traced to locale settings (need to use comma for decimal point - or leading zero on a numeric value dropped, or something like that), so weird things sometimes happen that nobody can reproduce because our environment is not the same.
Ice9 has sent me a version from which he has removed the tremolo sections and that does assemble. I've compared the two side-by-side and I can't see any evidence that I've got two copies of Don's original code
I've come across the locale settings issue with some of my own apps but I don't think it's that. In the UK we use the period (.) as the decimal separator; in the rest of Europe they use the comma. Time for Brexit
Thanks again Frank,
Phil.
I've come across the locale settings issue with some of my own apps but I don't think it's that. In the UK we use the period (.) as the decimal separator; in the rest of Europe they use the comma. Time for Brexit
Thanks again Frank,
Phil.
I am doing a copy/paste so it was the same as what you are doing.
The only big difference I can see is the locale setting, I am also on Windows 10 on both machines I've tried. Try changing to locale to US, both use the period decimal separator but there may be something in Windows that is handling things differently.
Actually try this leaving the locale to UK, take a new copy of the code, delete from line 190 down since the error says it starts at line 191. Assemble the code then click the view machine code icon (the m: with the underline) and see what it thinks the other code lines are. Something is being interpreted as a code line that isn't, could be comment lines with a particular character, directive lines, etc.
The only big difference I can see is the locale setting, I am also on Windows 10 on both machines I've tried. Try changing to locale to US, both use the period decimal separator but there may be something in Windows that is handling things differently.
Actually try this leaving the locale to UK, take a new copy of the code, delete from line 190 down since the error says it starts at line 191. Assemble the code then click the view machine code icon (the m: with the underline) and see what it thinks the other code lines are. Something is being interpreted as a code line that isn't, could be comment lines with a particular character, directive lines, etc.
Frank Thomson
Experimental Noize
Experimental Noize