Page 1 of 1

KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 3:11 pm
by SiggeSvahn
Hi! I have a non working snippet that I really would like to get in order. Which subforum is a good place to ask for a programmer to debug for money?

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 4:10 pm
by firace
SiggeSvahn wrote: Tue Jan 02, 2024 3:11 pm Hi! I have a non working snippet that I really would like to get in order. Which subforum is a good place to ask for a programmer to debug for money?
I guess this can be the right subforum, assuming it's a PB program.
But why not just post the snippet and see if people can help you fix it? Or would you rather not circulate the code publicly?

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 4:30 pm
by SiggeSvahn
Well, here is the snippet. I use PC Win11 and syntheziser KORG X5D. The portion that should receive a MIDI Bulf Dump does not work. I would pay 200$ to the first person who presents a version that works on my computer.

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

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 5:03 pm
by firace
SiggeSvahn wrote: Tue Jan 02, 2024 4:30 pm Well, here is the snippet. I use PC Win11 and syntheziser KORG X5D. The portion that should receive a MIDI Bulf Dump does not work. I would pay 200$ to the first person who presents a version that works on my computer.
Nice challenge! I unfortunately don't have a MIDI device to test.

But what exactly happens with the current code? Does it crash, or do you get an error message?

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 5:23 pm
by firace
Some shots in the dark... Could you try the below code?

I've fixed a few things like initializing the MIDI header, and the Sysex buffer.

Code: Select all

;;; firace debugging v0.3 

;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(PeekB(*SysexBuffer + i) & $FF)
          
          
          
        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
  
  
  MIDIHeader\dwFlags = 0
  MidiHeader\dwBufferLength = 16384
  MidiHeader\lpData = *SysexBuffer
  
  
  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
    
    midiInPrepareHeader_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader)) 
    midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))
    
    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

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 8:46 pm
by SiggeSvahn
firace wrote: Tue Jan 02, 2024 5:03 pm
SiggeSvahn wrote: Tue Jan 02, 2024 4:30 pm Well, here is the snippet. I use PC Win11 and syntheziser KORG X5D. The portion that should receive a MIDI Bulf Dump does not work. I would pay 200$ to the first person who presents a version that works on my computer.
Nice challenge! I unfortunately don't have a MIDI device to test.

But what exactly happens with the current code? Does it crash, or do you get an error message?
I see you two replies. I have been idle for a while. Just a moment while I connect the cables.

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 10:42 pm
by SiggeSvahn
firace wrote: Tue Jan 02, 2024 5:23 pm Some shots in the dark... Could you try the below code?

I've fixed a few things like initializing the MIDI header, and the Sysex buffer.

Code: Select all

;;; firace debugging v0.3 

;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(PeekB(*SysexBuffer + i) & $FF)
          
          
          
        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
  
  
  MIDIHeader\dwFlags = 0
  MidiHeader\dwBufferLength = 16384
  MidiHeader\lpData = *SysexBuffer
  
  
  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
    
    midiInPrepareHeader_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader)) 
    midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))
    
    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
NICE TRY! Your version is recieving 5 bytes of SYSEX data and then it stops (F0, 42, 30, 36, 23, F7). It is a kind of success so I want to send 200$ through PayPal. I would like it to continuously show what keeps coming from the synth. I have both the keyboard version KORG X5D and the rack version X5DR. Would you be interested in that I send the rack to you so that you could try yourself (tell me your price)?

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 11:21 pm
by firace
SiggeSvahn wrote: Tue Jan 02, 2024 10:42 pm NICE TRY! Your version is recieving 5 bytes of SYSEX data and then it stops (F0, 42, 30, 36, 23, F7). It is a kind of success so I want to send 200$ through PayPal. I would like it to continuously show what keeps coming from the synth. I have both the keyboard version KORG X5D and the rack version X5DR. Would you be interested in that I send the rack to you so that you could try yourself (tell me your price)?
Glad to know I could help!
But I don't have a MIDI keyboard at this time, so I can't do more thorough testing unfortunately. :(

PS: I just replied to your PM.

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 02, 2024 11:48 pm
by firace
Thanks for the generous reward! Here’s another version with increased buffer size, perhaps it will be able to capture more Sysex data. (untested)

Code: Select all


;;; firace debugging v0.4

;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(65536)
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(PeekB(*SysexBuffer + i) & $FF)
          
          
          
        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
  
  
  MIDIHeader\dwFlags = 0
  MidiHeader\dwBufferLength = 65536
  MidiHeader\lpData = *SysexBuffer
  
  
  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
    
    midiInPrepareHeader_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader)) 
    midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))
    
    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


Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Wed Jan 03, 2024 1:50 pm
by firace
Hey, I've had a bit of time to do some extra debugging and fixed a few more things... I would recommend to try both versions 0.5a and 0.5b (see below) and see which one produces the best result.
Hope this helps!

Code: Select all


;;; firace debugging ver 0.5a

;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(65536)
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(PeekB(*SysexBuffer + i) & $FF)
          
          
          
        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
  
  
  MIDIHeader\dwFlags = 0
  MidiHeader\dwBufferLength = 65536
  MidiHeader\lpData = *SysexBuffer
  
  
  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
    
    midiInPrepareHeader_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader)) 
    midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))
    
    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

Code: Select all


;; firace debugging ver 0.5b

;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(PeekB(MidiHeader\lpData + i) & $FF)       
        Next
        ;       MHI\lpData = @arrSysexMessage() ; MIDI Header pointer to MIDI data.
        
        Debug "Byte count: " + MidiHeader\dwBytesRecorded
        
        If MidiHeader\dwBytesRecorded
          midiInAddBuffer_(hMIDIIn, @MidiHeader, SizeOf(MidiHeader))    ; Recycle Sysex Buffer
        Endif
        
    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
  
  
  MIDIHeader\dwFlags = 0
  MidiHeader\dwBufferLength = 16384
  MidiHeader\lpData = *SysexBuffer
  
  
  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
    
    midiInPrepareHeader_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader)) 
    midiInAddBuffer_(_hMIDIIn, @MidiHeader, SizeOf(MidiHeader))
    
    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

Re: KORG X5D via MIDI (was: Where to hire a programmer)

Posted: Tue Jan 16, 2024 12:47 pm
by firace
Hi there, I was wondering, did you have a chance to try out the updated code? I’m curious to know if it provides more Sysex data.