bugfix: midi thru from udp to usb triggers an assert()#998
bugfix: midi thru from udp to usb triggers an assert()#998probonopd merged 3 commits intoprobonopd:mainfrom
Conversation
usbmidi supports 16 virtual cables (nCable in the code) any midi message received from udp sets this to 24 which is invalid. This replaces 24 with 0
Reviewer's guide (collapsed on small PRs)Reviewer's GuideFixes an assertion failure when forwarding MIDI messages received over UDP to USB by normalizing an out-of-range virtual cable number to a valid USB MIDI cable index. Sequence diagram for UDP to USB MIDI forwarding with cable normalizationsequenceDiagram
participant UdpSource
participant MidiRouter
participant CMIDIKeyboard
participant UsbMidiDriver
UdpSource->>MidiRouter: MIDI message (nCable 24)
MidiRouter->>CMIDIKeyboard: Send(pMessage, nLength, nCable 24)
CMIDIKeyboard->>CMIDIKeyboard: Check nCable
alt nCable == 24
CMIDIKeyboard->>CMIDIKeyboard: Set Entry.nCable = 0
else nCable != 24
CMIDIKeyboard->>CMIDIKeyboard: Set Entry.nCable = nCable
end
CMIDIKeyboard->>UsbMidiDriver: Enqueue USB MIDI message (Entry.nCable <= 15)
UsbMidiDriver->>UsbMidiDriver: Assert Cable <= 15 (no failure)
UsbMidiDriver-->>UdpSource: MIDI successfully forwarded via USB
Class diagram for CMIDIKeyboard Send logic with cable normalizationclassDiagram
class CMIDIKeyboard {
+void Send(u8* pMessage, size_t nLength, unsigned nCable)
}
class TSendQueueEntry {
+u8* pMessage
+size_t nLength
+unsigned nCable
}
CMIDIKeyboard "1" --> "many" TSendQueueEntry : enqueues
class SendImplementation {
+void Send(u8* pMessage, size_t nLength, unsigned nCable)
+void NormalizeCable(unsigned nCable)
}
CMIDIKeyboard ..> SendImplementation : implements logic
class NormalizeCableLogic {
+unsigned NormalizeCable(unsigned nCable)
}
SendImplementation ..> NormalizeCableLogic : uses
%% Pseudocode representation of the updated logic
class NormalizeCableLogicDetails {
+unsigned NormalizeCable(unsigned nCable)
unsigned nCableParam
unsigned resultCable
}
NormalizeCableLogicDetails : NormalizeCable(unsigned nCable)
NormalizeCableLogicDetails : if nCable == 24 then resultCable = 0
NormalizeCableLogicDetails : else resultCable = nCable
NormalizeCableLogic <|-- NormalizeCableLogicDetails
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- Instead of hard-coding 24, consider defining a named constant or reusing an existing enum/value for the UDP virtual cable so the intent is clearer and less error-prone if it changes elsewhere.
- You might want to clamp or validate nCable more generally (e.g., if nCable > 15, map to 0 or a default) rather than only handling the special case of 24, to avoid similar asserts from other invalid values.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Instead of hard-coding 24, consider defining a named constant or reusing an existing enum/value for the UDP virtual cable so the intent is clearer and less error-prone if it changes elsewhere.
- You might want to clamp or validate nCable more generally (e.g., if nCable > 15, map to 0 or a default) rather than only handling the special case of 24, to avoid similar asserts from other invalid values.
## Individual Comments
### Comment 1
<location> `src/midikeyboard.cpp:79-91` </location>
<code_context>
Entry.pMessage = new u8[nLength];
Entry.nLength = nLength;
- Entry.nCable = nCable;
+ // If the midi message originated from udp, nCable is VIRTUALCABLE (24)
+ // This violates usb midi as its > 15 and will trigger an assert
+ // maybe make this configurable or use the 1st usb rx message nCable
</code_context>
<issue_to_address>
**suggestion:** Avoid hardcoding the magic value 24; rely on a named constant instead.
Since the code and comment both rely on the value 24, it would be clearer and safer to use the named constant (e.g., VIRTUALCABLE) instead of the literal. That way, if the underlying value changes, this comparison stays correct and the intent remains obvious.
```suggestion
Entry.pMessage = new u8[nLength];
Entry.nLength = nLength;
// If the midi message originated from udp, nCable is VIRTUALCABLE
// This violates usb midi as its > 15 and will trigger an assert
// maybe make this configurable or use the 1st usb rx message nCable
if (nCable == VIRTUALCABLE)
{
Entry.nCable = 0;
}
else
{
Entry.nCable = nCable;
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
src/midikeyboard.cpp
Outdated
| Entry.pMessage = new u8[nLength]; | ||
| Entry.nLength = nLength; | ||
| Entry.nCable = nCable; | ||
| // If the midi message originated from udp, nCable is VIRTUALCABLE (24) | ||
| // This violates usb midi as its > 15 and will trigger an assert | ||
| // maybe make this configurable or use the 1st usb rx message nCable | ||
| if (nCable == 24) | ||
| { | ||
| Entry.nCable = 0; | ||
| } | ||
| else | ||
| { | ||
| Entry.nCable = nCable; | ||
| } |
There was a problem hiding this comment.
suggestion: Avoid hardcoding the magic value 24; rely on a named constant instead.
Since the code and comment both rely on the value 24, it would be clearer and safer to use the named constant (e.g., VIRTUALCABLE) instead of the literal. That way, if the underlying value changes, this comparison stays correct and the intent remains obvious.
| Entry.pMessage = new u8[nLength]; | |
| Entry.nLength = nLength; | |
| Entry.nCable = nCable; | |
| // If the midi message originated from udp, nCable is VIRTUALCABLE (24) | |
| // This violates usb midi as its > 15 and will trigger an assert | |
| // maybe make this configurable or use the 1st usb rx message nCable | |
| if (nCable == 24) | |
| { | |
| Entry.nCable = 0; | |
| } | |
| else | |
| { | |
| Entry.nCable = nCable; | |
| } | |
| Entry.pMessage = new u8[nLength]; | |
| Entry.nLength = nLength; | |
| // If the midi message originated from udp, nCable is VIRTUALCABLE | |
| // This violates usb midi as its > 15 and will trigger an assert | |
| // maybe make this configurable or use the 1st usb rx message nCable | |
| if (nCable == VIRTUALCABLE) | |
| { | |
| Entry.nCable = 0; | |
| } | |
| else | |
| { | |
| Entry.nCable = nCable; | |
| } |
|
Build for testing: |
|
I think you should simply change the VIRTUALCABLE define to 0 in udpmididevice.cpp. |
This reverts commit d300d2e. For a much simpler solution...
much simpler :) |
usbmidi supports 16 virtual cables (nCable in the code)
any midi message received from udp sets this to 24 which is invalid.
This replaces 24 with 0
|
Build for testing: |
|
@penfold42 thank you very much for this bugfix. Does the latest build work for you as intended? Do you think it is ready for being merged? |
The build from my dev environment does - do you think I should also test the github actions build? |
|
Yes, that'd be the their purpose. Thanks! |
Tested that build on my pi3. VMPK->rtpmidid->minidexed->Arduino USB midi cable->homebrew WiFi midi box->fluidsynth |
|
Thanks @penfold42 |
usbmidi.cpp(91): assertion failed: Cable <= 15
usbmidi supports 16 virtual cables (nCable in the code).
Midi message received from udp sets this to 24 which is invalid.
This replaces 24 with 0 but perhaps something configurable or dynamic could be done.
Summary by Sourcery
Bug Fixes: