Has anyone got a formula for BPM ??

Started by wadmixfm, June 14, 2024, 18:38:54

Previous topic - Next topic


typical example :

bpm = 120

in theory this should be 2 beats per second

but how could we calculate it

image a bar with

16 1/4 notes like this

1 . . . 1 . . . 1 . . . 1 . . .

in a loop this would play smooth but setting the tempo in that loop so the bpm would be spot on or very close

btw this is pattern based so no 96 quarter notes etc..... its just on or off


Yes its really me :)



120bpm = 1 beat every 0.5 seconds.
Your issue (mine was) is likely trying to keep that when your frame rate is 60fps.  It feels like it oughta be divisible. But if the frame rate drifts even a millisecond, you'll end up drifting out of sync.  And when the floating precision gets involved, it descends in perfect precision.
Instead use a NextBeatAt=... variable.
When the first beat hits, NextBeatAt#=Float(Mills())+(60000.0/bpm#)
Do your loop, and as soon as Mills()>=NextBeatAt#, then do whatever, and NextBeatAt#=NextBeatAt#+(60000.0/bpm#)
Do not do what you're expecting and do NextBeatAt=Mills()+... because that's when things go out of sync.

(You might also want to divide bpm by 4 to account for 4 beats in a bar.  .. Depends on your usage.  I know I did this very very recently, but can't remember where it was!!!)
"Load, Next List"


ahhhhh i see i will have a play thanks for the info :)

Yes its really me :)


Every Beat is 1000ms and there is 60,000ms in a minute. so
you do 60,000/beat

For example 60,000/120beat will come 500ms


Thanks Hardcoal
in my loop i just did this
Import BRL.TimerDefault
Import sdl.sdlfreeaudio
Graphics 1024,768
Global b1:TChannel = AllocChannel()
Global s1:TSound =LoadSound("\Users\Wad\Desktop\01 Bd.ogg") ' put a ogg/wav sample here
Global grid$[5,1,20] ' in my program this is 5= pn , 1 how many tracks ,20 notes per track
Global tem
Global Pn
For Local t=1 To 17 Step 4 ' this just creates a default pattern 1 note on beat 1,5,9,13 These are the beats
Grid$[pn,0,t]="1" ' grid$ - variable - array pn Pattern - 0 track T= note loop
DrawText "Press ' S ' To Run Sequence " ,0,20
Until KeyHit(KEY_S)

Function playme()
For Local i = 0 To 15 ' this is 16 notes

DrawText "Tempo : "+tem,0,20
DrawText "press arrow left or right to change tempo",0,40
DrawText "Press Space to Stop",0,60
Delay 14700/tem
If grid$[1,0,i]="1" Then PlaySound s1,b1
If KeyHit(KEY_SPACE) Then End
If KeyHit(KEY_LEFT) Then If tem<=40 Then tem=40 ; playme() ;  Else tem=tem-1
If KeyHit(KEY_RIGHT) Then If tem>=240 Then tem=240 ; playme() ; Else tem=tem+1
Until KeyHit(KEY_ESCAPE)
End Function

 it works well :)

but if anyone out there can modify it to run better please have a look :)

i wrote this on the mac but it should be ok on any platform all you need to do is load a ogg file from your location :)


I know it looks old school but thats what i am :))


Yes its really me :)


This is not the best way to do it.

You should call a PlayMe() function that checks if the waiting time is over or not

Graphics 1024,768
Global s1:TSound = LoadSound("\Users\Wad\Desktop\01 Bd.ogg")
Global Grid:String[5,1,20]
Global tem:Int=125,  Pn:Int=1
Global Note:Int      ' runs from 0 to 15
Global NextBeat:Int  ' timestamp of the next note
Global Stop:Int=True ' sequence is running or not
For Local t:Int=1 To 17 Step 4
    Grid[pn,0,t] = "1"

    Flip 1
Until AppTerminate() Or  KeyHit(KEY_ESCAPE)

Function PlayCheck()
    If Stop=True Then Return
    If MilliSecs() < NextBeat Then Return

    Note = Note +1
    If Note>15
    NextBeat = NextBeat + 60000/tem
    If Grid[Pn,0,Note] = "1" Then PlaySound s1
End Function  

Function DoAllOtherThings()  
    If Stop=True
        DrawText "Press ' S ' To Run Sequence " ,0,20
        DrawText "Press Space to Stop",0,20
    DrawText "Tempo : "+tem,0,60
    DrawText "press arrow left or right to change tempo",0,80
    If KeyHit(KEY_SPACE) Then
        Stop = True
    ElseIf    KeyHit(KEY_S) Then
        Stop = False
        Note = 0
        NextBeat = MilliSecs()
    If KeyHit(KEY_LEFT)
        Tem = Max(Tem-1, 60)
    ElseIf KeyHit(KEY_RIGHT)
        Tem = Min(Tem+1, 240)      
End Function
...back from Egypt


i did say i was old school he he



Yes its really me :)


in your code i get this error

Expecting expression but encountered 'next'
Yes its really me :)


don't you need a for local loop for a next command ??

when i take out the next command it just says

found newline ??

this is sooooo not old school lol

Yes its really me :)


removed some bugs in post #6 ... sorry I'm not in front of my computer....

...back from Egypt


ahhhhh ok it works now BUT.......

when the bar is created its way to slow

its not 125bpm at 60000/tem

the grid$ string is 16 notes long not 4

i just created that so i could simulate 4 beats to the bar

so in theory

                1111111  <--- note info
1234567890123456  <--- note info

1     1     1     1        <--- Grid$ data

in between the 1's there are spaces these spaces are notes also for example


the 1 in the list is bass drum
2 snare drum
and so on

so when i run your code which now works it runs at have speed

now when i put in my value of 14700/tem it runs perfectly

i have timed it on a stop watch and its bang on 125 beats a minute

so my old school code is no different to yours only yours is more compact mine does exactly the same

because in my own code if i change the 14700/tem back to 60000 it runs at the same speed which is not what i want

bpm calculations are soooo mucked up

but i can iterate  that when i change the tempo to say 100 (with my 14700/tem) its bang on 100 beats a minute

very weird , its maybe something to do with the 60hz timing or something like that but it works.



Yes its really me :)


I am working on a classic commodore 64 drum machine called MicroRhythm

here are some screen shots


Yes its really me :)


here is a small metronome ive made..

it works well..

its part of my big projects but it can also be stand alone


Ah I understand now!

As I understand your explanations in post #11 your time base is not the QUARTER but the SIXTEENTH.

Your 16 position represent the sixteen 1/16-notes of one bar. So the calculation base is not 60000/tim but 15000/tim

Test my code with 15000/tim and you will get exact 125.0 bpm or any other bpm with an accuracy of 100%

Your (by experiments) discovered 14700 are because of the inaccuracy of a DELAY based model. Reason is, that the moment, when the DELAY returns it is often already 1msec too late. If you now add the note distance 15000/tim you will not compensate this error. So the only chance you have is to add the 15000/tim to the old timestamp you calculated!

Try this experiment:

This test runs 10 seconds and should count 1000 frames:

Graphics 800,600
Global Start:Int, Frames:Int, NextBeat:Int

Start  = MilliSecs()+10000
Frames = 0

DrawText "DELAY Test running...", 100,100
Frames = Frames +1
Delay 10
Flip 0
Until MilliSecs()>Start

Print "DELAY based couting:   " + Frames

Start     = MilliSecs()+10000
Frames    = 0
NextBeat  = MilliSecs()
DrawText "NEXTBEAT Test running...",100,100
If MilliSecs()>NextBeat
Frames   = Frames +1
NextBeat = Nextbeat +10
Flip 0
Until MilliSecs()>Start

Print "NextBeat based couting: " + Frames

But the DELAY based test only counts ca. 920 beats
...back from Egypt