tap tempo snippet

Algorithm development and general DSP issues

Moderator: frank

Aaron
Posts: 54
Joined: Wed Mar 04, 2015 8:10 pm
Location: Oklahoma

Post by Aaron »

For those interested in using a sin for the LED rate indicator you will have to convert the "taptempo" register's values from a time to a frequency which can be done using the log and exp functions.

AN-0001 gives us the formula for finding the frequency coefficient for the wlds instruction which is:

Kf = 2^17 * (2piF/R)


Since the taptempo register is giving us a time value, we can find its frequency by inverting it using the log and exp functions which would look like:

Code: Select all

ldax taptempo     ;load taptempo
log -1,0              ;log base 2 of taptempo/16 * K + C
exp 1,0              ;2^(ACC * 16) * K + C
So now we can use this value and plug it into the formula for Kf. The only problem being that all of these values are way too large for the ACC to handle. Luckily, we can scale all of these values by doing all of the necessary math within the log and exp functions.

log(a*b) = log(a) + log(b)
log(a/b) = log(a) - log(b)


log(F) + log(2pi/R) + log(2^17) - log(512)

So we will end up with something like this:

Code: Select all

ldax     taptempo         ;load taptempo
log     -1,-0.271785      ;C = a reduced value of log(2pi/R) + log(2^17) - log(512)
exp     1,0                  ;
wrax    sin0_rate,0      ;save this value to sin0 rate

This can now replace:

Code: Select all

;Taptempo rate indicator, creates a square wave at the tap tempo rate 

sof	0,0.0625
wrax	rmp1_rate,0			;set rmp1 rate to 1Hz 
cho	rdal,rmp1			;read value of rmp1 
sof	-2,0.999				;level shift to 0 - 1 rising ramp 
sof	1,-0.001 			;
rdax	taptempo,-0.5			;deduct half of the taptempo value 
skp	neg,ENDLED			;if negative skip to ENDLED 
jam	rmp1				;else reset ramp1
ldax 	led				;and invert value of led register, creates square wave at taptempo rate 
sof	-1,0 				;increase gain to cause clipping
wrax	led,0 				;save to led, clear ACC
smear
Posts: 39
Joined: Fri Jul 01, 2016 9:47 am

Post by smear »

Thanks for the info on using a sin for the LED.

Speaking of which, what are you guys using as drivers? A simple transistor circuit?
slacker
Posts: 116
Joined: Tue Feb 01, 2011 1:13 pm

Post by slacker »

Yeah just an emitter follower, I stick a 100k resistor between the FV-1 output and the base of the transistor but may not be needed.

Something like this example, pretty much any NPN will work, adjust resistor value to taste.
Image
potul
Posts: 76
Joined: Tue Sep 26, 2017 12:33 am

Post by potul »

Reviving an old but interesting thread....

Looking at the tap tempo code, I see most of the instructions are used for switch debouncing. Could we do it simpler by using better the spinASM capabilities?
What about using a simple low-pass filter and some threshold detection?
slacker
Posts: 116
Joined: Tue Feb 01, 2011 1:13 pm

Post by slacker »

You might be able to do it with less code, I don't think lowpass filtering will help though the pot inputs are already lowpass filtered.
You could try reading the pot input and if it's below some threshold flip the "latch" value, then have a counter to create delay before you check the switch again. That might be good enough.
potul
Posts: 76
Joined: Tue Sep 26, 2017 12:33 am

Post by potul »

slacker wrote:You might be able to do it with less code, I don't think lowpass filtering will help though the pot inputs are already lowpass filtered.

You could try reading the pot input and if it's below some threshold flip the "latch" value, then have a counter to create delay before you check the switch again. That might be good enough.
Good point about the low filtering.... I will do some testing... maybe just adding some hysteresis between 2 thresholds is good enough for debouncing.[/quote]
gbiz
Posts: 5
Joined: Sat Jan 17, 2015 5:40 am

Post by gbiz »

I was looking to reduce the size of the previously taptempo code so i could do a clocksync'd echo with a basic reverb. This works for me for clocksync delays in a synth. IIRC it gives a saving of 12 instructions.
I've stripped out all the delay declarations, echo code etc, this is just the clocksync code.
I guess i should add that I use this for a synth module where it's usually clocked with a square wave with reasonably sharp edges. I haven't tested it with a tap tempo guitar pedal where you'd possibly need some debounce.

Code: Select all

; ***********************
; declarations

equ	smooth		0.001		; general smothing filter coeff
equ	delaytime	330		; initial delay time until we get a valid clock sync
equ     holdoff_count   0.05            ; debounce counter (0.05 is 1.5msec)
equ	count		0.001		; debounce counter

; pots
equ	TimePot		pot0

equ     overrun         reg21
equ     holdoff         reg22
equ     ramp            reg23           ;current value of rmpo, scaled to 0 to 1
equ     taptempo        reg24           ;taptempo value, 0 to 1

;*******************************************************
; initialisation
skp	run, loop

; init for clocksync
wldr	rmp0, 0, 4096			;set up rmp0
sof	0, 0.99		
wrax    overrun, 0              ; overrun can have any non-zero value
wrax    holdoff, 0              ; clear debounce/holdoff counter
sof	0, delaytime/1000		;set initial delay time
wrax	ramp, 1
wrax	taptempo, 0

; ***********************
; main loop
loop:

; get input signal

; pots

; read feedback level pot

; ***********************
; start clock sync ...
rdax    TimePot, 1                      ;read pot
sof     1, -0.5                         ;level shift to -0.5 to 0.5
skp     gez, Poz

; clock sync signal is < 0.5 (less than 1.65V at the CV input)
; just set holdoff negative
Neg:
sof     0, -count
wrax    holdoff, 0
skp     zro, INCLK

; clock sync signal is >= 0.5 (greater than 1.65V at the CV input)
; on the rising edge of a clock pulse ie first time through here, zero
; out the holdoff counter, it'll be negative from "Neg:"
; then increment holdoff counter
; for subequent passes just increment the holdoff counter
; when the holdoff_count passes a specific value (say, 50 == 1.5msec),
; it's safe to assume the pulse is stable so run the NEWCLK code to reset the ramp timer
; any other value just drop through to INCLK
Poz:
ldax    holdoff
skp     gez, Poz1                       ; zero out holdoff if this is the first +ve
clr
Poz1:
sof     1, count
wrax    holdoff, 1
sof     1, -holdoff_count
skp     zro, NEWCLK                     ; clock has been +'ve for holdoff_count cycles, call NEWCLK

;tap tempo, uses rmp0 as a 1 Hz rising ramp,
; if period between clock sync pulses is greater than 1sec, overrun is 0, so just use the previous
; valid value for taptempo
INCLK:
ldax    overrun
skp     zro, END_CLKSYNC                ; overrun is 0 if this cycle has overrun

sof     0, 0.0625
wrax    rmp0_rate, 0                    ;set rmp0 rate to 1Hz
cho     rdal, rmp0                      ;read value of rmp0
sof     -2, 0.999
sof     1, 0.001                        ;level shift to 0 to 1 rising ramp
wrax    ramp, 1                         ;write to ramp
sof     1, -0.999                       ;deduct 1 from ramp (use 0.5 for dual tap delay)
skp     neg, END_CLKSYNC                ;if answer is positive then second tap hasn't happened with 1s of first
OVER_RUN:                               ; timer has overrun 1sec, so ignore this sample period, use previous legit one
ldax    taptempo                        ;so keep last value of taptempo
wrax    ramp, 0
wrax    overrun, 0                      ; overrun is 0 this clock cycle has overrun
skp     zro, END_CLKSYNC                ;jump to end of clocksync

; this code is run at the start of a new clock pulse
; reset rmp0 & read the previous ramp count into taptempo
NEWCLK:
jam     rmp0
ldax    ramp
wrax    taptempo, 1
wrax    overrun, 0                      ; stuff any non-zero value into overrun

END_CLKSYNC:

; ***********************

ldax	taptempo
rdfx	offset, smooth
wrax	offset, 0

; ***********************
;; either ...
;ldax	taptempo
;rdfx	offset, smooth
;wrax	offset, 0
;; delay tap
;or	DelayMem * 256
;rdax	offset, 1
;wrax	addr_ptr, 0
;rmpa	1

; ***********************
;; or if you're really short on instructions & need 2 more, replace the last bit with
clr
or	DelayMem * 256
rdax	taptempo, 1
wrax	addr_ptr, 0
rmpa	1

; rest of code here ...
drakston
Posts: 1
Joined: Tue Jul 03, 2018 1:07 am

Re: tap tempo snippet

Post by drakston »

Hello

I used the last code which on pot2 has tap tempo and on pot1 smooth adjustments but I have a question whether it can be done so that if I have any time set on pot1, when it picks up on pot2 it will be taken into account with taptempo, if now I turn on the potentiometer again pot1 will take the delay time from this pot1

I guess you need to make changes to this part of the code, but can anyone help you?

Code: Select all

;Pot control on POT1

ldax pot1		;read pot1
sof 1,-0.05		;shift down now -0.05 to 0.95
skp neg,DODELAY		;if negative skip to delay, taptempo mode
ldax pot1		;else read pot1
sof 1/0.95,-0.05/0.95 	;scale to 0 to 1
wrax taptempo,0		;and write to taptempo register, pot controls delay time
edit: ok I found back in teh topic some code from slacker and it work as I want,

Code: Select all

ldax pot1
and %01111111_00000000_00000000
rdax time_pot,-1
skp zro,DODELAY
ldax pot1      ;else read pot1
and %01111111_00000000_00000000
wrax ramp,1      ;and write to ramp register, pot controls delay time
wrax time_pot,0
but, below a certain threshold, by turning down the potentiometer pot1, it stops setting the time and I have no sound of delay only bypass sound

any idea how to eliminate this ?
danfromdsf
Posts: 1
Joined: Fri Nov 09, 2018 3:51 pm

Re:

Post by danfromdsf »

slacker wrote: Tue Jun 04, 2013 11:01 am If you want a smaller maximum delay you need to change the following part of the code.

Code: Select all

LOW:
 sof 0,0.064       
 wrax rmp0_rate,0      ;set rmp0 rate to 1Hz
 cho rdal,rmp0      ;read value of rmp0
 
The sof 0,0.064 sets up a 1Hz ramp to give delay time up to 1 second, so for 700ms you change the sof command to

Code: Select all

sof 0,0.089285


This gives a ramp 700ms long. The formula to calculate the sof command for different delays is 1/delay time in seconds/16 so for 700ms 1/0.7/16 = 0.089285.....
I keep coming back to this post as I work on a tap tremolo. It's the only reference I've found (official documentation or otherwise) for setting the frequency of a ramp. Substituting 1/frequency for time the equation becomes frequency/16, which makes it incredibly simple if you know your desired Hz! So first off, thanks slacker and everyone else for this and the wealth of information in this thread. But I'm wondering: where does this equation come from? And is it an estimation, or a dead on formula? I ask partially because the sof 0, 0.064 sets up a 1Hz ramp, but if we follow through the equation 1/16=0.0625. Where does the extra .0015 come from? Would love help if anyone has input on this!


UPDATE: I realized I had the tools to do some extra research on my own - outputting a ramp to one of the analog outs to measure its frequency, controlling that frequency with a pot and measuring the voltage of the pot, I ended up at the following: Kf(decimal) = (f + 0.75) / 17.5
It seems strange, a linear relationship with a small offset, but applying it to this tap tremolo project locked everything in. Posting here in hopes it can help the next person wondering the same thing!
epreuss
Posts: 1
Joined: Fri Aug 17, 2018 8:34 am

Re: tap tempo snippet

Post by epreuss »

Hey fellows,

I am new to the forum but got the chance already programming a bit on the FV-1.

I am having a couple of question about the Tap-Tempo, I am using the one with two pots, one for the momentary switch and the other one to control the delay-time:

1) Is there a chance that you don't have to set the delay-time pot to zero to activate the tap tempo mode? I mean it's cool that it will be saved after tapping in the tempo and changing the pot to a manually set delay time, but the fact that you have to turn it to "zero" is a bit tricky. It would be great when you could just overwrite the delaytime by generally checking if you have a low to high or vice versa transition like the actual code is doing. Is it unavoidable to have the pot at zero to detect the taps?

2) I was adding an external modulation source, which was working great on the delaytime manual mode but not working when it is in taptempo mode. Do i have to modulate the ramp any kinda way for that after saving the latched ramp value? I did that after i LDAX the taptempo reg value before i read the pointer. I propably mixing up something in the code, or just lacking of knowledge.

3) Would be a microcontroller the smartest way to avoid the above mentioned issues? If so, I have to dive into Arduino programming to realize that what i want to and use a micro

I would appreciate every small bits of info, since I am pretty nooby still

Sorry and thank you in advance, Enrico
Post Reply