Receiving MIDI System Exclusive Messages

Just starting out? Need help? Post your questions and find answers here.
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Receiving MIDI System Exclusive Messages

Post by Wolfram »

GM is alway a limitation. If you want to do more or you want to be more flexible use the SC an normal midi dive.
You can address every sound by a bank change command followed by a program change.
If you want to assign a CC to a special parameter you must use a SysEx command, but this is not so complicated.

you can give me your code to get more overview of you idea.
macOS Catalina 10.15.7
MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

Wolfram wrote:GM is alway a limitation. If you want to do more or you want to be more flexible use the SC an normal midi dive.
You can address every sound by a bank change command followed by a program change.
If you want to assign a CC to a special parameter you must use a SysEx command, but this is not so complicated.

you can give me your code to get more overview of you idea.
Sorry for the delay to answer, but I had problems with the pc.
My code is very messy.
Here is a summary of what I have. But I don't see. And so, the layout must be crumbling!
Remembering that at any time, "F1" key changes the device, and "enter" plays the phrase.

Code: Select all

; --------------------
Define moc.MIDIOUTCAPS
Global MHI.MIDIHDR
Define hmo.i

Procedure PitchBend(channel, n)
  
Shared hmo
  If n=>16 :n0$="":Else:n0$="0":EndIf
    
    midiOutShortMsg_(hmo, Val("$00"+n0$+Hex(n)+n0$+Hex(n)+"E"+Hex(channel)))
  EndProcedure

Procedure ProgramChange(channel, n)
Shared hmo
  If n=>16 :n0$="":Else:n0$="0":EndIf
    
    midiOutShortMsg_(hmo, Val("$0000"+n0$+Hex(n)+"C"+Hex(channel)))
  EndProcedure

Procedure controlchange(channel, n, v)
Shared hmo
  If v=>16 :v0$="":Else:v0$="0":EndIf
If n=>16 :n0$="":Else:n0$="0":EndIf
    
    midiOutShortMsg_(hmo, Val("$00"+ v0$+Hex(v)+n0$+Hex(n)+"B"+Hex(channel)))
  EndProcedure
  
Procedure playnote(channel, n, v)
  Shared hmo
  If v>9 :v0$="":Else:v0$="0":EndIf
  If n>9 :n0$="":Else:n0$="0":EndIf
midiOutShortMsg_(hmo, Val("$00"+ v0$+Hex(v)+n0$+Hex(n)+"9"+Hex(channel)))
  EndProcedure
  
  Procedure stopnote(channel, n)
  Shared hmo
  If n>9 :n0$="":Else:n0$="0":EndIf
midiOutShortMsg_(hmo, Val("$0000"+n0$+Hex(n)+"9"+Hex(channel)))
      EndProcedure
      
      Gosub dispositivo
If Result = #MMSYSERR_NOERROR
  OpenWindow(0, 0, 0, 300, 300, "Playing a simple frase") 
tg2=TextGadget(#PB_Any, 10, 10, 150, 20, "Instrument number:")
sg1=SpinGadget(#PB_Any, 200, 10, 40, 20, 0, 127, #PB_Spin_Numeric)
SetActiveGadget(sg1)
SetGadgetText(sg1, "4")
SetActiveGadget(sg1)
tg3=TextGadget(#PB_Any, 10, 50, 150, 20, "Balance:")
sg2=SpinGadget(#PB_Any, 200, 50, 40, 20, 0, 127, #PB_Spin_Numeric)
SetGadgetText(sg2, "64")

tg4=TextGadget(#PB_Any, 10, 100, 100, 20, "Sysex:")
sg3=StringGadget(#PB_Any, 120, 100, 150, 20, "")

tg5=CheckBoxGadget(#PB_Any, 10, 150, 100, 20, "Pitch Bend:")

  Gosub atalho
  Repeat
    Select WaitWindowEvent()
      Case 13116
        Break
      Case #PB_Event_Gadget
        Select EventGadget()
          Case sg1
            SetGadgetText(sg1, Str(GetGadgetState(sg1)))
            
            Case sg2
            SetGadgetText(sg2, Str(GetGadgetState(sg2)))
        
        EndSelect
        
      Case #PB_Event_Timer
        Select EventTimer()
          Case 1
            Gosub stop
          Case 2
            p=p+1
            If p>127
              p=127
            RemoveWindowTimer(0, 2)  
            EndIf
            PitchBend(channel, p)
            EndSelect
      Case #PB_Event_Menu
        Select  EventMenu()
            Case 1
              Gosub play
            Case 2
              Gosub dispositivo
          EndSelect
    EndSelect
  ForEver
  EndIf
End

stop:
For r=50 To 73
  stopnote(channel, r)
Next
RemoveWindowTimer(0, 1)

Return
play:
controlchange(channel, 10, Val(GetGadgetText(sg2)))
programchange(0, Val(GetGadgetText(sg1)))
Gosub stop
AddWindowTimer(0, 1, 2000)
If GetGadgetState(tg5)=1
  AddWindowTimer(0, 2, 10)
  p =64
pitchbend(channel, 64)
  EndIf

For r= 50 To 71 Step 3
    playnote(0, r, 70)
    Delay(30)
    Next
Return

atalho:
AddKeyboardShortcut(0, #PB_Shortcut_Return, 1)
AddKeyboardShortcut(0, #PB_Shortcut_F1, 2)
Return

dispositivo:
 midiOutClose_(hmo)
OpenWindow(1, 0, 0, 300, 400, "Select a Midi Port")
iNumDev = midiOutGetNumDevs_()
tg1=TextGadget(#PB_Any, 10, 10, 280, 20, Str(iNumDev) + " MIDI out devices.")
lg1=ListViewGadget(#PB_Any, 10, 40, 280, 330)
For around = 0 To iNumDev - 1
  midiOutGetDevCaps_(around, moc, SizeOf(MIDIOUTCAPS))
  ;Debug " " + Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN)
aa$=Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN)
  AddGadgetItem(lg1, around, aa$)
Next
SetActiveGadget(lg1)
SetGadgetState(lg1, 0)
AddKeyboardShortcut(1, #PB_Shortcut_Return, 1)
Repeat
  w=WaitWindowEvent()
  Select w
    Case 13116
      End
    Case #PB_Event_Menu
      k=GetGadgetState(lg1)
      If EventMenu()=1 And k>-1
        Break
      EndIf
  EndSelect
ForEver

CloseWindow(1)

result = midiOutOpen_(@hmo, k, #Null, #Null, #CALLBACK_NULL)

Return
; --------------------
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Receiving MIDI System Exclusive Messages

Post by infratec »

Hi,

I allowed me to restructure your code.
I eliminate the global and shared variables.
There should only one eventloop inside the code, else you miss events.
Also Gosub is a bit outdated and makes it a bit more difficult to follow the code.

I hope you can follow my code lines:

Code: Select all

EnableExplicit

;-Enumerations
Enumeration Windows
  #MainWindow
  #DeviceWindow
EndEnumeration

Enumeration Gadgets
  #tg1
  #tg2
  #tg3
  #tg4
  #tg5
  #sg1
  #sg2
  #sg3
  #lg1
EndEnumeration

Enumeration Shortcuts
  #ReturnShotcut
  #F1Shortcut
EndEnumeration

Enumeration Timers
  #Timer1
  #Timer2
EndEnumeration


;-Procedures
Procedure PitchBend(hmo.i, channel.i, n.i)
  
  Protected n0$
  
  If n => 16
    n0$= ""
  Else
    n0$="0"
  EndIf
  
  midiOutShortMsg_(hmo, Val("$00" + n0$ + Hex(n) + n0$ + Hex(n) + "E" + Hex(channel)))
EndProcedure


Procedure ProgramChange(hmo.i, channel.i, n.i)
  
  Protected n0$
  
  If n=>16
    n0$ = ""
  Else
    n0$="0"
  EndIf
  
  midiOutShortMsg_(hmo, Val("$0000" + n0$ + Hex(n) + "C" + Hex(channel)))
EndProcedure


Procedure controlchange(hmo.i, channel.i, n.i, v.i)
  
  Protected v0$, n0$
  
  If v => 16
    v0$ = ""
  Else
    v0$ = "0"
  EndIf
  
  If n => 16
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
  
  midiOutShortMsg_(hmo, Val("$00" + v0$ + Hex(v) + n0$ + Hex(n) + "B" + Hex(channel)))
EndProcedure



Procedure playnote(hmo.i, channel.i, n.i, v.i)
  
  Protected v0$, n0$
  
  If v > 9
    v0$ = ""
  Else
    v0$ = "0"
  EndIf
  
  If n > 9
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
  
  midiOutShortMsg_(hmo, Val("$00" + v0$ + Hex(v) + n0$ + Hex(n) + "9" + Hex(channel)))
EndProcedure


Procedure stopnote(hmo.i, channel.i, n.i)
  
  Protected n0$
  
  If n > 9
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
  
  midiOutShortMsg_(hmo, Val("$0000" + n0$ + Hex(n) + "9" + Hex(channel)))
EndProcedure



Procedure stop(hmo.i, channel.i)
  
  Protected r.i
  
  
  For r = 50 To 73
    stopnote(hmo, channel, r)
  Next
  RemoveWindowTimer(#MainWindow, #Timer1)
EndProcedure


Procedure play(hmo.i, channel.i)
  
  Protected.i r, p
  
  
  controlchange(hmo, channel, 10, Val(GetGadgetText(#sg2)))
  programchange(hmo, channel, Val(GetGadgetText(#sg1)))
  stop(hmo, channel)
  AddWindowTimer(#MainWindow, #Timer1, 2000)
  If GetGadgetState(#tg5) = 1
    AddWindowTimer(#MainWindow, #Timer2, 10)
    p = 64
    pitchbend(hmo, channel, 64)
  EndIf
  
  For r = 50 To 71 Step 3
    playnote(hmo, channel, r, 70)
    Delay(30)
  Next
EndProcedure


Procedure dispositivo(hmo.i)
  
  Protected.i iNumDev, around, w, k, Result
  Protected aa$
  Protected moc.MIDIOUTCAPS
  
  midiOutClose_(hmo)
  
  OpenWindow(#DeviceWindow, 0, 0, 300, 400, "Select a Midi Port")
  
  iNumDev = midiOutGetNumDevs_()
  TextGadget(#tg1, 10, 10, 280, 20, Str(iNumDev) + " MIDI out devices.")
  ListViewGadget(#lg1, 10, 40, 280, 330)
  For around = 0 To iNumDev - 1
    midiOutGetDevCaps_(around, moc, SizeOf(MIDIOUTCAPS))
    ;Debug " " + Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN)
    aa$ = Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN)
    AddGadgetItem(#lg1, around, aa$)
  Next
  SetActiveGadget(#lg1)
  SetGadgetState(#lg1, 0)
  AddKeyboardShortcut(#DeviceWindow, #PB_Shortcut_Return, #ReturnShotcut)
  
EndProcedure




;-Main
Define.i Result, p, Event, DeviceId, hmo, channel


OpenWindow(#MainWindow, 0, 0, 300, 300, "Playing a simple frase")
TextGadget(#tg2, 10, 10, 150, 20, "Instrument number:")
SpinGadget(#sg1, 200, 10, 40, 20, 0, 127, #PB_Spin_Numeric)
SetActiveGadget(#sg1)
SetGadgetText(#sg1, "4")
SetActiveGadget(#sg1)
TextGadget(#tg3, 10, 50, 150, 20, "Balance:")
SpinGadget(#sg2, 200, 50, 40, 20, 0, 127, #PB_Spin_Numeric)
SetGadgetText(#sg2, "64")

TextGadget(#tg4, 10, 100, 100, 20, "Sysex:")
StringGadget(#sg3, 120, 100, 150, 20, "")

CheckBoxGadget(#tg5, 10, 150, 100, 20, "Pitch Bend:")

AddKeyboardShortcut(#MainWindow, #PB_Shortcut_Return, #ReturnShotcut)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_F1, #F1Shortcut)

PostEvent(#PB_Event_Menu, #MainWindow, #F1Shortcut)

;-EventLoop
Repeat
  Event = WaitWindowEvent()
  
  Select EventWindow()
    ;-MainWindowEvents
    Case #MainWindow
      
      Select Event
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #sg1
              SetGadgetText(#sg1, Str(GetGadgetState(#sg1)))
              
            Case #sg2
              SetGadgetText(#sg2, Str(GetGadgetState(#sg2)))
              
          EndSelect
          
        Case #PB_Event_Timer
          Select EventTimer()
            Case 1
              stop(hmo, channel)
            Case 2
              p = p + 1
              If p > 127
                p = 127
                RemoveWindowTimer(#MainWindow, #Timer2)
              EndIf
              PitchBend(hmo, channel, p)
          EndSelect
        Case #PB_Event_Menu
          Select EventMenu()
            Case #ReturnShotcut
              play(hmo, channel)
            Case #F1Shortcut
              DisableWindow(#MainWindow, #True)
              dispositivo(hmo)
          EndSelect
      EndSelect
      
    ;-DeviceWindowEvents
    Case #DeviceWindow
      Select Event
        Case #PB_Event_CloseWindow
          CloseWindow(#DeviceWindow)
          DisableWindow(#MainWindow, #False)
          SetActiveWindow(#MainWindow)
          
        Case #PB_Event_Menu
          DeviceId = GetGadgetState(#lg1)
          If EventMenu() = #ReturnShotcut And DeviceId > -1
            result = midiOutOpen_(@hmo, DeviceId, #Null, #Null, #CALLBACK_NULL)
            If Result <> #MMSYSERR_NOERROR
            EndIf
            PostEvent(#PB_Event_CloseWindow, #DeviceWindow, 0)
          EndIf
      EndSelect
      
  EndSelect
  
ForEver
MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

infratec wrote:Hi,

I allowed me to restructure your code.
I eliminate the global and shared variables.
There should only one eventloop inside the code, else you miss events.
Also Gosub is a bit outdated and makes it a bit more difficult to follow the code.

I hope you can follow my code lines:
Although the code was better fixed as above, it was not working properly.
The sound was without pause after 2 seconds.
The pitch was not working.
With the "pitch" option checked, the sound only lasted a few seconds.
I tried not to change much of the current structure, but I made some corrections.
Now it works just like the old code, but not confusing like I did the first time.
Additions and changes are commented.

Code: Select all

EnableExplicit
Global p  ;I added this line
;-Enumerations
Enumeration Windows
  #MainWindow
  #DeviceWindow
EndEnumeration

Enumeration Gadgets
  #tg1
  #tg2
  #tg3
  #tg4
  #tg5
  #sg1
  #sg2
  #sg3
  #lg1
EndEnumeration

Enumeration Shortcuts
  #ReturnShotcut
  #F1Shortcut
EndEnumeration

Enumeration Timers
  #Timer1
  #Timer2
EndEnumeration


;-Procedures

Procedure PitchBend(hmo.i, channel.i, n.i)
   Protected n0$
 
  If n => 16
    n0$= ""
  Else
    n0$="0"
  EndIf
 
  midiOutShortMsg_(hmo, Val("$00" + n0$ + Hex(n) + n0$ + Hex(n) + "E" + Hex(channel)))
EndProcedure


Procedure ProgramChange(hmo.i, channel.i, n.i)
 
  Protected n0$
 
  If n=>16
    n0$ = ""
  Else
    n0$="0"
  EndIf
 
  midiOutShortMsg_(hmo, Val("$0000" + n0$ + Hex(n) + "C" + Hex(channel)))
EndProcedure


Procedure controlchange(hmo.i, channel.i, n.i, v.i)
 
  Protected v0$, n0$
 
  If v => 16
    v0$ = ""
  Else
    v0$ = "0"
  EndIf
 
  If n => 16
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
 
  midiOutShortMsg_(hmo, Val("$00" + v0$ + Hex(v) + n0$ + Hex(n) + "B" + Hex(channel)))
EndProcedure



Procedure playnote(hmo.i, channel.i, n.i, v.i)
 
  Protected v0$, n0$
 
  If v > 15
    v0$ = ""
  Else
    v0$ = "0"
  EndIf
 
  If n > 15
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
 
  midiOutShortMsg_(hmo, Val("$00" + v0$ + Hex(v) + n0$ + Hex(n) + "9" + Hex(channel)))
EndProcedure

Procedure stopnote(hmo.i, channel.i, n.i)
  
  Protected n0$
 
  If n > 15
    n0$ = ""
  Else
    n0$ = "0"
  EndIf
 
  midiOutShortMsg_(hmo, Val("$0000" + n0$ + Hex(n) + "9" + Hex(channel)))
EndProcedure



Procedure stop(hmo.i, channel.i)
 
  Protected r.i
 
 
  For r = 50 To 73
    stopnote(hmo, channel, r)
  Next
  RemoveWindowTimer(#MainWindow, #Timer1)
EndProcedure


Procedure play(hmo.i, channel.i)
 
  Protected.i r
 
  controlchange(hmo, channel, 10, Val(GetGadgetText(#sg2)))
  programchange(hmo, channel, Val(GetGadgetText(#sg1)))
  stop(hmo, channel)
  AddWindowTimer(#MainWindow, #Timer1, 2000)
  If GetGadgetState(#tg5) = 1
    AddWindowTimer(#MainWindow, #Timer2, 10)
  EndIf
  p=64
 pitchbend(hmo, channel, 64)
  For r = 50 To 71 Step 3
    playnote(hmo, channel, r, 70)
    Delay(30)
  Next
EndProcedure


Procedure dispositivo(hmo.i)
 
  Protected.i iNumDev, around, w, k, Result
  Protected aa$
  Protected moc.MIDIOUTCAPS
 
  midiOutClose_(hmo)
 
  OpenWindow(#DeviceWindow, 0, 0, 300, 400, "Select a Midi Port")
 
  iNumDev = midiOutGetNumDevs_()
  TextGadget(#tg1, 10, 10, 280, 20, Str(iNumDev) + " MIDI out devices.")
  ListViewGadget(#lg1, 10, 40, 280, 330)
  For around = 0 To iNumDev - 1
    midiOutGetDevCaps_(around, moc, SizeOf(MIDIOUTCAPS))
    
AddGadgetItem(#lg1, around, Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN))
  Next
  SetActiveGadget(#lg1)
  SetGadgetState(#lg1, 0)
  AddKeyboardShortcut(#DeviceWindow, #PB_Shortcut_Return, #ReturnShotcut)
 
EndProcedure




;-Main
Define.i Result, Event, DeviceId, hmo, channel  ;I removed the "p" variable from here


OpenWindow(#MainWindow, 0, 0, 300, 300, "Playing a simple frase")
TextGadget(#tg2, 10, 10, 150, 20, "Instrument number:")
SpinGadget(#sg1, 200, 10, 40, 20, 0, 127, #PB_Spin_Numeric)
SetActiveGadget(#sg1)
SetGadgetText(#sg1, "4")
SetActiveGadget(#sg1)
TextGadget(#tg3, 10, 50, 150, 20, "Balance:")
SpinGadget(#sg2, 200, 50, 40, 20, 0, 127, #PB_Spin_Numeric)
SetGadgetText(#sg2, "64")

TextGadget(#tg4, 10, 100, 100, 20, "Sysex:")
StringGadget(#sg3, 120, 100, 150, 20, "")

CheckBoxGadget(#tg5, 10, 150, 100, 20, "Pitch Bend:")

AddKeyboardShortcut(#MainWindow, #PB_Shortcut_Return, #ReturnShotcut)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_F1, #F1Shortcut)

PostEvent(#PB_Event_Menu, #MainWindow, #F1Shortcut)

;-EventLoop
Repeat
  Event = WaitWindowEvent()
 
  Select EventWindow()
    ;-MainWindowEvents
    Case #MainWindow
     
      Select Event
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #sg1
              SetGadgetText(#sg1, Str(GetGadgetState(#sg1)))
             
            Case #sg2
              SetGadgetText(#sg2, Str(GetGadgetState(#sg2)))
             
          EndSelect
         
        Case #PB_Event_Timer
          Select EventTimer()
            Case #Timer1  ;I changed here
              stop(hmo, channel)
            Case #timer2  ;I changed here too!
              p = p + 1
              If p > 127
                p = 127
                RemoveWindowTimer(#MainWindow, #Timer2)
              EndIf
              PitchBend(hmo, channel, p)
          EndSelect
        Case #PB_Event_Menu
          Select EventMenu()
            Case #ReturnShotcut
              play(hmo, channel)
            Case #F1Shortcut
              DisableWindow(#MainWindow, #True)
              dispositivo(hmo)
          EndSelect
      EndSelect
     
    ;-DeviceWindowEvents
    Case #DeviceWindow
      Select Event
        Case #PB_Event_CloseWindow
          CloseWindow(#DeviceWindow)
          DisableWindow(#MainWindow, #False)
          SetActiveWindow(#MainWindow)
         
        Case #PB_Event_Menu
          DeviceId = GetGadgetState(#lg1)
          If EventMenu() = #ReturnShotcut And DeviceId > -1
            result = midiOutOpen_(@hmo, DeviceId, #Null, #Null, #CALLBACK_NULL)
            ;two old lines removed from here
            PostEvent(#PB_Event_CloseWindow, #DeviceWindow, 0)
          EndIf
      EndSelect
     
  EndSelect
 
ForEver


MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

If you were able to understand the code, and you do, I would like to know how it is possible to make sysex work in this code, such as controlchange, pitchbender, programchange, etc.
If this is really possible !!!
Grateful for what you've done so far.
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Receiving MIDI System Exclusive Messages

Post by Wolfram »

MarcosPC wrote:If you were able to understand the code, and you do, I would like to know how it is possible to make sysex work in this code, such as controlchange, pitchbender, programchange, etc.
If this is really possible !!!
Grateful for what you've done so far.
For sysex you need midiOutLongMsg
so it should look like this.

Code: Select all

sizeOfSysExMessage.a = 8
Dim sysexMessage.a(sizeOfSysExMessage -1)
sysexMessage(0) = $F0
sysexMessage(1) = xx
sysexMessage(2) = xx
sysexMessage(3) = xx
sysexMessage(4) = xx
sysexMessage(5) = xx
sysexMessage(6) = xx
sysexMessage(7) = $F7
midiOutLongMsg_(hmo, @sysexMessage(), sizeOfSysExMessage)
macOS Catalina 10.15.7
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Receiving MIDI System Exclusive Messages

Post by infratec »

SysEx for the Mastervolume (max 16383)

Set it to 10000 to get a quick difference.

Code: Select all

EnableExplicit

;-Enumerations
Enumeration Windows
  #MainWindow
  #DeviceWindow
EndEnumeration

Enumeration Gadgets
  #tg1
  #tg2
  #tg3
  #tg4
  #tg5
  #sg1
  #sg2
  #sg3
  #lg1
EndEnumeration

Enumeration Shortcuts
  #ReturnShotcut
  #F1Shortcut
EndEnumeration

Enumeration Timers
  #Timer1
  #Timer2
EndEnumeration


;-Procedures

Procedure PitchBend(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(n & $7F), 2, "0") + RSet(Hex(n >> 7), 2, "0") + "E" + Hex(channel)))  ; E = 1110 PITCH BEND
EndProcedure


Procedure ProgramChange(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$0000" + RSet(Hex(n), 2, "0") + "C" + Hex(channel))) ; C = 1100 PROGRAMM CHANGE
EndProcedure


Procedure controlchange(hmo.i, channel.i, n.i, v.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(v), 2, "0") + RSet(Hex(n), 2, "0") + "B" + Hex(channel)))  ; B = 1011 CONTROLLER
EndProcedure


Procedure playnote(hmo.i, channel.i, n.i, v.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(v), 2, "0") + RSet(Hex(n), 2, "0") + "9" + Hex(channel)))  ; 9 = 1001 NOTE ON
EndProcedure


Procedure stopnote(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$0000" + RSet(Hex(n), 2, "0") + "8" + Hex(channel))) ; 8 = 1000 NOTE OFF
EndProcedure


Procedure SysEXVolume(hmo.i, Volume.i)
 
  Protected *SysExBuffer
  Protected MIDIHeader.MIDIHDR
 
 
  If Volume > $3FFF
    Volume = $3FFF
  EndIf
 
  *SysExBuffer = AllocateMemory(8)
  If *SysExBuffer
   
    PokeA(*SysExBuffer + 0, $F0)  ; SysEx
    PokeA(*SysExBuffer + 1, $7F)  ; Realtime
    PokeA(*SysExBuffer + 2, $7F)  ; Channel (disregard)
    PokeA(*SysExBuffer + 3, $04)  ; SubID (Device Control)
    PokeA(*SysExBuffer + 4, $01)  ; SubID2 (Master Volume)
    PokeA(*SysExBuffer + 5, Volume & $7F)  ; Volume lower 7 bits
    PokeA(*SysExBuffer + 6, Volume >> 7)  ; Volume upper 7 bits
    PokeA(*SysExBuffer + 7, $F7)  ; SysEx End
   
    ;ShowMemoryViewer(*SysExBuffer, MemorySize(*SysExBuffer))
   
    MIDIHeader\lpData = *SysExBuffer
    MIDIHeader\dwBufferLength = MemorySize(*SysExBuffer)
    MIDIHeader\dwFlags = 0
   
    midiOutPrepareHeader_(hmo, @MIDIHeader, SizeOf(MIDIHDR))
   
    ;CopyMemory(*SysExBuffer, MIDIHeader\lpData, MemorySize(*SysExBuffer))
   
    midiOutLongMsg_(hmo, @MIDIheader, SizeOf(MIDIHDR))
   
    FreeMemory(*SysExBuffer)
  EndIf
 
EndProcedure


Procedure stop(hmo.i, channel.i)
 
  Protected r.i
 
 
  For r = 50 To 73
    stopnote(hmo, channel, r)
  Next
  RemoveWindowTimer(#MainWindow, #Timer1)
EndProcedure


Procedure play(hmo.i, channel.i)
 
  Protected.i r
  
  
  controlchange(hmo, channel, 10, GetGadgetState(#sg2)) ; 10 = pan
  programchange(hmo, channel, Val(GetGadgetText(#sg1)))
  stop(hmo, channel)
  AddWindowTimer(#MainWindow, #Timer1, 2000)
  If GetGadgetState(#tg5) = 1
    AddWindowTimer(#MainWindow, #Timer2, 5)
  EndIf
  pitchbend(hmo, channel, $2000)
  For r = 50 To 71 Step 3
    playnote(hmo, channel, r, 70)
    Delay(30)
  Next
EndProcedure


Procedure dispositivo(hmo.i)
 
  Protected.i iNumDev, around, w, k, Result
  Protected aa$
  Protected moc.MIDIOUTCAPS
 
  midiOutClose_(hmo)
 
  OpenWindow(#DeviceWindow, 0, 0, 300, 400, "Select a Midi Port")
 
  iNumDev = midiOutGetNumDevs_()
  TextGadget(#tg1, 10, 10, 280, 20, Str(iNumDev) + " MIDI out devices.")
  ListViewGadget(#lg1, 10, 40, 280, 330)
  For around = 0 To iNumDev - 1
    midiOutGetDevCaps_(around, moc, SizeOf(MIDIOUTCAPS))
   
AddGadgetItem(#lg1, around, Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN))
  Next
  SetActiveGadget(#lg1)
  SetGadgetState(#lg1, 0)
  AddKeyboardShortcut(#DeviceWindow, #PB_Shortcut_Return, #ReturnShotcut)
 
EndProcedure




;-Main
Define.i Result, Event, DeviceId, hmo, channel, p


OpenWindow(#MainWindow, 0, 0, 300, 300, "Playing a simple frase")
TextGadget(#tg2, 10, 10, 150, 20, "Instrument number:")
SpinGadget(#sg1, 200, 10, 40, 20, 0, 127, #PB_Spin_Numeric)
SetActiveGadget(#sg1)
SetGadgetText(#sg1, "4")
SetActiveGadget(#sg1)
TextGadget(#tg3, 10, 50, 150, 20, "Balance:")
TrackBarGadget(#sg2, 120, 50, 150, 20, 0, 128)
SetGadgetState(#sg2, 64)

TextGadget(#tg4, 10, 100, 100, 20, "SysexVolume:")
SpinGadget(#sg3, 120, 100, 150, 20, 0, 16383, #PB_Spin_Numeric)
SetGadgetText(#sg3, "16383")

CheckBoxGadget(#tg5, 10, 150, 100, 20, "Pitch Bend:")

AddKeyboardShortcut(#MainWindow, #PB_Shortcut_Return, #ReturnShotcut)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_F1, #F1Shortcut)

PostEvent(#PB_Event_Menu, #MainWindow, #F1Shortcut)

;-EventLoop
Repeat
  Event = WaitWindowEvent()
 
  Select EventWindow()
    ;-MainWindowEvents
    Case #MainWindow
     
      Select Event
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #sg1
              SetGadgetText(#sg1, Str(GetGadgetState(#sg1)))
            Case #sg2
              SetGadgetText(#sg2, Str(GetGadgetState(#sg2)))
          EndSelect
         
        Case #PB_Event_Timer
          Select EventTimer()
            Case #Timer1
              stop(hmo, channel)
              RemoveWindowTimer(#MainWindow, #Timer2)
            Case #Timer2
              p = p + 1              
              PitchBend(hmo, channel, $2000 + p)
              If p = $1FFF Or p = -$1FFF
                RemoveWindowTimer(#MainWindow, #Timer2)
              EndIf
          EndSelect
        Case #PB_Event_Menu
          Select EventMenu()
            Case #ReturnShotcut
             
              If GetGadgetText(#sg3) <> ""
                SysEXVolume(hmo, Val(GetGadgetText(#sg3)))
              EndIf
             
              play(hmo, channel)
              p = 0
            Case #F1Shortcut
              DisableWindow(#MainWindow, #True)
              dispositivo(hmo)
          EndSelect
      EndSelect
     
    ;-DeviceWindowEvents
    Case #DeviceWindow
      Select Event
        Case #PB_Event_CloseWindow
          CloseWindow(#DeviceWindow)
          DisableWindow(#MainWindow, #False)
          SetActiveWindow(#MainWindow)
         
        Case #PB_Event_Menu
          DeviceId = GetGadgetState(#lg1)
          If EventMenu() = #ReturnShotcut And DeviceId > -1
            result = midiOutOpen_(@hmo, DeviceId, #Null, #Null, #CALLBACK_NULL)
            ;two old lines removed from here
            PostEvent(#PB_Event_CloseWindow, #DeviceWindow, 0)
          EndIf
      EndSelect
     
  EndSelect
 
ForEver
Last edited by infratec on Wed Feb 19, 2020 8:18 am, edited 1 time in total.
MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

I am very grateful for everyone's effort to help me.
Unfortunately my computer stopped playing soundcanvas exclusive messages.
I am trying to correct this problem.

Even so, I am already quite optimistic about the codes provided, and I believe that my little mind opens up to this feature unknown to me.

As soon as I put everything to work, I'll post my complete code.
I look forward to everything being resolved.
MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

The pc problem has been solved, and the Roland demo songs using Sysex messages are already working perfectly on the windows media player.
I tested the complete posted code of Infratec.
The code works well with the yamaha vst: (syxg50). Although I did not enter any value. Just what was already. Both Yamaha and Roland vst.

However, Roland's SoundCanvas executes the phrase only once, and stops the program.
Debug does not indicate an error line or the like. Simply stop, and the fields (gadgets) are empty.
Taking a step by step, I realized that the program stops when executing the following line inside the procedure "SysEXVolume":
midiOutLongMsg_ (hmo, @MIDIheader, SizeOf (MIDIHDR))

But if I press "Enter" before the sentence ends, it repeats. If the sound ends and I press "Enter", literally nothing happens.

Going deeper, I saw that when I choose soundcanvas, the program vsthost64.exe is run in the background. However, if you use yamaha sxg50, vsthost32.exe is run.
When the sentence is executed for the first time, windows displays the error message, saying "foo_midi VST host bridge" has stopped working and needs to be closed. Even so, the program continues to respond to events. It only stops when I try to execute the sentence a second time.
Just remembering! It is only a problem when I use SoundCanvas. I'm looking for another 64bit vst even though it's a demo version just for testing.

As this is a part of the code that I don't quite understand, I don't know how to understand what is causing this shutdown.

If anyone can help me I would appreciate it, as this is a part of the code that I am trying to research, but I think it would take too long to find a solution alone.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Receiving MIDI System Exclusive Messages

Post by infratec »

I modified the sysex part a bit.

try it

Code: Select all

EnableExplicit

;-Enumerations
Enumeration Windows
  #MainWindow
  #DeviceWindow
EndEnumeration

Enumeration Gadgets
  #tg1
  #tg2
  #tg3
  #tg4
  #tg5
  #sg1
  #sg2
  #sg3
  #lg1
EndEnumeration

Enumeration Shortcuts
  #ReturnShotcut
  #F1Shortcut
EndEnumeration

Enumeration Timers
  #Timer1
  #Timer2
EndEnumeration


;-Procedures

Procedure PitchBend(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(n & $7F), 2, "0") + RSet(Hex(n >> 7), 2, "0") + "E" + Hex(channel)))  ; E = 1110 PITCH BEND
EndProcedure


Procedure ProgramChange(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$0000" + RSet(Hex(n), 2, "0") + "C" + Hex(channel))) ; C = 1100 PROGRAMM CHANGE
EndProcedure


Procedure controlchange(hmo.i, channel.i, n.i, v.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(v), 2, "0") + RSet(Hex(n), 2, "0") + "B" + Hex(channel)))  ; B = 1011 CONTROLLER
EndProcedure


Procedure playnote(hmo.i, channel.i, n.i, v.i)
  midiOutShortMsg_(hmo, Val("$00" + RSet(Hex(v), 2, "0") + RSet(Hex(n), 2, "0") + "9" + Hex(channel)))  ; 9 = 1001 NOTE ON
EndProcedure


Procedure stopnote(hmo.i, channel.i, n.i)
  midiOutShortMsg_(hmo, Val("$0000" + RSet(Hex(n), 2, "0") + "8" + Hex(channel))) ; 8 = 1000 NOTE OFF
EndProcedure


Procedure SysEXVolume(hmo.i, Volume.i)
  
  Protected MIDIHeader.MIDIHDR
  
  
  If Volume > $3FFF
    Volume = $3FFF
  EndIf
  
  MIDIHeader\lpData = AllocateMemory(8)
  If MIDIHeader\lpData
    
    PokeA(MIDIHeader\lpData + 0, $F0)  ; SysEx
    PokeA(MIDIHeader\lpData + 1, $7F)  ; Realtime
    PokeA(MIDIHeader\lpData + 2, $7F)  ; Channel (disregard)
    PokeA(MIDIHeader\lpData + 3, $04)  ; SubID (Device Control)
    PokeA(MIDIHeader\lpData + 4, $01)  ; SubID2 (Master Volume)
    PokeA(MIDIHeader\lpData + 5, Volume & $7F)  ; Volume lower 7 bits
    PokeA(MIDIHeader\lpData + 6, Volume >> 7)   ; Volume upper 7 bits
    PokeA(MIDIHeader\lpData + 7, $F7)           ; SysEx End
    
    MIDIHeader\dwBufferLength = MemorySize(MIDIHeader\lpData)
    MIDIHeader\dwFlags = 0
    
    midiOutPrepareHeader_(hmo, @MIDIHeader, SizeOf(MIDIHDR))
    
    midiOutLongMsg_(hmo, @MIDIheader, SizeOf(MIDIHDR))
    
    ;Unprepare the buffer And MIDIHDR
    While midiOutUnprepareHeader_(hmo, @MIDIHeader, SizeOf(MIDIHDR)) = #MIDIERR_STILLPLAYING
      Delay(3)
      Debug "Unprepeare"
    Wend
    
    FreeMemory(MIDIHeader\lpData)
  EndIf
  
EndProcedure


Procedure stop(hmo.i, channel.i)
  
  Protected r.i
  
  
  For r = 50 To 73
    stopnote(hmo, channel, r)
  Next
  RemoveWindowTimer(#MainWindow, #Timer1)
EndProcedure


Procedure play(hmo.i, channel.i)
  
  Protected.i r
  
  
  controlchange(hmo, channel, 10, GetGadgetState(#sg2)) ; 10 = pan
  programchange(hmo, channel, Val(GetGadgetText(#sg1)))
  stop(hmo, channel)
  AddWindowTimer(#MainWindow, #Timer1, 2000)
  If GetGadgetState(#tg5) = 1
    AddWindowTimer(#MainWindow, #Timer2, 5)
  EndIf
  pitchbend(hmo, channel, $2000)
  For r = 50 To 71 Step 3
    playnote(hmo, channel, r, 70)
    Delay(30)
  Next
EndProcedure


Procedure dispositivo(hmo.i)
  
  Protected.i iNumDev, around, w, k, Result
  Protected aa$
  Protected moc.MIDIOUTCAPS
  
  midiOutClose_(hmo)
  
  OpenWindow(#DeviceWindow, 0, 0, 300, 400, "Select a Midi Port")
  
  iNumDev = midiOutGetNumDevs_()
  TextGadget(#tg1, 10, 10, 280, 20, Str(iNumDev) + " MIDI out devices.")
  ListViewGadget(#lg1, 10, 40, 280, 330)
  For around = 0 To iNumDev - 1
    midiOutGetDevCaps_(around, moc, SizeOf(MIDIOUTCAPS))
    
    AddGadgetItem(#lg1, around, Str(around) + " " + PeekS(@moc\szPname[0], #MAXPNAMELEN))
  Next
  SetActiveGadget(#lg1)
  SetGadgetState(#lg1, 0)
  AddKeyboardShortcut(#DeviceWindow, #PB_Shortcut_Return, #ReturnShotcut)
  
EndProcedure




;-Main
Define.i Result, Event, DeviceId, hmo, channel, p


OpenWindow(#MainWindow, 0, 0, 300, 300, "Playing a simple frase")
TextGadget(#tg2, 10, 10, 150, 20, "Instrument number:")
SpinGadget(#sg1, 200, 10, 40, 20, 0, 127, #PB_Spin_Numeric)
SetActiveGadget(#sg1)
SetGadgetText(#sg1, "4")
SetActiveGadget(#sg1)
TextGadget(#tg3, 10, 50, 150, 20, "Balance:")
TrackBarGadget(#sg2, 120, 50, 150, 20, 0, 128)
SetGadgetState(#sg2, 64)

TextGadget(#tg4, 10, 100, 100, 20, "SysexVolume:")
SpinGadget(#sg3, 120, 100, 150, 20, 0, 16383, #PB_Spin_Numeric)
SetGadgetText(#sg3, "16383")

CheckBoxGadget(#tg5, 10, 150, 100, 20, "Pitch Bend:")

AddKeyboardShortcut(#MainWindow, #PB_Shortcut_Return, #ReturnShotcut)
AddKeyboardShortcut(#MainWindow, #PB_Shortcut_F1, #F1Shortcut)

PostEvent(#PB_Event_Menu, #MainWindow, #F1Shortcut)

;-EventLoop
Repeat
  Event = WaitWindowEvent()
  
  Select EventWindow()
      ;-MainWindowEvents
    Case #MainWindow
      
      Select Event
        Case #PB_Event_CloseWindow
          Break
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #sg1
              SetGadgetText(#sg1, Str(GetGadgetState(#sg1)))
            Case #sg2
              SetGadgetText(#sg2, Str(GetGadgetState(#sg2)))
          EndSelect
          
        Case #PB_Event_Timer
          Select EventTimer()
            Case #Timer1
              stop(hmo, channel)
              RemoveWindowTimer(#MainWindow, #Timer2)
            Case #Timer2
              p = p + 1             
              PitchBend(hmo, channel, $2000 + p)
              If p = $1FFF Or p = -$1FFF
                RemoveWindowTimer(#MainWindow, #Timer2)
              EndIf
          EndSelect
        Case #PB_Event_Menu
          Select EventMenu()
            Case #ReturnShotcut
              
              If GetGadgetText(#sg3) <> ""
                SysEXVolume(hmo, Val(GetGadgetText(#sg3)))
              EndIf
              
              play(hmo, channel)
              p = 0
            Case #F1Shortcut
              DisableWindow(#MainWindow, #True)
              dispositivo(hmo)
          EndSelect
      EndSelect
      
      ;-DeviceWindowEvents
    Case #DeviceWindow
      Select Event
        Case #PB_Event_CloseWindow
          CloseWindow(#DeviceWindow)
          DisableWindow(#MainWindow, #False)
          SetActiveWindow(#MainWindow)
          
        Case #PB_Event_Menu
          DeviceId = GetGadgetState(#lg1)
          If EventMenu() = #ReturnShotcut And DeviceId > -1
            result = midiOutOpen_(@hmo, DeviceId, #Null, #Null, #CALLBACK_NULL)
            ;two old lines removed from here
            PostEvent(#PB_Event_CloseWindow, #DeviceWindow, 0)
          EndIf
      EndSelect
      
  EndSelect
  
ForEver
MarcosPC
User
User
Posts: 17
Joined: Mon Mar 19, 2018 10:03 pm

Re: Receiving MIDI System Exclusive Messages

Post by MarcosPC »

OK! My mistake!
In another program that I did in another language, it gave a similar error in windows.
I used the 32bit version of soundcanvas, and it doesn't crash.
That is, my operating system has a problem with the 64-bit host version.
I have a laptop with windows 7 64bit installed, and I'll see if there is a problem there too.
Regardless, what I wanted was to make soundcanvas work with sysex, and this is already happening in the 32bit version.
SiggeSvahn
User
User
Posts: 40
Joined: Wed Oct 06, 2010 9:37 pm

Re: Receiving MIDI System Exclusive Messages

Post by SiggeSvahn »

Hi Khorus! After a long break I started coding again. Managed to send short MIDI messages to control my synth but I am failing to receive SYSEX DUMP. Tried you code by putting it amongst code that is working (receiving MIDI notes). Would you be kind to see what I did wrong?

Code: Select all

;Incoming SYSEX Tryout.
#WinMIDIrequester=1

Enumeration GADGETS 
  #txtOutputDevices=1
  #txtInputDevices
  #lgtOutputDevices
  #lgtInputDevices
  #btnOK
  #btnCancel
  #frgFrame
  #txtVersion
  #txttech
  #txtMaxVoice
  #txtPoly
EndEnumeration

Structure MIDI
  MIDIIn.A
  MIDIOut.A
  Stat.A
  Dat1.A
  Dat2.A
EndStructure

Global MidiHeader.MIDIHDR
Global hMiP0.l = 0
Global *SysexBuffer = AllocateMemory(4096)
Global _MIDI.MIDI
Global Dim arrSysexMessage.a(9)

Procedure MIDIRequester(*OutDevice, *InDevice)
  Define MaxOutDev, MaxInDev, InfoOut.MIDIOUTCAPS,InfoIn.MIDIINCAPS, a, OutDev, InDev, Quit, OK, TmpS.s, EventID
  
  #MOD_WAVETABLE = 6
  #MOD_SWSYNTH = 7
  #MIDIRequ_InSet = 2
  #MIDIRequ_OutSet = 1
 
  #Width = 400
  If OpenWindow(#WinMIDIrequester, 0, 0, #Width, 270, "MIDI-Requester Sel MIDI-modem etc slot that you want to use.", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    #Column = (#Width - 20) / 2
    #Offset = (#Width / 2) + 5
   
    TextGadget(#txtOutputDevices, 5, 5, #Column, 18, "Output-Device:", #PB_Text_Center | #PB_Text_Border)
    ListViewGadget(#lgtOutputDevices, 5, 23, #Column, 100)
    MaxOutDev = midiOutGetNumDevs_()
    InfoOut.MIDIOUTCAPS
    If MaxOutDev
      For a = -1 To MaxOutDev - 1
        midiOutGetDevCaps_(a, InfoOut, SizeOf(MIDIOUTCAPS))
        AddGadgetItem(#lgtOutputDevices, -1, PeekS(@InfoOut\szPname[0], 32))
      Next
    Else
      AddGadgetItem(#lgtOutputDevices, -1, "(no output device)")
      DisableGadget(#lgtInputDevices, 1)
    EndIf
;    MessageRequester("","1")
    TextGadget(#txtInputDevices, #Offset, 5, #Column, 18, "Input-Device:", #PB_Text_Center | #PB_Text_Border)
    ListViewGadget(#lgtInputDevices, #Offset, 23, #Column, 100)
    
    MaxInDev = midiInGetNumDevs_()
    InfoIn.MIDIINCAPS
    If MaxInDev
      For a = 0 To MaxInDev - 1
        midiInGetDevCaps_(a, InfoIn, SizeOf(MIDIINCAPS))
        AddGadgetItem(#lgtInputDevices, -1, PeekS(@InfoIn\szPname[0], 32))
      Next
    Else
      AddGadgetItem(#lgtInputDevices, -1, "(no input device)")
      DisableGadget(#lgtInputDevices, 1)
    EndIf
;     MessageRequester("","2")
    ButtonGadget(#btnOK, 5, 240, #Column, 24, "&OK")
    ButtonGadget(#btnCancel, #Offset, 240, #Column, 24, "&Cancel")
   
    FrameGadget(#frgFrame, 5, 130, #Width - 10, 100, "Info of Output-Device", 0)
    TextGadget(#txtVersion, 10, 145, #Width - 20, 18, "Version:")
    TextGadget(#txtTech, 10, 165, #Width - 20, 18, "Technology:")
    TextGadget(#txtMaxVoice, 10, 185, #Width - 20, 18, "Max. Voices:")
    TextGadget(#txtPoly, 10, 205, #Width - 20, 18, "Polyphonie:")
   
    OutDev = 0
    InDev = 0
    Quit = #False
    OK = #False
;     MessageRequester("","TEST")
    ; ======================================================================
    Repeat
      If GetGadgetState(#lgtOutputDevices) > -1 Or GetGadgetState(#lgtInputDevices) > -1
        DisableGadget(#btnOK, 0)
      Else
        DisableGadget(#btnOK, 1)
      EndIf
     
      If InDev <> GetGadgetState(#lgtInputDevices)
        InDev = GetGadgetState(#lgtInputDevices)
      EndIf
     
      If GetGadgetState(#lgtOutputDevices) <> OutDev
        OutDev = GetGadgetState(#lgtOutputDevices)
        midiOutGetDevCaps_(OutDev - 1, InfoOut, SizeOf(MIDIOUTCAPS))
        SetGadgetText(#txtVersion, "Version: " + Str(InfoOut\vDriverVersion >> 8) + "." + Str(InfoOut\vDriverVersion & $FF))
        Select InfoOut\wTechnology
          Case #MOD_MIDIPORT :  TmpS.s = "Hardware Port"
          Case #MOD_SYNTH :     TmpS.s = "Synthesizer"
          Case #MOD_SQSYNTH :   TmpS.s = "Square Wave Synthesizer"
          Case #MOD_FMSYNTH :   TmpS.s = "FM Synthesizer"
          Case #MOD_MAPPER :    TmpS.s = "Microsoft MIDI Mapper"
          Case #MOD_WAVETABLE : TmpS.s = "Hardware Wavetable Synthesizer"
          Case #MOD_SWSYNTH :   TmpS.s = "Software Synthesizer"
          Default: TmpS.s = "(Error Code " + Str(InfoOut\wTechnology) + ")"
        EndSelect
        SetGadgetText(#txtTech, "Technology: " + TmpS)
        If InfoOut\wVoices = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wVoices) : EndIf
        SetGadgetText(#txtMaxVoice, "Max. Voices: " + TmpS)
        If InfoOut\wNotes = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wNotes) : EndIf
        SetGadgetText(#txtPoly, "Polyphonie: " + TmpS)
      EndIf
     
      EventID = WaitWindowEvent()
      Select EventID
        Case #PB_Event_CloseWindow
          Quit = #True
          OK = #False
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #btnOK
              PokeL(*OutDevice, OutDev - 1) ; Trick to return two results (OutDev  & InDev)
              PokeL(*InDevice, InDev)
              Quit = #True
              OK = 3
              If (OutDev = -1 Or CountGadgetItems(#lgtOutputDevices) = 0) And OK & #MIDIRequ_OutSet 
                OK ! #MIDIRequ_OutSet : EndIf
                If (InDev = -1 Or CountGadgetItems(#lgtInputDevices) = 0) And OK & #MIDIRequ_InSet 
                  OK ! #MIDIRequ_InSet : EndIf
            Case #btnCancel
              Quit = #True
              OK = #False
          EndSelect
      EndSelect
    Until Quit
    ;==================================================================================
;     CloseWindow(#WinMIDIrequester)
    ProcedureReturn OK
  Else
    End
  EndIf
EndProcedure


Procedure MIDIInProc(hMIDIIn, WMsg, DuMMy, D1, D2) ;ONLY CALLED ON STARTUP BY ME BUT THE SYNTH CALLS IT ALL THE TIME! It is the callback function for handling incoming MIDI messages.
 Define i 
  
If FetchFlag
   Debug Hex(D2);Str(D1)
EndIf

  With _MIDI
    Select WMsg    ; process some MIDI in events.
      Case #MM_MIM_DATA;The MIM_DATA message is sent to a MIDI input callback function when a MIDI message is received by a MIDI input device.
        If D1 & $FF  =144 
          \Stat=(D1 >> 8)  & $FF  ;Note pitch value.
          \Dat1=(D1 >> 16) & $FF  ;Velocity value.
          If \Dat1
            SetWindowTitle(0,"Note On")
            Debug "MIDIInProc NOTE ON " + Str(D1) + "; " + Str(\Stat) + "; Velocity: " + Str(\Dat1) 
          Else
            SetWindowTitle(0,"Note Off")
          EndIf
        ElseIf D1 & $FF = $F0 ; Trying to recieve a SYSEX dump from my synth. The app MIDI-OX can recieve my dumps so my system is working.
          Debug "Start of SYSEX!"
          If (D1 >> 8)  & $FF = $42
            Debug "KORG-ID"
          EndIf
        EndIf
      Case #MIM_LONGDATA ; Trying to recieve a SYSEX dump from my synth. The app MIDI-OX can recieve my dumps so my system is working.
        Debug "---------- NEW INCOMING SYSEX -----------"
    
        For i = 0 To MidiHeader\dwBytesRecorded - 1                 ; Read Buffer Sent from LPData
        Debug Hex(arrSysexMessage(i))
      Next
;       MHI\lpData = @arrSysexMessage() ; MIDI Header pointer to MIDI data.
      
      midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))    ; Recycle Sysex Buffer
    EndSelect
  EndWith
EndProcedure

Procedure MIDIinit(OutDev, InDev, *MIDIInProc=-1,Instrument=0) ;ONLY CALLED ON STARTUP! MIDIinproc default solo show Note on, Note off
  Define iMidiInterface.i, i.l,sText.s
   
  If *MIDIinproc=-1:*MIDIinproc=@MIDIinproc():EndIf
  ; The MidiInProc function is the callback function for handling incoming MIDI messages. MidiInProc is a placeholder for the application-supplied function name.
  ; The address of this function can be specified in the callback-address parameter of the midiInOpen function.
  If midiInOpen_(@_hMIDIIn, InDev, *MIDIInProc, 0, #CALLBACK_FUNCTION) = #MMSYSERR_NOERROR
    If midiInStart_(_hMIDIIn) <> #MMSYSERR_NOERROR : MessageRequester("Error","Can't start MIDI IN",0) :End:  EndIf
  EndIf
  ; The midiInStart function starts MIDI input on the specified MIDI input device. hMidiIn is the handle to the MIDI input device. This function resets the time stamp to zero;
  ; time stamp values For subsequently received messages are relative to the time that this function was called. Calling this function when input is already started has no effect,
  ; and the function returns zero.
  midiOutOpen_(@_hMIDIout, OutDev, 0, 0, 0);Öppnar midi-interface. LPHMIDIOUT=lphmo=pointer to an HMIDIOUT handle.
  ; This location is filled with a handle identifying the opened MIDI output device.
  ; The handle is used To identify the device in calls To other MIDI output functions. OutDev=uDeviceID=Identifier of the MIDI output device that is to be opened.
  ; 3rd placeholder = dwCallback and 0 means no callback is desired. 4th placeholder is dwCallbackInstance. Last placeholder is dwFlags=callbackflag.
  midiOutShortMsg_(_hMIDIout, 192  | Instrument<<8 ) ; Sends a short MIDI message (here a Patch Change) to the specified MIDI output device. HMIDIOUT=hmo=Handle to the MIDI output device.
  ; This parameter can also be the handle of a MIDI stream cast To HMIDIOUT.
  ; The 2nd placeholder is dwMsg=similar to #MM_MIM_DATA above.
  If _hMIDIIn And _hMIDIout
    If midiConnect_(_hMIDIIn, _hMIDIout, 0);The midiConnect function connects a MIDI input device to a MIDI thru or output device,
      ; or connects a MIDI thru device To a MIDI output device.
      ; First inpDeviceHandle, then outpDevHandle, 3rd placeholder must be zero.
      MessageRequester("Error","Can't connect MIDI",0) :End
    EndIf
  EndIf
EndProcedure

MIDIResult = MIDIRequester(@OutDevice, @InDevice)

If MIDIResult & #MIDIRequ_OutSet : Debug "Output device: " + Str(OutDevice) : EndIf
If MIDIResult & #MIDIRequ_InSet  : Debug "Input device:  " + Str(InDevice) : EndIf

MIDIinit(OutDevice,InDevice);*** Is called only once! ****

OpenWindow(0, 10, 10, 300, 200, "MIDI Test")

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
Newbie
Post Reply