Skip to content

midiports: Web MIDI ports for Pyodide - #208

Merged
bdbarnett merged 1 commit into
alignment/midifrom
ostinato/webmidi
Oct 16, 2026
Merged

bdbarnett merged 1 commit into
alignment/midifrom
ostinato/webmidi

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

Adds midiports.webmidi, so Python running in Pyodide can give adafruit_midi.MIDI its ports through Web MIDI.

Web MIDI only exists on a page's main thread, so there are two ways in:

  • On the page: midi_in, midi_out = await webmidi.open(name="", sysex=False). The name matches part of a port's name, ignoring case; the default merges every input and sends to the first output. Devices plugged in later, or unplugged and plugged back in, are picked up while the ports are open. webmidi.ports(access, name="") does the same for code that already holds a MIDIAccess.
  • In a worker: midi_in, midi_out = webmidi.relay_ports(port) over a MessagePort that the page feeds. Page to worker is {data: Uint8Array, timeStamp: number}, one whole message per post; worker to page is {data: Uint8Array}.

Inputs are a byte ring, so an empty poll allocates nothing and any() is cheap. They also keep each message's arrival time: call midi_in.take_timestamp() once for each message receive() returns and you get that message's time in milliseconds on the performance.now() clock. Outputs send whole messages only, holding a partial write until it's finished, since Web MIDI's send() refuses part of a message.

The README gains a row in the transport table and an "In a browser" section.

Testing: both halves are in tests/midiports_contract.py over a fake MIDIAccess and a fake MessagePort (200 of 200 notes each way, any() first, timestamps paired with receive()), passing on CPython and unix MicroPython. tests/test_midiports.py adds unit tests for the ring, overflow, timestamp pairing, hot-plug reattach, closing, open() and relay posting. The module was also run inside Pyodide 0.27.7 under Node against a JavaScript fake MIDIAccess and a real MessageChannel. It hasn't been tried against a real device in a browser yet.

@bdbarnett
bdbarnett merged commit 13cc131 into alignment/midi Oct 16, 2026
2 checks passed
@bdbarnett
bdbarnett deleted the ostinato/webmidi branch October 16, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant