react-native-midi-api
v0.1.0
Published
A native Web MIDI API polyfill for React Native (iOS, Android & Web) — talk to USB & BLE MIDI hardware with the standard requestMIDIAccess surface. Drop-in replacement for @motiz88/react-native-midi.
Downloads
843
Maintainers
Readme
react-native-midi-api
A native Web MIDI API polyfill for React Native — talk to USB & BLE MIDI hardware from iOS, Android, and Web with the standard requestMIDIAccess surface. MIDI 1.0 + SysEx.
Built as a modern, maintained drop-in replacement for the abandoned @motiz88/react-native-midi: same public API, correctness improvements (stable port maps, standard MIDIMessageEvent), and no third-party native MIDI pod.
Platform support
| Platform | Transport | Minimum version | Status |
| --- | --- | --- | --- |
| Web | navigator.requestMIDIAccess (browser Web MIDI passthrough) | Any Web-MIDI-capable browser | ✅ |
| iOS | CoreMIDI — USB-MIDI | iOS 14+ | ✅ |
| Android | android.media.midi — USB-MIDI | API 24+ (Android 7) | ✅ |
| BLE-MIDI | Bluetooth LE MIDI | — | 🔜 planned — PRs welcome! |
BLE-MIDI note: The consuming app can do BLE MIDI separately today via
react-native-ble-manager. Native BLE-MIDI transport integrated directly into this library is planned. See the tracking issue Odisei-Music/Odisei-Play#1143 — contributions welcome.
Install
npx expo install react-native-midi-api
# or
npm install react-native-midi-apiThis is an Expo module. In a managed Expo or Expo-prebuild app it autolinks with no extra steps. In a bare React Native app, follow installing Expo modules once, then npx pod-install for iOS.
Peer dependencies: expo, react, react-native — these must be present in the consuming app (never auto-installed).
Usage
import { requestMIDIAccess } from "react-native-midi-api";
import type { MIDIMessageEvent, MIDIConnectionEvent } from "react-native-midi-api";
// Request access (sysex: false by default).
const midi = await requestMIDIAccess({ sysex: false });
// Enumerate connected inputs and attach listeners.
for (const input of midi.inputs.values()) {
console.log("Input:", input.name, input.manufacturer);
input.onmidimessage = (event: MIDIMessageEvent) => {
const [status, data1, data2] = event.data; // Uint8Array
console.log("MIDI in:", status.toString(16), data1, data2);
};
}
// Enumerate connected outputs and send a Note On
// (channel 1, note 64, velocity 127).
const output = [...midi.outputs.values()][0];
output?.send([0x90, 0x40, 0x7f]);
// Schedule a Note Off 500 ms from now.
output?.send([0x80, 0x40, 0x00], performance.now() + 500);
// React to devices connecting / disconnecting (hotplug).
midi.onstatechange = (event: MIDIConnectionEvent) => {
const port = event.port;
console.log(port?.name, "→", port?.state, port?.connection);
};The surface mirrors the W3C Web MIDI API — refer to the MDN docs for full semantics.
Requesting SysEx access
System Exclusive (0xF0 … 0xF7) messages require explicit opt-in:
// Enable SysEx in both directions.
const midi = await requestMIDIAccess({ sysex: true });
// Send a SysEx message.
output?.send([0xf0, 0x41, 0x10, 0x00, 0x00, 0x00, 0x28, 0x12, 0xf7]);
// Inbound SysEx arrives through onmidimessage as normal.
input.onmidimessage = (e: MIDIMessageEvent) => {
if (e.data[0] === 0xf0) console.log("SysEx:", e.data);
};Without
{ sysex: true }, callingsend()with a0xF0start byte throwsInvalidAccessError, and incoming SysEx bytes are filtered out silently. This gating applies in both directions — outbound and inbound.
API
Full API reference (all exports, type signatures, and TSDoc annotations) is available at midi.odiseimusic.com (coming soon — the site builds from source on every merge to main).
Quick reference
| Export | Kind | Notes |
| --- | --- | --- |
| requestMIDIAccess(options?) | function | { sysex?, software? } → Promise<MIDIAccess>. On Web, resolves the browser's native access. |
| MIDIAccess | interface | inputs / outputs (stable ReadonlyMaps), sysexEnabled, onstatechange, statechange event. |
| MIDIPort | interface | id, manufacturer, name, type, version, state, connection, open(), close(), onstatechange. |
| MIDIInput | interface | Extends MIDIPort; onmidimessage + standard midimessage event. |
| MIDIOutput | interface | Extends MIDIPort; send(data, timestamp?), clear(). |
| MIDIInputMap / MIDIOutputMap | type | ReadonlyMap<string, MIDIInput | MIDIOutput>. |
| MIDIMessageEvent | class | Standard event; .data: Uint8Array, .receivedTime. |
| MIDIConnectionEvent | class | Standard event; .port: MIDIPort | null. |
| MIDIOptions | interface | { sysex?: boolean; software?: boolean }. |
| InvalidAccessError / InvalidStateError | class | Thrown for disallowed SysEx / disconnected-port sends. |
| validateMidiMessage / getChannelMessageLength | function | Low-level helpers for parsing raw MIDI bytes. |
Platform notes
- Web: Requires a Web-MIDI-capable browser (Chrome / Edge). Safari does not support Web MIDI natively — a MIDI polyfill extension may be needed.
- iOS: Requires iOS 14+. CoreMIDI is the underlying transport. USB-MIDI devices are plug-and-play. No external native pod is required.
- Android: Requires API level 24+ (Android 7 Nougat). Uses the
android.media.midisystem API. USB-MIDI devices are plug-and-play.
Contributing
Bug reports and pull requests are welcome on GitHub. Please follow the Conventional Commits style used in this repo.
BLE-MIDI is explicitly unimplemented and contributions for it are especially welcome. Please open an issue to discuss the approach before sending a large PR, so we can align on the transport design.
Acknowledgments
@motiz88/react-native-midi(MIT, © 2022 Moti Zilberman) — the reference Web MIDI surface and Expo module structure this package is modeled on.SimpleEventTargetImplandvalidateMidiMessageare direct adaptations (the latter ultimately deriving from Chromium's BSD-licensed Web MIDI implementation). The Android MIDI framing logic (MidiConstants.kt,MidiFramer.kt,MidiMessageReassembler.kt) is adapted from the same upstream project's Android port, which itself derives from AOSP'sMidiFramer.java/MidiConstants.java. SeeNOTICE.react-native-audio-apiMIDI draft by Software Mansion (MIT, © 2024 Software Mansion) — architectural reference for the modern CoreMIDI integration approach. SeeNOTICE.
License
MIT © 2026 Odisei Music S.L.
