An accurate BPM clock

Hi, what is the current best way to generate an accurate (sample accurate would be great) bpm clock to drive sequencers?

I seem to remember from the past that a midi clock input was the best way to set the rate of an LFO clock, around 2015, or working out the number of samples every from 4th ppq…and then pumping that value into the 0…64 dial in the midi/out/clock (see attached). Seems like a fair bit of fudging.

Is it possible to do this calculation accurately in fixed point world and translate that back to *soloti world (0…64, -64…64)?

edit- Ive been trying for the last couple of hours but I can’t quite reach the precision needed on the output. e.g.

float input_value = (60.f / 146.f) * 16.f; = 6.57534 // this is what i need

(int32_t)(input_value * (1 << 24) + 0.5f) = 110315944 // Adding 0.5 for rounding which gives 6.5625

are there any tricks? bit beyond me :dizzy_face:

set accurate bpm midi clock.axp (6.1 KB)

1 Like

Hi! I don’t know the mechanics surrounding midi clock and I haven’t analyzed the sss object, but if you multiply an integer by 64 you will always get a multiple of 64. You can’t get i.e. 27170 but 27136 or 27200. You need to find a more precise method to measure the samples.

2 Likes

Some tricky challenge here. First of all patatas is right, integers can have a lot of error after multiply or division (for example, so-called floor division).

Next, what comes to my mind is that you have the MIDI clock at 96ppq, which (for the sake of simplicity) is 384 pulses in a 4/4 measure. At, say, 200 BPM max this would be 200 / (60/384) = 1280 pulses per second. We’re measuring these pulses at k-rate (3000 per second) so there might already be some error introduced to the timing.

Next, the float to integer conversion … there might be a way.

What are these numbers based on? (60 seconds in a minute / 146 BPM) * 16 samples in one k-cycle?

Inside the Clock2Timing object, there is a comment saying:

//increment counting to get how many k-rate samples it takes till next trigger

Does this mean it measures a “sample” as a k-rate cycle of 3 khz, not an audio-rate sample at 48 khz?

Sorry I haven’t been very clear! (I’ve gotten into a nasty habit of posting late in the day, when my brain has turned to mush)

No the 16.f is 1/16th notes - that gives 6.57534 Hz - the period needed for a lfo/square running as a clock for example. There is also the other issue of what that translates to back in Axoloti world, where it needs to map to -64.0 to 64.0. Again potential for error and loss of precision.

This object is from 2015/16 I believe, not something that I made! I found it in the forum archives.

Indeed I have had those most success so far (with minimal drift) with midi sync, but I’m interested to explore the possibilities of an internal BPM accurate timing clock, without having to resort to an external midi clock (I’m like a dog with bone).

My naive mind thinks back to the venerable Atari ST’s rock-solid timing, which didn’t have an FPU, so relied on fixed point arithmetic - so in my naivety - I assume that it must be possible on the *oloti. Though, I do feel like I’ve waded into the highest-grade maths class :joy: which is ironic because maths was my poorest subject at school.

Oh if it is about extracting very precise timing from a MIDI clock signal, there is the dark and arcane way of the hal_lld_get_counter_value()! This will return you the number of cpu clock cycles since bootup (and it will wrap around at some point I guess?), anyway, you can uint32_t x = hal_lld_get_counter_value(); at some point then uint32_t time = hal_lld_get_counter_value() - x; to measure how many CPU cycles have passed. (one is 168 MHz)

But then again you will be constrained by k-rate if you work in k-rate code, and also midi only runs at 31500 baud. Maybe misusing some audio-rate code for getting a good hal_lld_get_counter_value() will get you better timing.

Ok this is a lot to take in but let’s figure it out step by step!

Another, quite different way is to say f€£k it and focus on the more likely bpm rates, like whole numbers and possibly half inbetween, like 100, 100.5,101 bpm, …

Or does it have to work with less stable clocks like tap tempo or trigger inputs?

Looks like the same method as deriving an accurate clock from the WebAudioContext in the browser!

Yeah I see what you mean. I guess this would be something that has to be handled all within the object, i.e. not in the patching environment. The object would need to output the clock based on an integer attribute (or input) because providing a bpm based on the range -64…64 would be fiddly

would that be in a hardcode lookup table/c-array?

No I hadn’t thought it would be that sophisticated - just a straightforward stable, accurate clock :slight_smile:

I have a clock object that can put out a trigger gate and a counter from a whole number bpm, with variable ppq and pulsewidth. (It can also midi sync and do tap tempo).

Here’s an example patch

bpm clock example.axp (18.2 KB)

3 Likes

Not sure exactly how accurate it is, but it’s accurate enough for rock and roll, which is good enough for me!

1 Like

nicceee will take a look. thanks!

dude that’s working really well - thanks for the share!

@MattilynMattroe would you mind briefly explaining what is going on pls?

so is this essentially using midi clock at it’s core, either internally generated, or from an external source?

It’s not using midi clock (though it can receive midi clock and sync to it). I can’t remember exactly how it does the maths (it’s been years since i made it) but it works out how many k rate cycles there are for one beat at the bpm and uses that as the basis for a clock. The kbeat outlets puts out the number of k rate cycles for 1 beat.

If a midi clock is recieved or a tempo is tapped, it will sync to that instead.

I’ve actually made some objects for use with the clock, such as lfos, too.

Glad it’s useful!

2 Likes