Implementing step phase/flange

Algorithm development and general DSP issues

Moderator: frank

Post Reply
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Implementing step phase/flange

Post by B.C. »

Hi all,

Given the FV-1's efficiency at generating all pass filters and pitch shifting, I was thinking it should be possible to implement the step phase effect on it. I was wondering if anyone had any ideas on how to do this, as I'm lost to how to do it at the moment.

Here is a good example of the step phase/flange as done by Muse:
http://www.youtube.com/watch?v=6GnDJ8xPMEQ

Thanks!
Brandon
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

I've never programmed one before so need a good definition of the algorithm. I did a bit of checking online but couldn't find a good definition, many samples and examples but nothing with a real explanation of how the effect is created. It seems to be more than just quantization of the LFO but not sure.
Frank Thomson
Experimental Noize
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

In analog effects, we'd approach it with a noise generator into the input of a sample and hold circuit, a square wave LFO into the gate switch of the s+h, and we'd take the resultant random voltage steps and use that to control the thing we're modulating.

Creating noise in the FV1 might be kind of cycle-intensive, so since true randomness is not that critical, take a ramp LFO and sample it every so often - there's your random step LFO. It will be fairly simple to plug that into the ROM flanger program, I would think.
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Thanks for the help guys!

I did a little research and some call it a barberpole flanging like effect. I'm not so sure about that, but it seems a pseudo-random LFO is the way to go. Please see this nice article:
http://www.geofex.com/article_folders/l ... random.htm

Feel free to lay all the theory on me, as I am an electrical engineering major(senior). I'm just not as use to the Spin Semi Architecture as other microprocessors I've used.

Thanks again! :D
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

OK then, if you're an engineer then I would do the following:

Get the ROM flange/reverb code from http://www.spinsemi.com/programs.php and cut out the reverb portion. Notice where the LFO is used in the code then...

Make a random number generator from either Taylor's suggestion of a sampled LFO and sample it at some rate not related to the LFO frequency or see the posts here on making an LFSR random number generator http://www.spinsemi.com/forum/viewtopic ... c&start=15. Use the results to replace the LFO in the flanger code.

Give it a try and if you have any problems post the code, people like Taylor and myself will gladly assist as best we can.
Frank Thomson
Experimental Noize
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Fantastic, I appreciate all of your guy's help. I'll implement it after finals here this week and I'll send you the results. Thanks again!

Brandon
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

Barber pole flanging is actually something different. That's when you use a frequency shifter (not pitch shifter) and shift frequencies by a very small amount - it creates something a flanger or phaser, but it appears to constantly be moving downward or upward, rather than up and then down, cyclically. When flanger pedals like the digital Boss one have a "rise" or "fall" mode, this is what it's doing.

It's called barber pole flanging after the red, blue, and white swirly poles outside old-timey barber shops. They appear to constantly be moving downward because of the spinning stripes.

http://bestanimations.com/Careers/Barber-02-june.gif
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Thanks for the clarification. I know a good amount about many effects, but phase and flange are relatively new to me.

I'll be attacking the code here after Monday, its finals week :shock:
seancostello
Posts: 74
Joined: Mon Sep 11, 2006 10:04 pm

Post by seancostello »

I always thought "step flange" was a standard flanger, where the modulation waveform was quantized. So, instead of having a continuous triangle wave, you have a "staircase" triangle consisting of N number of steps.

I think my Boss PH-3 phase has this as one of its modes.

Sean Costello
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Sean,

Yes, that step setting on the PH-3 is something like what I am going for.

Brandon
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Hi all,

I decided to implement the 24 bit lfsr but I'm having an error with the skpzro command, it pops up with an error. I didn't know this OP code and apparently the IDE doesn't either.

Any help would be great!

; ; Frank Thomson - OCT Distribution
; V2 of 24-bit
; 2011
;
; reg 0 : lfsr register
; reg 1 : copy lfsr
; reg 1 : temp register
;
equ lfsr reg0
equ lfsr2 reg1
equ temp reg2
;
; seed the lfsr with a non-zero value
skp run,start
ldax adcl
or 0x001000 ; just to ensure it is really non-zero
wrax lfsr,0
;
;
start:
ldax lfsr ; get lfsr reg
and 0x00ffff ; get rid of upper bits to avoid saturating
wrax lfsr2,1.0 ; save the result and keep in acc
rdax lfsr2,0.5 ; get lfsr shifted 1 bit and add it
rdax lfsr2,0.25 ; get lfsr shifted 2 bits and add
rdax lfsr2,0.0078125 ; get lfsr shifted 7 bits and add
and 0x000001 ; only care about lsb of result
wrax temp,0 ; save result
rdax lfsr,0.5 ; get lfsr reg shifted right
and 0x7fffff ; clear msb
wrax lfsr,0 ; save result
ldax temp ; get the result back
skp zro,shftzro ; if 0 jump
; if here the bit was a 1
sof 0,0 ; clear acc
rdax lfsr,1.0 ; get the low
or 0x800000 ; set the bit
wrax lfsr,0 ; save it
;
shftzro:
ldax lfsr
wrax dacl,0
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Ok, never mind on that last message, I found my mistake.

So I got the code to run, but I'm not seeing any output, and I'm not sure why. The code is pasted below. Correct me if I'm wrong, but shouldn't this effectively be using the lfsr register to choose a psuedo random pointer in the delay line causing the step phase sound?

;Guitar reverb/flange
;AMDG prepaired by B.C.
;pot0 = Phase Depth
;pot1 = Phase Rate
;pot2 = Not used
;
mem phadel 512
;

equ phadel_138 phadel+138 ;mid pointer to phase delay
equ phadel_139 phadel+139 ;mid pointer to flange delay +1

equ lfsr reg0
equ lfsr2 reg1
equ temp reg2
equ phaout reg3 ;mixed phase output
equ phadout reg4 ;phase delay output
equ mix reg5 ;mix coefficient for phaser
equ fbk reg6 ;fbk coefficient for feedback around mixed phase
equ k1 reg8 ;first coefficient for linear interpolation
equ k2 reg9 ;second coefficient for linear interpolation
equ osc reg10 ;Oscillator value
equ temp2 reg11 ;temp register for Phaser

;-------------------------------------------------------
;set up lfo for reverb, 0.5Hz, +/-20 samples:
;-------------------------------------------------------
skp RUN, LOOP
wlds 0, 12, 160 ;setup LFO0
LOOP:

;--------------------------------------------------------
;prepare mix values from pot2:
;--------------------------------------------------------
rdax pot2, 1.999 ;make pot2 cause mix to be 1:1 at 50% rotation and greater.
wrax mix, 0 ;flange mix is pot2, gain causes saturation limit at approx 1.0, pot2 at midscale
rdax pot2, 1.0
mulx pot2
wrax fbk, 0 ;feedback is squared pot2, 0 to 1.0

;-------------------------------------------------------
;Set up DFII All Pass Filter for Phase
;-------------------------------------------------------

rdax phadout, 0.6 ;get fraction of phase output
mulx fbk ;multiply by feedback function
rdax adcl, 0.5 ;add inputs * 0.5 each
rdax adcr, 0.5
wra phadel, 0 ;write phase delay input, clear acc

;-------------------------------------------------------
;Set up Linear Feedback Shift Register
;-------------------------------------------------------
; seed the lfsr with a non-zero value
skp run,start
ldax adcl
or 0x001000 ; just to ensure it is really non-zero
wrax lfsr,0
;
;
start:
ldax lfsr ; get lfsr reg
and 0x00ffff ; get rid of upper bits to avoid saturating
wrax lfsr2,1.0 ; save the result and keep in acc
rdax lfsr2,0.5 ; get lfsr shifted 1 bit and add it
rdax lfsr2,0.25 ; get lfsr shifted 2 bits and add
rdax lfsr2,0.0078125 ; get lfsr shifted 7 bits and add
and 0x000001 ; only care about lsb of result
wrax temp,0 ; save result
rdax lfsr,0.5 ; get lfsr reg shifted right
and 0x7fffff ; clear msb
wrax lfsr,0 ; save result
ldax temp ; get the result back
skp zro,shftzro ; if 0 jump
; if here the bit was a 1
sof 0,0 ; clear acc
rdax lfsr,1.0 ; get the low
or 0x800000 ; set the bit
wrax lfsr,0 ; save it
;
shftzro:

;---------------------------------------------------------
;Read value from Pot 1 to determine rate
;---------------------------------------------------------
rdax pot1, 1.0 ;read pot1
mulx pot1 ;square value, range = 0 to 1
sof 0.05, 0.005 ;scale to range of 0.005 to 0.55
sof .001, 0 ;scale further to 0.00005 to 0.0055
rdax lfsr, 1.0 ;add to lfsr value

;--------------------------------------------------------
; now formulate delay pointer,
; and pass through to fract calc:
;--------------------------------------------------------
or phadel_138 < 8 ;fladel^ + 138 ;get midpoint address pointer
rdax lfsr, 0.03125 ;add lfsr wave modulation, scaled to fit delay range
wrax addr_ptr, 1.0 ;establish address for lower interpolation sample
;--------------------------------------------------------
; address pointer set, now develop fraction of tri:
;-------------------------------------------------------
and 0x0000ff ;mask off integer portion of address, leaving a fractional value in the lowest acc byte
sof -2.0, 0 ;these operations shift the resulting fractional value to the range 0.0 to 0.999...
sof -2.0, 0 ;only -2.0 is exact, but it changes sign of shifted value
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof -2.0, 0
sof 1.9999 ,0 ;15 shifts, last one is positive, and 1.9999 is nearly 2.0...
wrax k2, 1.0 ;write result as coefficient for second sample read
sof -1.0, 0.999 ;K1 is 1-K2 (or very nearly)
wrax k1, 0.0 ;write result as coefficient for first sample read
;-------------------------------------------------------
;read from first pointer:
;-------------------------------------------------------
rmpa 1.0 ;read memory for first sample read
mulx k1 ;multiply by K1
wrax temp2, 0 ;and store in temp, while clearing the acc
;-------------------------------------------------------
;get second pointer:
;-------------------------------------------------------
or phadel_139 < 8 ;phadel^ + 139 ;form second pointer
rdax lfsr, 0.03125 ;add lfsr waveform again
wrax addr_ptr, 0 ;establish address for upper interpolation sample
rmpa 1.0 ;read second interpolation sample
mulx k2 ;multiply by K2
rdax temp2, 1.0 ;add temp (first value*K1)
wrax phadout, 1.0 ;write the result to the phanger delay output
mulx mix ;multiply by the mix value
rda phadel, 1.0 ;add the input to the phaser delay
wrax phaout, 0.0 ;write result to phaout and clear acc
;
sof 1.999, 0 ;scale gain back up
wrax dacr, 1.0 ;write to right output, save accumulator
wrax dacl, 1.0 ;write to left output, clear acc
;

Please pardon me, its been a while since I've had assembly level programming.
slacker
Posts: 116
Joined: Tue Feb 01, 2011 1:13 pm

Post by slacker »

I haven't gone through the whole thing but I think the reason you're getting no output is here

Code: Select all

wrax phaout, 0.0 ;write result to phaout and clear acc
;
sof 1.999, 0 ;scale gain back up
wrax dacr, 1.0 ;write to right output, save accumulator
wrax dacl, 1.0 ;write to left output, clear acc 
You're taking the output of the phaser and writing it to the phaout register and then clearing the accumulator. This means there's nothing in the accumulator for the rest of the instructions to process so you get nothing out. You need to change the code to

Code: Select all

wrax phaout, 1
this will then write to phaout and keep the signal in the accumulator to pass to the rest of the code.

I don't think the code will do what you want though, your lfsr will generate a different random number every processor cycle so you'll probably just get noise. What you need to do is use an LFO to periodically sample and hold a random number, this will give you the stepped effect.

Something like this should work, add the wldr line under the wlds line near the top of your code. Stick the rest of it before your lfsr code, right before the "setup linear feedback shift register" line. The code sets up a ramp LFO with the speed controlled by pot2, it's a negative ramp starting at zero and going downwards. Every time it hits zero the lfsr code will run sampling a new random value, the rest of the time, while the ramp is negative the lfsr code is skipped so it holds the last value it grabbed. Hope that makes sense.

Code: Select all

wldr rmp0,0,4096


ldax pot2	;sets lfo speed
mulx pot2	;make the taper a bit nicer
muxl pot2
wrax rmp0_rate,1	;write to ramp 1 rate to set speed
cho rdal,rmp0	;get current value of rmp0 
sof -1,0		;invert ramp now goes from 0 to -0.5

skp neg, shftzro 	;if the accumualtor is negative skip to the end, do nothing

B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

Hey Slacker, thanks for the catch! It is outputting now.

I implemented the changes you suggested, but I think I have to take a look at the allpass filter. The effect is now behaving more like a ring modulator, in which the ramp is changing pitch, instead of modulating phase.
Post Reply