Skip to content

Commit 02d5646

Browse files
fix sysex parsing in rtmidi platform
Buffers come in chunk of 1kb, they sometime need to be kept around until the message is completed in subsequent buffer
1 parent 0ad6fba commit 02d5646

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

src/Midinette.Platform.RtMidi/RtMidinettePlatformImpl.fs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,14 @@ type RtMidiMidinettePlatformImpl() as this =
107107
let error = new Event<_>()
108108
let channelMessage = new Event<_>()
109109
let sysex = new Event<_>()
110+
let invalidSysex = new Event<_>()
110111
let systemMessage = new Event<_>()
111112
let realtimeMessage = new Event<_>()
112-
port.InputDevice.Message.Add(fun bytes ->
113+
114+
let sysexParts = ResizeArray()
115+
116+
let rec onBytes (bytes: byte array) =
117+
113118
let status : MidiMessageType = LanguagePrimitives.EnumOfValue (bytes.[0])
114119
let inline toMidiEvent (bytes: byte array) (watch: Stopwatch) =
115120
let timestamp = watch.ElapsedTicks
@@ -120,21 +125,52 @@ type RtMidiMidinettePlatformImpl() as this =
120125
let event = toMidiEvent bytes watch
121126
event1.Trigger event
122127
platformNoticer ({info = device},event)
128+
let inline pushSysexBytes endSysexIndex =
129+
let sysexBytes =
130+
[|
131+
yield! sysexParts.ToArray()
132+
yield bytes.[0 .. endSysexIndex]
133+
|] |> Array.concat
134+
135+
sysex.Trigger (UMX.tag_sysex_data sysexBytes)
136+
platformEvents.NoticeSysex({info = device }, sysexBytes)
137+
sysexParts.Clear()
138+
139+
140+
let inline getSysexEndIndex () = bytes |> Array.tryFindIndex (fun i -> i = byte MidiMessageType.SysExEnd)
123141
if MidiMessageTypeIdentifaction.isChannelMessage status then
124142
triggerMessageEvent channelMessage platformEvents.NoticeChannelMessage
125143
elif MidiMessageTypeIdentifaction.isRealtimeMessage status then
126144
triggerMessageEvent realtimeMessage platformEvents.NoticeRealtimeMessage
127145
elif MidiMessageTypeIdentifaction.isSystemMessage status then
128-
if MidiMessageTypeIdentifaction.isSysexBeginOrEnd status then
129-
sysex.Trigger (UMX.tag_sysex_data bytes)
130-
platformEvents.NoticeSysex({info = device }, bytes)
146+
if status = MidiMessageType.SysExEnd then
147+
sysexParts.Add ([|bytes.[0]|])
148+
pushSysexBytes 0
149+
elif status = MidiMessageType.SysEx then
150+
if sysexParts.Count > 0 then
151+
invalidSysex.Trigger(sysexParts.ToArray() |> Array.concat)
152+
sysexParts.Clear()
153+
else
154+
match getSysexEndIndex () with
155+
| Some endSysexIndex ->
156+
pushSysexBytes endSysexIndex
157+
if bytes.Length > endSysexIndex then
158+
onBytes bytes.[endSysexIndex..]
159+
| None ->
160+
sysexParts.Add bytes
131161
else
132162
triggerMessageEvent systemMessage platformEvents.NoticeSystemMessage
163+
elif sysexParts.Count > 0 then
164+
match getSysexEndIndex() with
165+
| Some endIndex ->
166+
pushSysexBytes endIndex
167+
| None ->
168+
sysexParts.Add bytes
133169
else
134170
#if DEBUG
135171
failwithf "unable to parse what I received received %A" bytes
136172
#endif
137-
)
173+
port.InputDevice.Message.Add(onBytes)
138174
let inEvents = {error = error; channelMessage = channelMessage; sysex = sysex; systemMessage = systemMessage; realtimeMessage = realtimeMessage }
139175
Some ({ inPort = port; info = rtDevice; inEvents = inEvents } :> _)
140176
| _ -> None

0 commit comments

Comments
 (0)