External tap tempo with FV-1

Started by mark2, March 31, 2021, 06:28:42 PM

Previous topic - Next topic

mark2

I'm curious if anyone has put together an external tap tempo using a microcontroller and interfaced it with the FV-1 using either PWM or a digital pot.

In theory it seems very simple, but I'm expecting that in practice translating the actual interval time to an appropriate analog voltage or PWM signal will be ... problematic.

It's on my near-term todo list so I can certainly post back with what I find, but I thought I'd put out a feeler first to see if anyone had any experiences to share. Thanks!

octfrank

Used a micro to handle debounce, interval division, etc. then drove a POT input on FV-1 high for as long as the desired delay. FV-1 watched for the POT going high and simply counted the number of sample periods the POT was high and that became the delay time. Much better resolution than trying to use the analog value as the delay time.
Frank Thomson
Experimental Noize

mark2

Yeah, that makes a lot of sense, thanks.

Sweetalk

I use a uC to handle the tap tempo and delay pot. Using a semaphore the uC handles the delay setting priority of the Pot or the Tap, when either one changes the last state (with some histeresys to avoid glitches or false changes) takes the semaphore and changes the delay and so on. Then divide/multiply to handle subdivisions.

To the FV1 goes a PWM signal and in the soft just a regular delay program reading one of the pot inputs. The resolution is good enough!.

Quote from: octfrank on March 31, 2021, 08:01:57 PM
Used a micro to handle debounce, interval division, etc. then drove a POT input on FV-1 high for as long as the desired delay. FV-1 watched for the POT going high and simply counted the number of sample periods the POT was high and that became the delay time. Much better resolution than trying to use the analog value as the delay time.
That's a nice approach. It uses much instructions on the FV1?. I prefer to use more coding on the uC (more room for that) and leave the FV1 as simple as possible.

potul

Quote from: octfrank on March 31, 2021, 08:01:57 PM
Used a micro to handle debounce, interval division, etc. then drove a POT input on FV-1 high for as long as the desired delay. FV-1 watched for the POT going high and simply counted the number of sample periods the POT was high and that became the delay time. Much better resolution than trying to use the analog value as the delay time.

This is what I do in my taptempo implementation. Send a pulse to the FV1 and read the duration of it. I tried the PWM approach and it was not very reliable.
One small detail though: Using the pulse approach has a drawback... you need to wait for an additional tempo cycle (once the uC knows the tapped tempo, it needs to "transmit it" to the FV1). For longer delays, this is somehow anoying because it can take up to 1 second for the FV1 to adapt to the new tempo. To overcome this I scaled down the pulse. I divide it by 4, so a 1 second delay transmits a 250ms pulse. Then I compensate in the FV1 for it.
In order to make this work, you need to use the "fast POT" trick to avoid the POT filtering ruinining the slowest tempos.




Sweetalk

Quote from: potul on April 05, 2021, 11:27:15 AM
Quote from: octfrank on March 31, 2021, 08:01:57 PM
Used a micro to handle debounce, interval division, etc. then drove a POT input on FV-1 high for as long as the desired delay. FV-1 watched for the POT going high and simply counted the number of sample periods the POT was high and that became the delay time. Much better resolution than trying to use the analog value as the delay time.

This is what I do in my taptempo implementation. Send a pulse to the FV1 and read the duration of it. I tried the PWM approach and it was not very reliable.
One small detail though: Using the pulse approach has a drawback... you need to wait for an additional tempo cycle (once the uC knows the tapped tempo, it needs to "transmit it" to the FV1). For longer delays, this is somehow anoying because it can take up to 1 second for the FV1 to adapt to the new tempo. To overcome this I scaled down the pulse. I divide it by 4, so a 1 second delay transmits a 250ms pulse. Then I compensate in the FV1 for it.
In order to make this work, you need to use the "fast POT" trick to avoid the POT filtering ruinining the slowest tempos.

Before using the approach I mentioned before (letting the uC do all the heavy lifting with the tap tempo and sending a PWM signal proportional to the tempo) I used a uC to calculate the tempo, send a train of pulses for a time window (to avoid sending a square signal continously) and reading in the FV1 like the tempo is beign tapped there in a pot input. I have to adjust the pulse width in order for the slow and fast setting to be correct. There was no big lag in long settings but it was code consuming on the FV side and I couldn't do the priority check on the delay pot and tap tempo. The other approach gives me more control, better user interface and since I already placed and uC to do this it was silly to do it the previous way.

Maybe if you adjust the pulse width you will have better resolution in fast settings and not much lag on the long.

MetalGuy

I have this code but don't remember from where. Never tried it:

;tap tempo delay
;mono input (ADCL) mono output (DACL)
;a 0 - 0.99 square wave at the tap tempo rate is send to DACR. This can be used to flash a LED using a suitable driver.
;Pot 2 is used as a tap tempo switch input. This should be a momentary switch, transition can be high to low or low to high.
;see guitar amp application note for examples of switch hookup. 
;pot 0 = feedback
;pot 1 = set below 0.05 delay is taptempo controlled, above 0.05 pot1 sets delay time

;set up registers and equates

equ  db reg0 ;debounce
equ  mom reg1 ;momentary output of switch +1 high, -1 Low
equ  latch reg2 ;latched output of switch +1 high, -1 low
equ ramp reg3 ;current value of rmpo, scaled to 0 to 1
equ taptempo reg4 ;taptempo value, 0 to 1
equ fback reg5 ;feedback
equ delayout reg6 ;delay output
equ clip reg7 ;clipping
equ led reg8 ;taptempo LED

equ count 0.01 ;debounce counter
equ delaytime 330 ;initial delay time in milli seconds

mem delay 32767

skp run,START
wldr rmp0,0,4096 ;set up rmp0
wldr rmp1,0,4096 ;set up rmp1
sof 0,0.99
wrax latch,1 ;set latch = 1 high
wrax led,0 ;set led = 1 high
sof 0,delaytime/1000 ;set initial delay time
wrax ramp,0

START:

;Switch Debouncing and pot filtering work around

ldax   pot2 ;read pot2
sof 1,-0.5 ;level shift to -0.5 to 0.5
skp neg,DOWN ;if negative jump to DOWN
ldax db ;else high, read db
sof 1,count ;add count
wrax db,0 ;write new value to db
skp zro,ENDDB ;jump to ENDDB
DOWN:
ldax db ;read db
sof 1,-count ;deduct count
wrax db,0 ;write new value to db

ENDDB:

;latching switch, falling edge triggered flipflop
;Output of debounce routine of < -0.9 is low, > 0.9 is high, values in between
;are ignored and the switch does nothing, Schmitt trigger action.


ldax db ;read db
absa ;get absolute value
sof 1,-0.9 ;deduct 0.9 so only values < -0.9 or > 0.9 give a positive result
skp neg,ENDSWITCH ;if negative then jump to ENDSWITCH
ldax db ;read db
sof 1,-0.9 ;deduct 0.9
skp neg,LO ;if negative jump to LO, output of debounce is low
sof 0,0.999 ;else output of debounce is high
wrax mom,0 ;set mom to 1 &#40;high&#41;
skp zro,ENDSWITCH ;jump to ENDSWITCH
LO&#58;
ldax mom ;read mom
skp neg,ENDSWITCH ;if it's negative then debounce was already low last time so do nothing, jump to ENDSWITCH
sof 0,-0.999 ;else mom was high last time so switch has only just been pressed &#40;falling edge&#41;
wrax mom,0 ;set mom to -1 &#40;low&#41;
ldax latch ;read latch
sof -1,0 ;invert, high becomes low, low becomes high
wrax latch,0 ;write to value to latch

ENDSWITCH&#58;

;tap tempo, uses rmp0 as a 1 Hz rising ramp, runs whilst latch is low and is sampled and held when latch is high

ldax latch ;read latch
skp neg,LOW ;if negative jump to LOW
jam rmp0 ;else latch is high, jam rmp0 &#40;reset to 0&#41;
ldax ramp ;read ramp, will contain last value of rmp0 before latch went high
wrax taptempo,0 ;write to taptempo
skp zro,ENDTT ;jump to ENDTT
LOW&#58;
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 0.999 from ramp
skp neg,ENDTT ;if answer is positive then second tap hasn't happened with 0.999 ms of first
ldax taptempo ;so keep last value of taptempo
wrax ramp,0
sof 0,0.999 ;and reset latch high
wrax latch,0
ENDTT&#58;

;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
wrax led,0
ENDLED&#58;

;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

DODELAY&#58;

clr
rdax fback,1 ;read feedback register, scaled to 0.95%
rdax adcl,1 ;mix with input from ADCL
wra delay,0 ;write to head of delay
ldax taptempo ;read taptempo register
wrax addr_ptr,0 ;write to delay address pointer
rmpa 1 ;read from delay address set by pointer
wrax delayout,1 ;write to delayout register

mulx pot0 ;mulx with pot0, feedback level control
wrax clip,-0.33333 ;soft clip, using cube distortion snippet
mulx clip
mulx clip
rdax clip,1
wrax fback,0 ;write to feedback register

rdax delayout,0.5 ;read delayout register
rdax adcl,1 ;mix with input from ADCL
wrax dacl,0 ;write to DACL

ldax led ;read led register
wrax dacr,0 ;write to DACR, flashes LED attached to DACR

octfrank

Frank Thomson
Experimental Noize

potul

Quote from: Sweetalk on April 06, 2021, 09:35:04 AM
Quote from: potul on April 05, 2021, 11:27:15 AM
Quote from: octfrank on March 31, 2021, 08:01:57 PM
Used a micro to handle debounce, interval division, etc. then drove a POT input on FV-1 high for as long as the desired delay. FV-1 watched for the POT going high and simply counted the number of sample periods the POT was high and that became the delay time. Much better resolution than trying to use the analog value as the delay time.

This is what I do in my taptempo implementation. Send a pulse to the FV1 and read the duration of it. I tried the PWM approach and it was not very reliable.
One small detail though: Using the pulse approach has a drawback... you need to wait for an additional tempo cycle (once the uC knows the tapped tempo, it needs to "transmit it" to the FV1). For longer delays, this is somehow anoying because it can take up to 1 second for the FV1 to adapt to the new tempo. To overcome this I scaled down the pulse. I divide it by 4, so a 1 second delay transmits a 250ms pulse. Then I compensate in the FV1 for it.
In order to make this work, you need to use the "fast POT" trick to avoid the POT filtering ruinining the slowest tempos.

Before using the approach I mentioned before (letting the uC do all the heavy lifting with the tap tempo and sending a PWM signal proportional to the tempo) I used a uC to calculate the tempo, send a train of pulses for a time window (to avoid sending a square signal continously) and reading in the FV1 like the tempo is beign tapped there in a pot input. I have to adjust the pulse width in order for the slow and fast setting to be correct. There was no big lag in long settings but it was code consuming on the FV side and I couldn't do the priority check on the delay pot and tap tempo. The other approach gives me more control, better user interface and since I already placed and uC to do this it was silly to do it the previous way.

Maybe if you adjust the pulse width you will have better resolution in fast settings and not much lag on the long.

The lag was a result of the concept... If I set a 1 second delay by tapping, once I have finished tapping the uC sends the pulse or train of pulses to the FV1, that will last 1 second. So between the last tap and the FV1 changing tempo there is 1 second gap. As I mentioned, what I did is scale down the pulse train, so now the gap is only .25 seconds worst case and it's ok from the UX perspective.
I also manage a pot and tap tempo and subdivisions from the uC, and incorporated some preset capability as well. All managed by the uC.