Add a MIDI monitor for diagnosing controller input - #565
Draft
diamondsea11 wants to merge 1 commit into
Draft
Conversation
There is currently no way to see what a MIDI controller is actually sending. The only path that reports incoming MIDI to a client is MIDI learn, which by design shows just the messages it can bind to: note-on with non-zero velocity and control change (minus bank select and CC LSB). Program change, note-off, pitch bend, aftertouch and channel pressure are dropped in two places -- the realtime filter in AudioHost and again in PiPedalModel::OnNotifyMidiListen -- so when a footswitch "does nothing", there is nothing to look at. Adds a monitor mode alongside MIDI learn rather than a second pipeline: - MidiListener gains listenForAllEvents. The filter in OnNotifyMidiListen becomes per-listener, so learn clients receive exactly the same set of messages as before. - New monitorMidiEvents socket message reuses the existing listener list and is cancelled with cancelListenForMidiEvent. - SetMonitorAllMidiEvents on the audio host makes the realtime filter pass messages through unmodified while a monitor is attached. - The three places that recomputed the listen flag now share UpdateMidiListenerState(). The UI is a read-only, full-screen dialog reached from a toolbar button in System MIDI Bindings: newest-first list of decoded messages with channel, type and data, plus pause and clear. Bounded to 200 entries so a controller streaming CCs cannot grow it without limit. No change to MIDI learn behaviour, to bindings, or to what reaches plugins. Verified with npx tsc -b --force. The C++ has not been compiled -- I have no Linux build environment here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
diamondsea11
pushed a commit
to diamondsea11/pipedal
that referenced
this pull request
Aug 6, 2026
…draft Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft — the diagnostics half of the MIDI work, which you said you had no objection to. Deliberately carries none of the Control Hub / controller-profile / per-snapshot-action material that overlaps with your MIDI Mappings roadmap.
Two things up front, so you can judge how hard to look at it:
tsc -b --force. Everything else is code review only.main. That means it's new code, not code that has been running on my Pi.The problem
There is no way to see what a controller is actually sending. The only path that reports incoming MIDI to a client is MIDI learn, and by design it reports only what it can bind to: note-on with non-zero velocity, and control change minus bank select and CC LSB. Everything else is dropped twice — once in the realtime filter in
ProcessMidiMonitor, and again inPiPedalModel::OnNotifyMidiListen. So when a footswitch appears to do nothing, there is nothing to look at, and no way to tell "the device sent nothing" from "the device sent a program change and PiPedal ignored it".The change
A monitor mode alongside MIDI learn rather than a parallel pipeline:
MidiListenergainslistenForAllEvents. The filter inOnNotifyMidiListenbecomes per-listener, so learn clients receive exactly the set of messages they received before — the note-off and non-note/CC drops are preserved for them verbatim.monitorMidiEventssocket message reuses the existing listener list; cancelled with the existingcancelListenForMidiEvent. ThelistenForMidiEventmessage is untouched, so there is no wire-compatibility question for existing clients.SetMonitorAllMidiEventson the audio host makes the realtime filter pass messages through unmodified while a monitor is attached, and only then.UpdateMidiListenerState().The UI is a read-only full-screen dialog reached from a toolbar button in System MIDI Bindings. Newest-first list of decoded messages (time, channel, type, data), pause and clear. Bounded to 200 entries so a controller streaming CCs can't grow it without limit.
Things worth your judgement
MidiNotifyBodyto the ring buffer instead of only bindable ones. For a controller that streams CCs that's a higher rate than learn ever produced. It's bounded by MIDI bandwidth and only happens while the dialog is open, but you know that ring buffer's headroom better than I do — if you'd rather it coalesced or rate-limited, say so.CancelMonitorAtomOutput'smidiEventListeners.size()check alone. It looks like a copy-paste (it's in the atom-output path), but it's pre-existing and unrelated, and I didn't want to bury it in this diff.Happy to drop the UI entirely and land just the backend if you'd rather build the dialog yourself.