Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set the BPM explicitly from LFE #46

Open
1 of 4 tasks
Tracked by #42
oubiwann opened this issue Dec 31, 2021 · 6 comments
Open
1 of 4 tasks
Tracked by #42

Set the BPM explicitly from LFE #46

oubiwann opened this issue Dec 31, 2021 · 6 comments
Labels
enhancement Update for an existing feature
Milestone

Comments

@oubiwann
Copy link
Contributor

oubiwann commented Dec 31, 2021

Tasks:

  • Figure out how to get values of 30-300 BPM from MIDI CC to VCV Rack clocks
  • Write an LFE function that maps desired BPM value to the appropriate combination of MIDI CC values (see table and screenshot below, in the comments)
  • Add API support for setting the BPM
  • Remove all code that dynamically calculates the BPM

Part of #42

@oubiwann oubiwann added the enhancement Update for an existing feature label Dec 31, 2021
@oubiwann oubiwann added this to the 0.2.0 milestone Dec 31, 2021
@oubiwann
Copy link
Contributor Author

oubiwann commented Dec 31, 2021

Looks like the BPM voltage is this:

Voltage BPM
-2 30
-1 60
0 120
1 240
~1.322 300

So ... for x from -2 to 1 Volts:

  • y = 2^(x + 2) * 30 BPM -->
  • y/30 = 2^(x + 2) -->
  • log2(y/30) = x + 2 -->
  • x = log2(y/30) - 2

This checks out:

lfe> (- (math:log2 (/ 300 30)) 2)
1.3219280948873622

@oubiwann
Copy link
Contributor Author

oubiwann commented Dec 31, 2021

Using 4 MIDI CC inputs to generate BPM voltages (the more, the smoother it is between higher BPMs) ...

cc val (0,1,2,3) volts bpm
0,0,0,0 -2 30
127,0,0,0 -1.177 53
127,127,0,0 -0.344 95
127,127,127,0 0.489 168
127,127,127,127 1.321 30

Screenshot of used modules:

Screenshot 2021-12-31 at 4 13 01 AM

In the above, the offset modules are set to the following:

  • offset: -2V
  • scale: 0.3315
  • order of operations: scale then offset

and then for the umix module:

  • input gain: -12 db
  • hard output clipping

@oubiwann
Copy link
Contributor Author

oubiwann commented Dec 31, 2021

Looks like I found a better solution:

Screenshot 2021-12-31 at 5 28 35 AM

the exponent module configured with:

  • shape: -5
  • shape depth: 1
  • input voltage range: 10

offset module:

  • offset: -2
  • scale: 0.33655

This setup gives the following spread:

cc val bpm
0 30
32 97
64 157
92 228
128 300

The differences between those:

lfe> (- 97 30)
67
lfe> (- 157 97)
60
lfe> (- 228 157)
71
lfe> (- 300 228)
72

That's as close as I could get to linear 😉

This experiment was accomplished with the following setup:

Screenshot 2021-12-31 at 5 43 58 AM

@oubiwann
Copy link
Contributor Author

The one downside of that last approach was that, as the 300 BPM mark is approached, resolution is lost and things get pretty jumpy. In fact, long before the 300 BPM mark.

Good new/bad news:

  • VCV Rack now supports 14-bit MIDI
  • This is a cumbersome approach and it's too smooth as the BPM count grows higher ...

It requires a couple of right-click changes to the MIDI CC - CV module:

Screenshot 2021-12-31 at 1 48 50 PM

(uncheck "Smooth" and check "14-bit ...")

With that change, the following was able to generate a perfectly smooth, continuous BPM ramp, from 30 to 300, no BPMs left behind:

lfe> (list-comp ((<- x (lists:seq 0 127)) (<- y (lists:seq 0 127 5)))
       (um:bank-select x y 0) (timer:sleep 250))

I suspect what I'll end up doing is generating a list of BPM/bank select tuples ...

@oubiwann
Copy link
Contributor Author

That's basically an LFO ramp: raw input (once the bank select calls are received by VCV Rack) is from 0 to 10V. VCV Rack crashes if I don't put a sleep between calls, but I was able to bring it down to a 100 millisecond wait instead of 250. With the 5-step jumps in y, this is incrementing 0.003 Volts every 100 ms, so that works out to about 5.5 minutes to do the whole ramp.

@oubiwann
Copy link
Contributor Author

oubiwann commented Dec 31, 2021

Not quite there, but close:

lfe> (set msbs-lsbs (list-comp ((<- msb (lists:seq 0 127)) (<- lsb (lists:seq 0 127 5))) (list msb lsb)))
lfe> (set select-voltages (list-comp ((<- y (lists:seq 30 300))) (* 3.010299956639812 (math:log2 (/ y 30)))))
lfe> (set ordered (lists:foldl (lambda (x acc) 
                                 (lists:append acc `(#(,(+ 0.003 (element 1 (lists:last acc))) ,x)))) 
                               '(#(0 (0 0)))
                               msbs-lsbs))
lfe> (set indexed (maps:from_list ordered))
lfe> (set keys (maps:keys indexed))
lfe> (defun closest (x) (lutil-math:get-closest (lists:nth x select-voltages) keys))
lfe> (set select-msbs-lsbs (list-comp ((<- i (lists:seq 1 (length select-voltages))))
       (mref indexed (closest i))))

lfe> (list-comp ((<- msb-lsb select-msbs-lsbs)) (um:bank-select msb-lsb 0) (timer:sleep 500))

(defun bpm (bpm)
  (um:bank-select (lists:nth (- bpm 29) select-msbs-lsbs) 0))

@oubiwann oubiwann modified the milestones: 0.2.0, 0.3.0, 0.4.0 Nov 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Update for an existing feature
Projects
None yet
Development

No branches or pull requests

1 participant