Skip to content

midi host: document drain requirement of RX FIFO#3614

Merged
HiFiPhile merged 4 commits intohathach:masterfrom
HakanL:midi-host-rx-bufsize-default-and-docs
May 7, 2026
Merged

midi host: document drain requirement of RX FIFO#3614
HiFiPhile merged 4 commits intohathach:masterfrom
HakanL:midi-host-rx-bufsize-default-and-docs

Conversation

@HakanL
Copy link
Copy Markdown
Contributor

@HakanL HakanL commented Apr 22, 2026

Follow-up to #3239. That fix addressed garbage bytes in the data position of USB-MIDI event packets. A related wedge remains when a packet contains events whose header byte (cable number) varies mid-buffer, because tuh_midi_stream_read terminates on cable-number transitions rather than on end-of-FIFO.

With the default CFG_TUH_MIDI_RX_BUFSIZE = TUH_EPSIZE_BULK_MAX (64 B), any residue left in the stream FIFO by a parse-stop-on-cable-transition prevents the next bulk IN transfer from landing. tu_edpt_stream_read_xfer in midih_xfer_cb silently fails to queue and the driver stops receiving data with no error indication.

Reproducer: Akai LPD8 mk1 (VID 0x09E8, PID 0x0075). After its 64 B power-on burst — whose USB-MIDI event headers span multiple fake cable numbers — the endpoint goes silent forever unless the host FIFO is big enough to absorb the residue or the app drains the FIFO in a loop. See attached lpd8-usbmon.pcap in the linked issue for a Linux usbmon capture showing the same device streaming fine under snd-usb-audio (whose read loop drains per call).

Changes

  1. CFG_TUH_MIDI_RX_BUFSIZE default raised from TUH_EPSIZE_BULK_MAX to 2 * TUH_EPSIZE_BULK_MAX. Gives the app one full packet of residue headroom. Cost: +64 B per MIDI instance.
  2. Added a note on tuh_midi_stream_read that it may return without draining the FIFO when a cable-number change is encountered, and callers should invoke it in a loop to guarantee full drainage.

Tested

STM32H753 (DWC2 OTG host, full speed) against:

  • Akai LPD8 mk1 (the reproducer — reliable across unplug/replug cycles with this patch; wedges without)
  • Akai LPD8 mk2
  • WORLDE ORCA 16 MiniKey

All three work with the new defaults; no behaviour change observed for mk2 or WORLDE.

Addresses the remaining wedge reported as a continuation of #3239. Full reproduction details and captures in #3613.

…ement

Follow-up to hathach#3239. tuh_midi_stream_read terminates on cable-number
transitions, leaving residue in the FIFO. With the default RX FIFO
sized equal to one bulk packet, the next bulk IN transfer fails to
queue and the driver silently stops receiving. Raising the default
to 2x bulk gives single-call apps a full packet of headroom and
documents the drain-loop expectation.

Reproduced with Akai LPD8 mk1 (VID 09E8 PID 0075) on STM32H753 DWC2
host; fixed with this patch. See hathach#3613 for full repro + captures.
Copilot AI review requested due to automatic review settings April 22, 2026 22:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts TinyUSB’s MIDI host defaults and API documentation to prevent a silent RX stall when tuh_midi_stream_read() stops early on USB-MIDI cable-number transitions, leaving residue in the endpoint stream FIFO.

Changes:

  • Increase default MIDI host RX FIFO size to 2 * TUH_EPSIZE_BULK_MAX to provide headroom for leftover bytes.
  • Increase default MIDI host TX FIFO size symmetrically.
  • Document that tuh_midi_stream_read() may return without draining the FIFO and should be called in a loop to fully drain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/class/midi/midi_host.h
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/class/midi/midi_host.h:50

  • PR description says the default CFG_TUH_MIDI_TX_BUFSIZE was raised “symmetrically”, but in this header it still defaults to TUH_EPSIZE_BULK_MAX. Either update the PR description to match the code, or also change the TX default here if symmetry is intended.
  #define CFG_TUH_MIDI_RX_BUFSIZE (2 * TUH_EPSIZE_BULK_MAX)
#endif

#ifndef CFG_TUH_MIDI_TX_BUFSIZE
  #define CFG_TUH_MIDI_TX_BUFSIZE TUH_EPSIZE_BULK_MAX

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 3, 2026

MemBrowse Memory Report

No memory changes detected across 2233 targets. View Project Dashboard →

HiFiPhile added 2 commits May 7, 2026 11:17
Even if CFG_TUH_MIDI_RX_BUFSIZE=100*TUH_EPSIZE_BULK_MAX, calling tuh_midi_stream_read without a loop  can return only one 4-byte packet and preventing subsequent transfer.

Signed-off-by: Zixun LI <admin@hifiphile.com>
@HiFiPhile HiFiPhile changed the title midi host: raise default RX FIFO above EP size + document drain requirement midi host: document drain requirement May 7, 2026
@HiFiPhile HiFiPhile changed the title midi host: document drain requirement midi host: document drain requirement of RX FIFO May 7, 2026
Comment thread src/class/midi/midi_host.h Outdated
#define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MAX
// Default sized to 2x the bulk endpoint to absorb residue left in the FIFO
// when tuh_midi_stream_read() stops early on a cable-number transition.
// Sizing this equal to the endpoint packet size (the historical default)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, with your 2. always reading stream in a loop this comment is no longer true.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @HiFiPhile I didn't see your comment here. Hmm, I don't think no-change would work though, I needed the extra RX buffer to capture the garbage that the LPD8 was sending out.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any garbage should be drained by reading RX FIFO in a loop.

Even if CFG_TUH_MIDI_RX_BUFSIZE=100*TUH_EPSIZE_BULK_MAX, calling tuh_midi_stream_read without a loop can return only one 4-byte packet and preventing subsequent transfer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HiFiPhile Yeah, that makes sense, but I already have a loop to read, so I don't know why it didn't work until I bumped the buffer size. I'll do some more testing.

@HiFiPhile HiFiPhile merged commit d21fdd9 into hathach:master May 7, 2026
291 of 293 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants