hi,
I'm coding a basic midi sequencer and came toa full stop when I started to think that I cannot implement the ticks (midi pulses) using PureBasics ElapsedMilliseconds().
What I want to do is to have a sequencer with resolution of 96 ticks/pulses per beat. This means (as far as I understand the whole math behind it) that each beat goes through 96 ticks before moving on to the next beat. If thats so how would I make a sequencer that can perfectly play those 96 ticks even at high bpm rates. I tried using the timer but it gave me 15 to 16 milliseconds of time between each call but to play a 200 BPM beat you will need around 3 msec between each tick and this is not achievable using this timer.
This leads me to a conclusion that I am doing it completely wrong. So I wanted to ask you guys which is the best solution to create such perfect timing programs in PB. I know some of the sequencer even use four times and more the resolution than 96. How do they do it? Of course I could skip the whole tick part and just use delay for the appropriate note length but I also would like to implement midi note recording which again means that I will have to use ticks anyway.
thank you,
olby
basic midi sequencer
basic midi sequencer
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
do anyone know how to prevent my sequencer from slowing down when computer is doing something in the background? it will start playing back slower when I for example switch back to purebasic window and click a menu. I guess my computer can handle those tasks simultaneously.
sequencer update is handled in a separate thread so none of the other code gets into its way. it is something to do with the hi performance timers. currently I just simply check if the specific time since the last tick is passed (timer => tick)and if yes move on to the next tick. i guess this is incorrect way of handling this. are there any better solutions ?
thank you once again,
olby
sequencer update is handled in a separate thread so none of the other code gets into its way. it is something to do with the hi performance timers. currently I just simply check if the specific time since the last tick is passed (timer => tick)and if yes move on to the next tick. i guess this is incorrect way of handling this. are there any better solutions ?
thank you once again,
olby
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
With threads you can achieve acceptable performance, and do other tasks smultaneously.
May be you can start with this:
Cheers
May be you can start with this:
Code: Select all
#NoteOn = $90;
#MSEC=60000.0 ; = millisecs in 1 minute
Global _hMIDIout
Procedure midiinit()
For nDev=-1 To MidiOutGetNumDevs_()-1
If MidiOutGetDevCaps_(nDev,@midi.MIDIOUTCAPS,SizeOf(MIDIOUTCAPS))=0
If midi\wVoices>0
MidiPort=nDev
EndIf
EndIf
Next
MidiOutOpen_(@_hMIDIout,MidiPort,0,0,0)
EndProcedure
Macro MMK ; mouse key state
Abs(GetAsyncKeyState_(#VK_LBUTTON) +GetAsyncKeyState_(#VK_RBUTTON)*2+GetAsyncKeyState_(#VK_MBUTTON)*3)/$8000
EndMacro
Macro PlayMIDINote(Chan, Note, Vol=100)
MidiOutShortMsg_(_hMIDIout, #NoteOn | Chan | Note << 8 | Vol << 16) ;
EndMacro
Macro BPM_Msec(n) ; convert MilliSecs to Beats per Minute and vice versa
#MSEC/n
EndMacro
Structure Metronome
BPM.l
Msecs.l
Sound.B
Vol.B
count.l
EndStructure
Procedure ThreadMetron(*Param.Metronome)
With *Param
\Sound=35 ; 35=acoustic bass drum
Repeat
PlayMIDINote(9,\Sound,100) ; 9=perc MIDI channel
; \count+1 ; for beat count
Delay(\Msecs)
ForEver
EndWith
EndProcedure
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
If OpenWindow(0, 100, 100,400,80 ,"Test Metronome", #WS_OVERLAPPEDWINDOW|#PB_Window_ScreenCentered)
StickyWindow(0,1)
_TB=TrackBarGadget(#PB_Any,40,10,300,30,50,500)
_InfoTB=TextGadget(#PB_Any,GadgetX(_TB),40,300,20,"",#PB_Text_Border)
SetGadgetState(_TB,100)
SetGadgetText(_InfoTB,"Beats per minute : "+Str(GetGadgetState(_TB)))
BPM.Metronome
BPM\Msecs=BPM_Msec(GetGadgetState(_TB))
midiinit()
Thread1=CreateThread(@ThreadMetron(),@BPM)
ThreadPriority(Thread1,31)
Repeat
If GetAsyncKeyState_(27) : End : EndIf
Ev=WaitWindowEvent()
Select Ev
Case #PB_Event_Gadget
Select EventGadget()
Case _TB
BPM\BPM=GetGadgetState(_TB)
BPM\Msecs=BPM_Msec(BPM\BPM)
SetGadgetText(_InfoTB,"Beats per minute : "+Str(BPM\BPM))
EndSelect
EndSelect
Until Ev=#WM_CLOSE
End
EndIf
don't use delay when you need it accurate
http://www.codeproject.com/KB/system/cp ... play=Print
(take a look at the code)
http://www.codeproject.com/KB/system/cp ... play=Print
(take a look at the code)
사십 둘 .