Flip flop

Algorithm development and general DSP issues

Moderator: frank

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

Flip flop

Post by livingston »

I'm trying to do something kind of like the old analog octave down pedals that generate a square wave, except going several (say 4) octaves down. These, I think, use flip flop circuits to change sign every time a rising edge happens at their input, generating a square wave an octave lower than the input. So I'd like to do something like that, where the square wave is divided in frequency several times.

How do I do the logic? I know from previous threads how to count zero crossings, but how can we either ignore every other zero crossing, or read only positive-going edges?

I plan to iterate this several times, so if there's way to discard 7 out of every 8 zero crossings, without doing intermediary flip-flops, that would be even better.
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

To avoid using extra flip flops use a counter, logic would be something like (excuse the pseudo code, not in the office to try this)

at start load counter with X (X is number of crossings to skip before inverting flop) and set "flop" to 0

at zero crossing, decrement counter
is counter <= 0?
if yes, invert flop, reload counter with X
if no, do nothing
output flop
Frank Thomson
Experimental Noize
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

So here's what I came up with:

Code: Select all

equ 	old_sig 	reg0 
equ	counter	reg1
equ	square	reg2

skp	run, doit
clr
rdax	pot0,1
wrax	counter,0	;load counter with a number. Number is varied by pot0
sof	0,.5
wrax	square,0		;create square wave
doit:

ldax 	old_sig 		; read in saved value 
ldax 	adcr 		; read in ADC left, also pushes ACC -> PACC 
skp 	zrc,different 	; skip if the signs of ACC and PACC are different 

; if here the sign of both old_sig and adcl are the same 

wrax 	old_sig,0		; save the adcl to old_sig 
clr 
skp 	zro,end		; jump over the routine for zero crossing 
different: 

; if here the signs are different so a zero crossing happened 
wrax      old_sig,0		; save the adcl to old_sig 
rdax	     counter,1
sof	     1,-.1		;decrement counter
skp	    gez,nothing	;if counter is greater than zero, do nothing
rdax	    square,1		;if counter is less than zero, flip sign of square
sof   -1,0
wrax	    square,0
sof	   0, .7
wrax	    counter,0

nothing:
wrax	     counter,0
end:
rdax	   square,1
SKP   GEZ,1            ;make square only positive
CLR                       ;make square only positive
mulx	     adcr
wrax	    dacr,0

What it's supposed to do is: make an audio rate square wave triggered by zero crossings in the input signal. Then divide that square wave down to an LFO whose pitch is proportional to the input pitch. Then use this square to cut the input on and off, thus creating a square wave tremolo whose speed changes on different notes.

But it doesn't work. What I get out of the output is the input, with some noise on top. It's kind of like a terrible fuzz pedal sound. I know there's got to be some error in the logic, but I can't figure it out. I know you said to load the flop with zero ("square" is the flop here) but I figured that couldn't be right since changing the sign of zero just gives you zero.

Any thoughts?
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

I haven't had the chance to run it but a quick read seems like the logic is sound, a couple things to try:

1. Give the input signal lots of gain, we want to try to "square it up" prior to using it.

2. You said:
livingston wrote:I know you said to load the flop with zero ("square" is the flop here) but I figured that couldn't be right since changing the sign of zero just gives you zero.
Actually zero is correct but I failed to explain how to use it, sorry. For things like this I tend to use XOR to invert a bit value. For example:
A = 0x01000
B = 0x01000
A = A XOR B results in A = 0x00000
If we do it again
A = A XOR B results in A = 0x01000

So if we treat A as the square wave and B as our inversion mask we can flip the value between 0 and 1 easily. This removes the need at the end of your code for the GEZ and forcing a negative value to 0 to have a positive only output. Note that a +/-1 output should also work fine so you can still do the SOF and just output the result directly, again getting rid of the GEZ at the end.
Frank Thomson
Experimental Noize
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

frank wrote:I haven't had the chance to run it but a quick read seems like the logic is sound, a couple things to try:

1. Give the input signal lots of gain, we want to try to "square it up" prior to using it.
I see what you're saying, and you're right, but low input gain wouldn't make it not work, I think it would just have bad tracking, right? If you do have a chance to try the code it would be a big help. I can't seem to get anywhere with this.
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

Give this a try, reads audio in from left and outputs audio on left (clean, no effect) and square wave on right. POT0 varies square wave frequency ratio.

Code: Select all

equ    old_sig    reg0
equ   counter   reg1
equ   square   reg2
equ	length	reg3

skp   run, doit
clr
wrax   square,0      ;initialize square wave


doit:
clr
rdax   pot0,1	; read in POT0
wrax   length,0   	; load count length with a number. Number is varied by pot0

ldax    old_sig       ; read in saved value
ldax    adcl       	; read in ADC left, also pushes ACC -> PACC
skp    zrc,different    ; skip if the signs of ACC and PACC are different

; if here the sign of both old_sig and adcl are the same
wrax    old_sig,0	; save the adcl to old_sig
skp    zro,end	; jump over the routine for zero crossing


different:
; if here the signs are different so a zero crossing happened
wrax      old_sig,0      ; save the adcl to old_sig
rdax      counter,1	; read in the counter
sof        1,-.2      ;decrement counter
skp       gez,nothing   ;if counter is greater than zero, do nothing
clr
rdax       square,1      ;if counter is less than zero, flip sign of square
xor 0x7fffff
wrax	square,0	; save the inverted square
rdax	length,1.0 ; read in the counter reload value

nothing:
wrax        counter,0	; save the counter value
end:
rdax      square,1		; read the square wave
wrax       dacr,0		; output square wave on DAC right
rdax	adcl, 1.0		; read in audio from ADC left
wrax	dacl, 1		; Output audio on DAC left
Frank Thomson
Experimental Noize
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

Aha, yes I needed that clear the counter before creating the square wave. And the addition of the Length register is probably important, though I'm not sure I understand precisely what it's for. I guess it's not good to write a pot directly to the counter?

BTW, the program as you've got it there makes a very nice little square wave octave synth effect. Just tack the input envelope onto that square wave and maybe a filter on the end.
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

livingston wrote:And the addition of the Length register is probably important, though I'm not sure I understand precisely what it's for. I guess it's not good to write a pot directly to the counter?
Habit, normally I would have done things like limited the range of the pot or made it an exponential sweep or ??? So I would save the result in a reg then use that where necessary. But if you want to use the raw pot value there is nothing wrong with doing that if it fits the program.

livingston wrote:BTW, the program as you've got it there makes a very nice little square wave octave synth effect. Just tack the input envelope onto that square wave and maybe a filter on the end.
Hmmm, may try to play with that later. I developed the program using a function generator and a scope to watch the signals to make sure it was working properly so really haven't listened to it.
Frank Thomson
Experimental Noize
livingston
Posts: 131
Joined: Sun Nov 15, 2009 3:37 pm
Location: New Orleans, LA US

Post by livingston »

So how would we do a multiplier instead of divider? I don't need actual code, just having a hard time coming up with the conceptual basis.

If we keep the zero crossing routine, and every time there's a zero crossing, we flip the phase twice, I suppose that would give an octave up, but the positive pulse would have the same width no matter what the input pitch, which might sound weird.

Maybe the easiest way to do this in the FV-1 is to just use the pitch shifter algo, do it a few times to give 3 or 4 octaves up (quality of audio won't matter since we're converting to a square wave), then divide down as much as we want. The pitch shift's delay might get too bad iterating it that much though.
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Post by frank »

A digital PLL is a typical way to do a multiplier. It will lag a little and it won't respond as fast to changes on the input as the divide does but it should have less delay than the pitch shift algo.
Frank Thomson
Experimental Noize
amz-fx
Posts: 38
Joined: Wed Sep 06, 2006 7:06 am
Location: Louisiana, USA
Contact:

Post by amz-fx »

livingston wrote:So how would we do a multiplier instead of divider? I don't need actual code, just having a hard time coming up with the conceptual basis.
When you cross zero going up, you output a pulse of a fixed width. When it crosses zero going down, you output another pulse... this effectively doubles the frequency. I've made this with cmos chips and it works but the sound will be somewhat synth-like.

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

Post by livingston »

Right, that's what I was getting at here, though it may not have been clear:
livingston wrote: If we keep the zero crossing routine, and every time there's a zero crossing, we flip the phase twice, I suppose that would give an octave up, but the positive pulse would have the same width no matter what the input pitch, which might sound weird.
So the width of the pulse would have to be set in the code, I think, which would be strange since in a regular pulse wave, the proportion between high and low is the same at any frequency, whereas here, low notes would have very narrow pulse width, approaching 100% duty cycle on the lowest notes.
B.C.
Posts: 38
Joined: Sat Mar 06, 2010 5:28 pm

Post by B.C. »

frank wrote:A digital PLL is a typical way to do a multiplier. It will lag a little and it won't respond as fast to changes on the input as the divide does but it should have less delay than the pitch shift algo.
Whoa, thats cool. Will check out.
amz-fx
Posts: 38
Joined: Wed Sep 06, 2006 7:06 am
Location: Louisiana, USA
Contact:

Post by amz-fx »

livingston wrote:So the width of the pulse would have to be set in the code, I think, which would be strange since in a regular pulse wave, the proportion between high and low is the same at any frequency, whereas here, low notes would have very narrow pulse width, approaching 100% duty cycle on the lowest notes.
The high E string at the 12th fret of a guitar is 660Hz (approx). This means that each wave cycle takes 1.5 ms.

So if we output a pulse of 1.2 ms then we have an "on" time of around 80% of the cycle.

The low E note on the guitar is 82 Hz with a cycle taking 12.2 ms. A 1.2 ms pulse is "on" about 10% of the time.

We have a pulse width that is varying from 10% to 80%, and that's not too bad. What changes is the harmonics of the sound... 50% duty cycle is woody sounding while a narrow duty cycle is more string-like. There were string synths back in the day of top-octave-dividers that used narrow pulses for string synth sounds. An 80% duty cycle and a 20% will sound much the same.

None of them sound bad and it might even give a more realistic quality with different pulse widths. Varying the duty cycle sounds a lot like a filter opening and closing since the harmonics are changing.

A 2.4 ms wave will be 50% duty cycle and this is very close to G#4 - high E guitar string's 4th fret.

Note to Frequency calculator: http://www.muzique.com/schem/freq.htm

regards, Jack
Post Reply