basic midi sequencer

Just starting out? Need help? Post your questions and find answers here.
Olby
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Jan 12, 2009 10:33 am
Contact:

basic midi sequencer

Post by Olby »

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
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
User avatar
bobobo
Enthusiast
Enthusiast
Posts: 206
Joined: Mon Jun 09, 2003 8:30 am

Post by bobobo »

사십 둘 .
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Post by eriansa »

You can use Multimedia-Timers (mmsystem) or the Midistream api's.
Olby
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Jan 12, 2009 10:33 am
Contact:

Post by Olby »

thank you. I will look into these.
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
User avatar
bobobo
Enthusiast
Enthusiast
Posts: 206
Joined: Mon Jun 09, 2003 8:30 am

Post by bobobo »

사십 둘 .
Olby
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Jan 12, 2009 10:33 am
Contact:

Post by Olby »

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
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

With threads you can achieve acceptable performance, and do other tasks smultaneously.
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
Cheers
Olby
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Jan 12, 2009 10:33 am
Contact:

Post by Olby »

@einander:

Thanks that was very useful peace of code. I did almost everything the same, I just didn't know about the the thread priority command. Man, PureBasic is extremely powerful language... Gotta study it better.. :wink:
Intel Core i7 Quad 2.3 Ghz, 8GB RAM, GeForce GT 630M 2GB, Windows 10 (x64)
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

@ Olby : You're welcome
This code can help as a starter, but with intensive process activity, sometimes falls behind.
Maybe using Mutex the timing can be improved.
User avatar
bobobo
Enthusiast
Enthusiast
Posts: 206
Joined: Mon Jun 09, 2003 8:30 am

Post by bobobo »

don't use delay when you need it accurate

http://www.codeproject.com/KB/system/cp ... play=Print
(take a look at the code)
사십 둘 .
Post Reply