## Has anyone got a formula for BPM ??

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

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

lee

Yes its really me

#### dawlane

Well you could try playing around with this.
https://muted.io/bpm-to-ms/

#### Jayenkai

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.
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!!!)

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

lee
Yes its really me

#### Hardcoal

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.TimerDefaultImport sdl.sdlfreeaudioGraphics 1024,768 SetAudioDriver("FreeAudio")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 temtem=125Global PnPn=1For Local t=1 To 17 Step 4 ' this just creates a default pattern 1 note on beat 1,5,9,13 These are the beatsGrid\$[pn,0,t]="1" ' grid\$ - variable - array pn Pattern - 0 track T= note loop Next DrawText "Press ' S ' To Run Sequence " ,0,20FlipRepeatUntil KeyHit(KEY_S)playme()Function playme()Repeat For Local i = 0 To 15 ' this is 16 notesClsDrawText "Tempo : "+tem,0,20DrawText "press arrow left or right to change tempo",0,40DrawText "Press Space to Stop",0,60FlipDelay 14700/temIf grid\$[1,0,i]="1" Then PlaySound s1,b1If KeyHit(KEY_SPACE) Then End If KeyHit(KEY_LEFT) Then If tem<=40 Then tem=40 ; playme() ;  Else tem=tem-1If KeyHit(KEY_RIGHT) Then If tem>=240 Then tem=240 ; playme() ; Else tem=tem+1Next 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

cheers

I know it looks old school but thats what i am

Lee

Yes its really me

#### Midimaster

#6
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

`SuperStrictGraphics 1024,768Global 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 15Global NextBeat:Int  ' timestamp of the next noteGlobal Stop:Int=True ' sequence is running or not For Local t:Int=1 To 17 Step 4    Grid[pn,0,t] = "1"NextRepeat    Cls    PlayCheck()    DoAllOtherThings()    Flip 1Until AppTerminate() Or  KeyHit(KEY_ESCAPE)Function PlayCheck()    If Stop=True Then Return    If MilliSecs() < NextBeat Then Return    Note = Note +1    If Note>15        Stop=True    EndIf           NextBeat = NextBeat + 60000/tem    If Grid[Pn,0,Note] = "1" Then PlaySound s1End Function   Function DoAllOtherThings()       If Stop=True        DrawText "Press ' S ' To Run Sequence " ,0,20    Else        DrawText "Press Space to Stop",0,20    EndIf           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()    EndIf    If KeyHit(KEY_LEFT)        Tem = Max(Tem-1, 60)    ElseIf KeyHit(KEY_RIGHT)        Tem = Min(Tem+1, 240)           EndIf    End Function `
...back from Egypt

i did say i was old school he he

cheers

midimaster

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

lee
Yes its really me

#### Midimaster

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

...back from Egypt

#11
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

1234567890123456

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.

cheers

lee

Yes its really me

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

here are some screen shots

lee.

Yes its really me

#### Hardcoal

here is a small metronome ive made..

it works well..

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

#### Midimaster

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:

`SuperStrictGraphics 800,600Global Start:Int, Frames:Int, NextBeat:IntStart  = MilliSecs()+10000Frames = 0Repeat Cls DrawText "DELAY Test running...", 100,100 Frames = Frames +1 Delay 10 Flip 0Until MilliSecs()>StartPrint "DELAY based couting:   " + FramesStart     = MilliSecs()+10000Frames    = 0NextBeat  = MilliSecs()Repeat Cls DrawText "NEXTBEAT Test running...",100,100 If MilliSecs()>NextBeat Frames   = Frames +1 NextBeat = Nextbeat +10 EndIf Flip 0Until MilliSecs()>StartPrint "NextBeat based couting: " + Frames`
But the DELAY based test only counts ca. 920 beats
...back from Egypt