Phaser/allpass filter code
Moderator: frank
-
- Posts: 131
- Joined: Sun Nov 15, 2009 3:37 pm
- Location: New Orleans, LA US
Phaser/allpass filter code
I've read this but I must admit I'm not at the point where I can translate these diagrams into the proper opcodes.
How would I write a single allpass stage in code?
How would I write a single allpass stage in code?
The FV-1 has special instructions for this to make it quick to do. Make the following assumptions:
"IN" is in the accumulator already, may have come from a filter, delay, ADC, etc.
"DELAY" is the name of the delay block in the all-pass.
"K" = 0.37, why? Because I like that number for examples.
Note the LR register is automatically updated every time a value is read from memory so it holds DELAY# when we execute the wrap instruction.
So there you have it, a 2-tick APD.
"IN" is in the accumulator already, may have come from a filter, delay, ADC, etc.
"DELAY" is the name of the delay block in the all-pass.
"K" = 0.37, why? Because I like that number for examples.
Code: Select all
rda DELAY#, 0.37 ; Read end of DELAY, multiply by 0.37 and add to acc
wrap DELAY, 0.37 ; Write acc to delay, multiply acc by -0.37 and add the 'last read' value from delay memory saved in the LR register. OUT is in the acc.
So there you have it, a 2-tick APD.
Frank Thomson
Experimental Noize
Experimental Noize
-
- Posts: 131
- Joined: Sun Nov 15, 2009 3:37 pm
- Location: New Orleans, LA US
Can I equate K to a register, or is it like my earlier question where it needs to be a specific coefficient? If I can't, how do I create a varying K value for a phaser?
In this case K is fixed, you need to use mulx to multiply by a register. An all pass can still be done but it will take 6 or 7 instructions to do it, I haven't written code to do this but it should be:
read end of delay (rda),
multiply by reg (mulx),
add input (rdax or rda depending if from register or memory),
write to head of delay (wra),
multiply by reg (mulx),
multiply by -1 (sof),
read end of delay(rda)
read end of delay (rda),
multiply by reg (mulx),
add input (rdax or rda depending if from register or memory),
write to head of delay (wra),
multiply by reg (mulx),
multiply by -1 (sof),
read end of delay(rda)
Frank Thomson
Experimental Noize
Experimental Noize
-
- Posts: 131
- Joined: Sun Nov 15, 2009 3:37 pm
- Location: New Orleans, LA US
I hacked up what I thought a 4-stage phaser might look like using your suggestions. It uses the envelope to vary the phasing.
So far it doesn't work, but it involved a lot of guessing so I didn't really expect it to. I can't remember now why I made the delays 205 samples, and I'm guessing this is one thing that isn't right, but I don't really know how to figure them.
Any suggestions on where I'm going wrong?
Code: Select all
mem delay 205
mem delay2 205
mem delay3 205
mem delay4 205
mem delay5 205
mem delay6 205
mem delay7 205
mem delay8 205
equ ap1out reg1
equ ap2out reg2
equ ap3out reg3
equ ap4out reg4
equ ap5out reg5
equ env reg6
equ envfil reg7
rdax adcr,1
absa
RDFX envfil,0.001 ;use LPF opcode for filtering
WRLX envfil,-1 ;infinite shelf LPF (could have used WRAX avgfil,1)
sof 1.5,0 ;get bigger envelope
wrax env,0
rda DELAY#, 1 ; Read end of DELAY,
mulx env
rdax adcr, 1
wra delay, 1 ;write to head of delay (wra),
mulx env ;multiply by reg (mulx),
sof -1, 0 ;multiply by -1 (sof),
rda DELAY#, 1 ;read end of delay(rda)
wrax ap1out, 0
rda DELAY2#, 1 ; Read end of DELAY,
mulx env
rdax ap1out, 1
wra delay2, 1 ;write to head of delay (wra),
mulx env ;multiply by reg (mulx),
sof -1, 0 ;multiply by -1 (sof),
rda DELAY2#, 1 ;read end of delay(rda)
wrax ap2out, 0
rda DELAY3#, 1 ; Read end of DELAY,
mulx env
rdax ap2out, 1
wra delay3, 1 ;write to head of delay (wra),
mulx env ;multiply by reg (mulx),
sof -1, 0 ;multiply by -1 (sof),
rda DELAY3#, 1 ;read end of delay(rda)
wrax ap3out, 0
rda DELAY4#, 1 ; Read end of DELAY,
mulx env
rdax ap3out, 1
wra delay4, 1 ;write to head of delay (wra),
mulx env ;multiply by reg (mulx),
sof -1, 0 ;multiply by -1 (sof),
rda DELAY4#, 1 ;read end of delay(rda)
wrax ap4out, 1
mulx pot1
rdax adcr, 1
wrax dacr, 0
Any suggestions on where I'm going wrong?
A quick look seems OK (will take a closer look Monday when back in the office), try making it just one AP and seeing if it works than add in the LP filter, then the additional stages, etc. We need to isolate where it fails.
Frank Thomson
Experimental Noize
Experimental Noize
-
- Posts: 18
- Joined: Tue Jul 22, 2008 3:54 pm
- Location: Ottawa, Canada
- Contact:
I just had to do a similar thing, where the allpass coefficient was in a register, derived from a pot. Input is in the ACC, so I didn't think you needed to add the input, it is done in the first rda. I came up with this (hopefully it is right):frank wrote:In this case K is fixed, you need to use mulx to multiply by a register. An all pass can still be done but it will take 6 or 7 instructions to do it, I haven't written code to do this but it should be:
read end of delay (rda),
multiply by reg (mulx),
add input (rdax or rda depending if from register or memory),
write to head of delay (wra),
multiply by reg (mulx),
multiply by -1 (sof),
read end of delay(rda)
rda delay#, 1 ; allpass with WRAP replaced to use variable coefficient
mulx coefficient
wra delay, -1 ; store to delay and then negate ACC
mulx coefficient ; apply 'negative' coefficient
rda delay#, 1 ; add in the end entry in the delay
-mark
My blog: http://tubenexus.com
My blog: http://tubenexus.com
Not quite correct, input to all-pass is: input + (delayout * K)mdroberts1243 wrote:
I just had to do a similar thing, where the allpass coefficient was in a register, derived from a pot. Input is in the ACC, so I didn't think you needed to add the input, it is done in the first rda. I came up with this (hopefully it is right):
rda delay#, 1 ; allpass with WRAP replaced to use variable coefficient
mulx coefficient
wra delay, -1 ; store to delay and then negate ACC
mulx coefficient ; apply 'negative' coefficient
rda delay#, 1 ; add in the end entry in the delay
If input is in ACC then you are doing: (input + delayout) * K
Not the same result
Frank Thomson
Experimental Noize
Experimental Noize
-
- Posts: 18
- Joined: Tue Jul 22, 2008 3:54 pm
- Location: Ottawa, Canada
- Contact:
Thanks Frank!frank wrote:Not quite correct, input to all-pass is: input + (delayout * K)mdroberts1243 wrote:
I just had to do a similar thing, where the allpass coefficient was in a register, derived from a pot. Input is in the ACC, so I didn't think you needed to add the input, it is done in the first rda. I came up with this (hopefully it is right):
rda delay#, 1 ; allpass with WRAP replaced to use variable coefficient
mulx coefficient
wra delay, -1 ; store to delay and then negate ACC
mulx coefficient ; apply 'negative' coefficient
rda delay#, 1 ; add in the end entry in the delay
If input is in ACC then you are doing: (input + delayout) * K
Not the same result
Had to go over it a few times to understand... ended up storing the input to a temp register, clearing the ACC and adding a line:
wrax temp, 0
rda delay#, 1 ; allpass with WRAP replaced to use variable coefficient
mulx coefficient
rdax temp,1 ; add input *NEW*
wra delay, -1 ; store to delay and then negate ACC
mulx coefficient ; apply 'negative' coefficient
rda delay#, 1 ; add in the end entry in the delay
-mark
My blog: http://tubenexus.com
My blog: http://tubenexus.com
-
- Posts: 18
- Joined: Tue Jul 22, 2008 3:54 pm
- Location: Ottawa, Canada
- Contact:
I think it works, but I went and tried to add chorusing on the delay taps, screwing everything up, which requires me to re-think the flow again.frank wrote:That looks good, think that will work.
I don't understand the 'post' processing chorus stuff that is done in a lot of the reverb example programmes... is that explained anywhere? I'm trying to implement the modulated output taps directly in the allpass as shown in a lot of reverb flow-diagrams instead.
Thanks,
-mark
My blog: http://tubenexus.com
My blog: http://tubenexus.com
Can you post or link directly to an example so I can see the code you are talking about? Lots of reasons to do things in a reverb program.
Frank Thomson
Experimental Noize
Experimental Noize
-
- Posts: 18
- Joined: Tue Jul 22, 2008 3:54 pm
- Location: Ottawa, Canada
- Contact:
Hi Frank,frank wrote:Can you post or link directly to an example so I can see the code you are talking about? Lots of reasons to do things in a reverb program.
Thanks. I've been coding up the Dattorro plate reverb as an exercise (in frustration)
I will start a separate thread... the result might be interesting for others.
-mark
My blog: http://tubenexus.com
My blog: http://tubenexus.com
-
- Posts: 18
- Joined: Tue Jul 22, 2008 3:54 pm
- Location: Ottawa, Canada
- Contact:
I think the plate reverb examples on spinsemi use a block of chorus statements at the end of the code to affect each delay. I don't understand that... It seems to just juggle some samples in the interior of the delay. If this is somehow equivalent to modulating the read from the end of the delay/AP then it would be a lot more efficient to implement the Dattorro diagram in the FV-1!frank wrote:Can you post or link directly to an example so I can see the code you are talking about? Lots of reasons to do things in a reverb program.
-mark
My blog: http://tubenexus.com
My blog: http://tubenexus.com
A quick look at the code makes me believe the chorusing of values in the all-pass' is to stop any repetitive noise from happening. With these kind of structures you can get a repetitive sound at a particular frequency, by slightly shifting the sound with a chorus type effect you can stop that from happening.
Frank Thomson
Experimental Noize
Experimental Noize