How to receive a MIDI Sysex from a device (Mac OS)

I am sending SysEx’s to the device on Xojo using the MIDISysexSendRequestMBS class.
I know it is successful, because SysEx Librarian detects incoming SysEx’s from the device in response to my instructions.

The question is, how to receive these in my own Xojo application?

Try posting to the Add-Ons category for MBS stuff, or to the MBS mailing list for best response.

You would receive them on an MidiEndpointMBS with a packet list.
And I think you join the DataMemory part of all the MidiPacketMBS objects to get the sysEx data.

1 Like

Some data started arriving when I created a Handler for the inputPort’s Read Event.
However, it is broken up into packets of 3 bytes, and sometimes out of sequence! Below is my event Handler for the Read function (packet_list is the variable I use to analyse the Midi messages I am receiving).

readData(port As MidiPortMBS, endpoint As MidiEndpointMBS, list as MidiPacketListMBS)

packet_list = list
endpoint.Recieved(list)

Verifying the input, e.g like so:

p_string = EncodingToHexMBS(packet_list.Item(index).DataString)`
System.DebugLog(p_string)

and then printing the output gives various results in sometimes correct order, e.g. F0 00 02, 1C 4E F7, 02 04 F7.
Meanwhile Sysex Librarian correctly identifies each message as a 9 hex-value sequence.

Hi Dominik. Resurrecting this old message thread. Can you share some code in which the Read event of your MidiEndpointMBS works? The MBS documentation states that one should subclass MidiEndpointMBS in order to gain access to the Read event. I’ve done this, but I simply cannot get the event to fire.

I’ve embarked on a project to create a GUI that never existed for a old piece of MIDI-enabled gear. My XOJO program can select programs/presets on the unit, and I can send Sysex messages, but after countless frustrating hours, I just can’t get my Read event to respond to the incoming Sysex. Both Sysex Librarian and MIDI Monitor show my outgoing Sysex message and the incoming one, so I know the unit is responding as expected.

Thanks for any help you can provide.

You need to create a port for your MidiClientMBS

midiPort=new MyMidiPort // Subclass of MidiPortMBS
MidiClient.CreateInputPort(NewCFStringMBS("My input port"), midiPort)
If midiPort.Handle=0 then
  MsgBox "There was an error opening the MIDI port: "+str(midiClient.Lasterror)
  Return
end if

and later, like in the ObjectAdded event of MidiClientMBS, connect an endpoint to the port

for srcnum=0 to numsources-1
  source = new MidiEndpointMBS
  source=me.GetSource(srcnum)
  if source<>Nil then
    sourcename = Source.StringProperty(me.kMIDIPropertyName).str // debug
    if Instr(sourcename,"name of device") <> 0 then // It's the device I want
      midiPort.ConnectSource(source)

Julia,

THANK YOU SO MUCH for some working code! I can now see data arriving at the my input port’s Read event. However, I’ve got an issue - only on rare occasion does the Sysex-ending F7 byte appear at the end of the data. All the preceding data appears (in proper sequence) as expected. Any suggestions? MIDI Monitor (open source) program ALWAYS shows the F7 at the end of the data, so I know it’s there (even with its option OFF to force (append?) F7 at the end).

Also, getting back to my original post above, I inquired about getting my MidiClientMBS’s Read event to fire. Does this event fire when the entire data package has been received as opposed to the input port’s Read event which fires 3 bytes at a time?

1 Like

Hi Peter,

Glad my ancient rickety code is helpful :slight_smile:

Here’s my endpoint Read event handler:

Sub Read(endpoint as MidiEndpointMBS, list as MidiPacketListMBS) Handles Read
   
  Dim i, n, x, MsgByte as integer
  Dim pack as MIDIPacketMBS
  Dim data as memoryBlock
  
  // Data is coming in, reset the timeout
  RXTimer = Microseconds
  
  // Store incoming sysex messages (each beginning with a SOX and ending with an EOX) into the Messages() buffer.
  n = list.Count-1
  
  for i = 0 to n
    pack = list.item(i)
    data = pack.dataMemory
    
    if not GotSOX then
      if data.Byte(0) = &hF0 then // ## this will only find SOX if it's at the beginning of a packet. ##
        SysexStr = ""
        GotSOX = True // Start the sysex accumulation
      end
    end
    
    if GotSOX then // accumulate the sysex message
      For x=0 to data.Size-1
        SysexStr = SysexStr + chrB(data.Byte(x))
        If data.Byte(x)=EOX Then // Got EOX - done accumulating, be on the lookout again for new messages
          GotSOX = False
          Messages.Append(SysexStr)
        End If
      Next
    end
    
  Next
  
End Sub

It’s been over a decade since I wrote this and I rarely go this deeply into the bowels of the app anymore, but it’s been in continuous use ever since, so it seems I don’t have any trouble getting EOX (0xF7).

As is the case with serial devices, you want to do as little processing as possible in the Read event - just accumulate messages there in a buffer and handle them later e.g. in the Action event of a timer. If you try to do too much processing in the Read event you may miss bytes.

Ok, got it. BUT how did you initialize/setup your EndPointMBS object’s Read event? Did you subclass EndPointMBS to (for example) MyEndPointMBS and then add the Read event to your MyEndPointMBS subclass in the IDE? Or did you do a AddHandler MyMIDIEndpointMBS.Read, WeakAddressOf Read in your code?

Looking at your code in the prior message, if I’m not mistaken, your endpoint’s Read is called AFTER it’s received the entire Sysex message. You then break it down into its individual bytes. Perfect. I would prefer to do it this way (which still isn’t working for me) instead of utilizing my inputport’s Read, which doesn’t get the entire Sysex message at once, but rather in 3 byte chunks (and is almost always missing the F7 at the end of the message, as mentioned).

Yes.

Yeah, it does look that way… probably not how I’d do it now, but it works in my app, which deals mostly (entirely?) with pretty short messages.