Spin Semiconductor Forum Index Spin Semiconductor
Support forum
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

A Spin on the Dattorro Plate Reverb

 
Post new topic   Reply to topic    Spin Semiconductor Forum Index -> Algorithm development
View previous topic :: View next topic  
Author Message
mdroberts1243



Joined: 22 Jul 2008
Posts: 18
Location: Ottawa, Canada

PostPosted: Mon Sep 13, 2010 4:07 am    Post subject: A Spin on the Dattorro Plate Reverb Reply with quote

I wanted to code a reverb from scratch, a fairly complex reverb that would pretty much consume all the FV-1 resources, and hopefully learn about tuning the reverb in the process. The Dattorro paper seemed a great starting point as it was a well-documented plate reverb that is touted as sounding fairly decent. There's a great thread on gearslutz that got me keen to do this.

This version follows (or attempts to) the block diagram in the paper exactly. I have another version that tries to go further (as the paper suggests) and uses both LFOs with SIN, COS, and COMPA to get eight different modulations, one for each delay in the 'tank'.

I have corrected a serious error in the damping low-pass filter, but I still suspect errors because of a strong sibilance in the reverb output... appreciate some additional eyes on this! UPDATE... found another error... the 'simple' low-pass for input bandwidth limiting didn't work the way I thought... much more pleasing now.

Code:

; Plate Reverb -- derived from Jon Dattorro paper "Effect Design"
; - Supposedly good sounding with minimal required resources
; - available at: https://ccrma.stanford.edu/~dattorro/EffectDesignPart1.pdf
;

;pot0=reverb level
;pot1=reverb time
;pot2 = hf loss in tank (turn up for MORE damping)

; fixed parameters from the paper
equ   decay_diffusion_1   0.70   ;default parameters from Dattorro paper
equ   input_diffusion_1   0.75
equ   input_diffusion_2   0.625

; k1 for freqs:
equ   k1_1kHz   0.82552
equ   k1_2kHz   0.68148
equ   k1_4kHz   0.46441
equ   bandwidth   1-k1_2kHz   ; coefficient for input low-pass

equ   excursion   16   ; peak excursion for tap modulation

; no idea what a suitable pre-delay would be...  could go as high as 7957 samples
mem   predelay      3802   ; 3802=116ms predelay at 32kHz

; allpass names are formed from the Dattorro paper node numbers in Figure 1
; all the memory sizes have been scaled up by 1.1010x to account for difference in sampling
; original paper specified sample rate of 29761 Hz, we have 32768

mem   ap13_14      156   ; coeff is input_diffusion_1
mem   ap19_20      117   ; coeff is input_diffusion_1
mem   ap15_16      417   ; coeff is input_diffusion_2
mem   ap21_22      305   ; coeff is input_diffusion_2

mem   ap23_24       740+excursion   ; coeff is decay_diffusion_1
mem   ap46_48      1000+excursion   ; coeff is decay_diffusion_1

mem   del24_30   4903
mem   del48_54   4643
mem   ap31_33      1982   ; coeff is decay_diffusion_2 (derived from pot1)
mem   ap55_59      2924   ; coeff is decay_diffusion_2
mem   del33_39   4096
mem   del59_63   3483

equ   krl         reg0   ; coeff for reverb level (from pot0)
equ   decay         reg1   ; coeff for reverb time (from pot1)
equ   decay_diffusion_2      reg2   ; related to coeff for reverb time (from delay)
equ   damping         reg3   ; coeff for high-frequency decay within the tank (from pot2)
equ   one_minus_dmpg      reg4
equ   lp_inp         reg5   ; 'bandwidth' low-pass at input
equ   lp30_31         reg6   ; tank low-pass set by 'damping'
equ   lp54_55         reg7   ; tank low-pass set by 'damping'
equ   mono         reg8   ; mono input signal
equ   diffuse_in      reg9   ; output of input diffusers
equ   temp         reg10   ; temp for expanded allpass calculations
equ   temp2         reg11   ; another temp value for allpass

;
; code starts here!

; now generate a pair of LFOs to modulate the APs in the loop:

skp   run,2
wlds   SIN0,27,excursion   ; paper calls for 1-2Hz, 25=1Hz, 50=2Hz
wlds   SIN1,41,excursion

;now derive control coefficients from pots:

rdax   pot0,1      ; control reverb attenuation level
mulx   pot0      ; square it
wrax   krl,0      ; reverb level, write for later use

rdax   pot1,1
wrax   decay,1         ; reverb time

; decay_diffusion_2 = decay + 0.15 but must range between 0.25 to 0.5
sof   1.0,-0.35      ; check to see if we will go higher than ceiling (0.35 + 0.15)
skp   neg,1         ;
clr            ; set ceiling to 0.35 if we are still positive (after restoration below)
sof   1.0,0.35         ; restore ACC (could combine with below)
sof   1.0,-0.10      ; check to see if we will be below floor (0.10 + 0.15)
skp   gez,1
clr            ; clr ACC will set floor to 0.25 after restoration below
sof   1.0,0.25         ; restore ACC (+ 0.10) and add 0.15
wrax   decay_diffusion_2,0

rdax   pot2,1         ; control high freq loss in the tank (low pass filter)
wrax   damping,1      ; low-pass coefficient
sof   -1,0.999         ; make '1-damping' control from 1- pot2
wrax   one_minus_dmpg,0   ; other low pass damping coefficient

; sum inputs to mono, with 0.5x input gain adjustment
rdax   adcl,0.75   ;TESTING... boosted from 0.5
rdax   adcr,0.75
wrax   mono,1      ; leave signal in ACC

; do the pre-delay
wra   predelay,0

; input low-pass
rda   predelay#,bandwidth
rdax   lp_inp,1-bandwidth
wrax   lp_inp,1

; now do input all passes:

rda   ap13_14#,-input_diffusion_1
wrap   ap13_14,input_diffusion_1
rda   ap19_20#,-input_diffusion_1
wrap   ap19_20,input_diffusion_1
rda   ap15_16#,-input_diffusion_2
wrap   ap15_16,input_diffusion_2
rda   ap21_22#,-input_diffusion_2
wrap   ap21_22,input_diffusion_2
wrax   diffuse_in,0

;
;allpassed input in place, now process the tank (two sides), with filtering

; left side of Figure 1 tank
rda   del59_63#,1   ; input from right-side delay out

mulx   decay
rdax   diffuse_in,1

;modulated tap on this AP
wrax   temp,0
cho     rda,sin0,sin|reg|compc,ap23_24#-excursion-1
cho    rda,sin0,sin,ap23_24#-excursion
wrax   temp2,decay_diffusion_1   ; store, apply coeff (note flipped sign for this AP)
rdax   temp,1         ; add input
wra   ap23_24,-decay_diffusion_1   ; write to head of delay
rdax   temp2,1            ; add modulated tail

wra   del24_30,0   ;delay
rda   del24_30#,1

; simple low-pass with variable control
mulx   one_minus_dmpg
wrax   temp,0
rdax   lp30_31,1   
mulx   damping      ;     damping derived from pot
rdax   temp,1
wrax   lp30_31,1

mulx   decay      ; apply decay
wrax   temp,0      ; save for applying a bit later...

; another allpass, but WRAP replaced to use variable coefficient
rda   ap31_33#,-1
mulx   decay_diffusion_2   ; mult with 'negative' coefficient from pot
rdax   temp,1      ; add input from temp register
wra   ap31_33,1   ; store to delay
mulx   decay_diffusion_2   ; apply coeff
rda   ap31_33#,1

wra   del33_39,0   ; delay
rda   del33_39#,1

; right side of Figure 1 tank, delay output already in ACC
mulx   decay
rdax   diffuse_in,1

; modulated tap on this AP
wrax   temp,0
cho    rda,sin0,cos|reg|compc,ap46_48#-excursion-1
cho    rda,sin0,cos,ap46_48#-excursion
wrax   temp2,decay_diffusion_1   ; store, apply coeff (note flipped sign for this AP)
rdax   temp,1         ; add input
wra   ap46_48,-decay_diffusion_1
rdax   temp2,1            ; add modulated tail

wra   del48_54,0   ;delay
rda   del48_54#,1

; simple low-pass with variable control
mulx   one_minus_dmpg
wrax   temp,0
rdax   lp54_55,1   
mulx   damping      ;     damping derived from pot
rdax   temp,1
wrax   lp54_55,1

mulx   decay      ; apply decay

; another allpass, but WRAP replaced to use variable coefficient
wrax   temp,0      ; save for applying a bit later...
rda   ap55_59#,-1
mulx   decay_diffusion_2   ; mult with 'negative' coefficient from pot
rdax   temp,1      ; add input from temp register
wra   ap55_59,1   ; store to delay
mulx   decay_diffusion_2   ; apply coeff
rda   ap55_59#,1

wra   del59_63,0   ; write delay leaving ACC clear

;
;now gather outputs from loop delays (values scaled for different sampling freq):

rda   del48_54+292,0.6
rda   del48_54+3274,0.6
rda   ap55_59+2107,-0.6
rda   del59_63+2198,0.6
rda   del24_30+2192,-0.6
rda   ap31_33+205,-0.6
rda   del33_39+1174,-0.6
mulx   krl            ;attenuate reverb by Pot0 setting
wrax   dacl,0

rda   del24_30+389,0.6
rda   del24_30+3993,0.6
rda   ap31_33+1352,-0.6
rda   del33_39+2943,0.6
rda   del48_54+2325,-0.6
rda   ap55_59+369,-0.6
rda   del59_63+133,-0.6
mulx   krl            ;attenuate reverb by Pot0 setting
wrax   dacr,0

;
;  DONE

_________________
-mark
My blog: http://tubenexus.com


Last edited by mdroberts1243 on Mon Sep 13, 2010 5:15 pm; edited 2 times in total
Back to top
View user's profile Send private message Visit poster's website
mdroberts1243



Joined: 22 Jul 2008
Posts: 18
Location: Ottawa, Canada

PostPosted: Mon Sep 13, 2010 12:07 pm    Post subject: Reply with quote

I found a serious error in how I'm implementing the low-pass for 'damping' in the tank... just need to figure out how to do it and I'll repost the source.
_________________
-mark
My blog: http://tubenexus.com
Back to top
View user's profile Send private message Visit poster's website
mdroberts1243



Joined: 22 Jul 2008
Posts: 18
Location: Ottawa, Canada

PostPosted: Mon Sep 13, 2010 1:59 pm    Post subject: Reply with quote

mdroberts1243 wrote:
I found a serious error in how I'm implementing the low-pass for 'damping' in the tank... just need to figure out how to do it and I'll repost the source.


Fixed the two damping low-pass filters but still don't like the sibilance I'm hearing.
_________________
-mark
My blog: http://tubenexus.com
Back to top
View user's profile Send private message Visit poster's website
mdroberts1243



Joined: 22 Jul 2008
Posts: 18
Location: Ottawa, Canada

PostPosted: Mon Sep 13, 2010 5:17 pm    Post subject: Reply with quote

mdroberts1243 wrote:
mdroberts1243 wrote:
I found a serious error in how I'm implementing the low-pass for 'damping' in the tank... just need to figure out how to do it and I'll repost the source.


Fixed the two damping low-pass filters but still don't like the sibilance I'm hearing.


I think the latest version, with the fix to the input bandwidth low-pass filter nails it (finally).
_________________
-mark
My blog: http://tubenexus.com
Back to top
View user's profile Send private message Visit poster's website
mdroberts1243



Joined: 22 Jul 2008
Posts: 18
Location: Ottawa, Canada

PostPosted: Tue Sep 14, 2010 7:05 am    Post subject: More modulated version of Dattorro Plate Reverb Reply with quote

Here's a version of the Dattorro Plate Reverb that modulates all four of the allpasses in the 'tank' portion of the algorithm using slightly different LFO modes in each case.

The thing I don't like is that even if you turn the decay all the way down and the damping all the way up you get a really strong 'tail' that is fairly long... apparently from the way the outputs are derived from the tank delays and especially the allpasses, which take time to reduce even if you are applying no further input (I'm guessing).

Some of the VST plugins I've auditioned don't seem to have this 'artifact', but I can't see how they get rid of it... perhaps I've still got a problem somewhere, but I can't see where I've departed from the paper.

Code:
; Plate Reverb -- derived from Jon Dattorro paper "Effect Design"
; - Supposedly good sounding with minimal required resources
; - available at: https://ccrma.stanford.edu/~dattorro/EffectDesignPart1.pdf
; - coded by mdroberts1243 'at' gmail.com

;pot0=reverb level
;pot1=reverb time (decay... all the way up is infinite sustain in the tank)
;pot2 = hf loss in the tank (damping... turn up for MORE damping)

; fixed parameters from the paper
equ   decay_diffusion_1   0.70   ;default parameters from Dattorro paper
equ   input_diffusion_1   0.75
equ   input_diffusion_2   0.625

; k1 for freqs:
equ   k1_1kHz   0.82552
equ   k1_2kHz   0.68148
equ   k1_4kHz   0.46441
equ   k1_12kHz 0.232205
equ   bandwidth   1-k1_2kHz   ; coefficient for input low-pass

equ   excursion   8   ; peak excursion for tap modulation

; no idea what a suitable pre-delay would be...  could go as high as 7000+ samples
; 655=20ms, 3802=116ms, etc.
mem   predelay      655   ; 3802=116ms predelay at 32kHz

; allpass names are formed from the Dattorro paper node numbers in Figure 1
; all the memory sizes have been scaled up by 1.1010x to account for difference in sampling
; original paper specified sample rate of 29761 Hz, we have 32768

mem   ap13_14      156   ; coeff is input_diffusion_1
mem   ap19_20      117   ; coeff is input_diffusion_1
mem   ap15_16      417   ; coeff is input_diffusion_2
mem   ap21_22      305   ; coeff is input_diffusion_2

mem   ap23_24       740+excursion   ; coeff is decay_diffusion_1
mem   ap46_48      1000+excursion   ; coeff is decay_diffusion_1

mem   del24_30   4903
mem   del48_54   4643
mem   ap31_33      1982+excursion   ; coeff is decay_diffusion_2 (derived from pot1)
mem   ap55_59      2924+excursion   ; coeff is decay_diffusion_2
mem   del33_39   4096
mem   del59_63   3483

equ   krl         reg0   ; coeff for reverb level (from pot0)
equ   decay         reg1   ; coeff for reverb time (from pot1)
equ   decay_diffusion_2      reg2   ; related to coeff for reverb time (from delay)
equ   damping         reg3   ; coeff for high-frequency decay within the tank (from pot2)
equ   one_minus_dmpg      reg4
equ   lp_inp         reg5   ; 'bandwidth' low-pass at input
equ   lp30_31         reg6   ; tank low-pass set by 'damping'
equ   lp54_55         reg7   ; tank low-pass set by 'damping'
equ   mono         reg8   ; mono input signal
equ   diffuse_in      reg9   ; output of input diffusers
equ   temp         reg10   ; temp for expanded allpass calculations
equ   temp2         reg11   ; another temp value for allpass

;
; code starts here!

; now generate a pair of LFOs to modulate the APs in the loop:

skp   run,2
wlds   SIN0,27,excursion   ; paper calls for 1-2Hz, 25=1Hz, 50=2Hz
wlds   SIN1,23,excursion

;now derive control coefficients from pots:

rdax   pot0,1      ; control reverb attenuation level
mulx   pot0      ; square it
wrax   krl,0      ; reverb level, write for later use

rdax   pot1,1
;mulx   pot1      ; could square it if you like.
wrax   decay,1      ; reverb time

; decay_diffusion_2 = decay + 0.15 but must range between 0.25 to 0.5
sof   1.0,-0.35      ; check to see if we will go higher than ceiling (0.35 + 0.15)
skp   neg,1         ;
clr            ; set ceiling to 0.35 if we are still positive (after restoration below)
sof   1.0,0.35         ; restore ACC (could combine with below)
sof   1.0,-0.10      ; check to see if we will be below floor (0.10 + 0.15)
skp   gez,1
clr            ; clr ACC will set floor to 0.25 after restoration below
sof   1.0,0.25         ; restore ACC (+ 0.10) and add 0.15
wrax   decay_diffusion_2,0

rdax   pot2,1         ; control high freq loss in the tank (low pass filter)
wrax   damping,-1      ; low-pass coefficient
sof   1,0.9990234375      ; make '1-damping' control from 1- pot2
wrax   one_minus_dmpg,0   ; other low pass damping coefficient

; sum inputs to mono, with 0.5x input gain adjustment
rdax   adcl,0.5   ;
rdax   adcr,0.5
wrax   mono,1      ; leave signal in ACC

; do the pre-delay
wra   predelay,0

; input low-pass
rda   predelay#,bandwidth
rdax   lp_inp,1-bandwidth
wrax   lp_inp,1

; now do input all passes:

rda   ap13_14#,-input_diffusion_1
wrap   ap13_14,input_diffusion_1
rda   ap19_20#,-input_diffusion_1
wrap   ap19_20,input_diffusion_1
rda   ap15_16#,-input_diffusion_2
wrap   ap15_16,input_diffusion_2
rda   ap21_22#,-input_diffusion_2
wrap   ap21_22,input_diffusion_2
wrax   diffuse_in,0

;
;allpassed input in place, now process the tank (two sides), with filtering
; - all the delays & ap-delays are modulated by LFOs... four different variations

; left side of Figure 1 tank
rda   del59_63#,1

mulx   decay
rdax   diffuse_in,1
wrax   temp,0

cho     rda,sin0,sin|reg|compc,ap23_24#-excursion-1
cho    rda,sin0,sin,ap23_24#-excursion
wrax   temp2,decay_diffusion_1   ; store, apply coeff (note flipped sign for this AP)
rdax   temp,1         ; add input
wra   ap23_24,-decay_diffusion_1   ; write to head of delay
rdax   temp2,1            ; add modulated tail

wra   del24_30,0   ;delay
rda   del24_30#,1

; simple low-pass with variable control
mulx   one_minus_dmpg
wrax   temp,0
rdax   lp30_31,1   
mulx   damping      ;     damping derived from pot
rdax   temp,1
wrax   lp30_31,1

mulx   decay      ; apply decay
wrax   temp,0      ; save for applying a bit later...

; another allpass, but WRAP replaced to use variable coefficient
cho    rda,sin1,cos|reg|compc,ap31_33#-excursion-1
cho    rda,sin1,cos,ap31_33#-excursion
wrax   temp2,-1      ; store temporarily, and negate
mulx   decay_diffusion_2   ; mult with 'negative' coefficient from pot
rdax   temp,1         ; add input from temp register
wra   ap31_33,1      ; store to delay
mulx   decay_diffusion_2   ; apply coeff
rdax   temp2,1         ; add back in the modulated tail stored in temp

wra   del33_39,0   ; delay
rda   del33_39#,1

; right side of Figure 1 tank, delay output already in ACC
mulx   decay
rdax   diffuse_in,1
wrax   temp,0

cho    rda,sin0,cos|reg|compc,ap46_48#-excursion-1
cho    rda,sin0,cos,ap46_48#-excursion
wrax   temp2,decay_diffusion_1   ; store, apply coeff (note flipped sign for this AP)
rdax   temp,1         ; add input
wra   ap46_48,-decay_diffusion_1
rdax   temp2,1            ; add modulated tail

wra   del48_54,0   ;delay
rda   del48_54#,1

; simple low-pass with variable control
mulx   one_minus_dmpg
wrax   temp,0
rdax   lp54_55,1   
mulx   damping      ;     damping derived from pot
rdax   temp,1
wrax   lp54_55,1

mulx   decay      ; apply decay
wrax   temp,0      ; save for applying a bit later...

; another allpass, but WRAP replaced to use variable coefficient
cho     rda,sin1,sin|reg|compc,ap55_59#-excursion-1
cho    rda,sin1,sin,ap55_59#-excursion
wrax   temp2,-1      ; store temporarily, and negate
mulx   decay_diffusion_2   ; mult with 'negative' coefficient from pot
rdax   temp,1         ; add input from temp register
wra   ap55_59,1      ; store to delay
mulx   decay_diffusion_2   ; apply coeff
rdax   temp2,1         ; add back in the modulated tail stored in temp

wra   del59_63,0   ; write delay leaving ACC clear

;
;now gather outputs from loop delays (values scaled for different sampling freq):

rda   del48_54+292,0.6
rda   del48_54+3274,0.6
rda   ap55_59+2107,-0.6
rda   del59_63+2198,0.6
rda   del24_30+2192,-0.6
rda   ap31_33+205,-0.6
rda   del33_39+1174,-0.6
mulx   krl            ;attenuate reverb by Pot0 setting
wrax   dacl,0

rda   del24_30+389,0.6
rda   del24_30+3993,0.6
rda   ap31_33+1352,-0.6
rda   del33_39+2943,0.6
rda   del48_54+2325,-0.6
rda   ap55_59+369,-0.6
rda   del59_63+133,-0.6
mulx   krl            ;attenuate reverb by Pot0 setting
wrax   dacr,0

;
;  DONE

_________________
-mark
My blog: http://tubenexus.com
Back to top
View user's profile Send private message Visit poster's website
MacroMachines



Joined: 12 Dec 2014
Posts: 70
Location: Detroit,MI

PostPosted: Fri Jul 08, 2016 1:36 am    Post subject: Reply with quote

Decent reverb! I like it more with the excursion up to 256+
_________________
http://MacroMachines.net
Digital Control for your Analog Soul.
Back to top
View user's profile Send private message Visit poster's website AIM Address
Display posts from previous:   
Post new topic   Reply to topic    Spin Semiconductor Forum Index -> Algorithm development All times are GMT - 8 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group