Perfect Bluetooth MIDI For Windows

Bluetooth MIDI on Windows,
actually working.

A tiny Windows app that bridges a Bluetooth LE MIDI keyboard (Roland FP-90X, WIDI Master, CME, Yamaha MD-BT01, …) into the new Windows MIDI Services stack — so any DAW or Chrome Web MIDI site (like Midiano) can use it as if it were wired.

Download for Windows View on GitHub MIT licensed · single .exe · Windows 11
Perfect Bluetooth MIDI For Windows — main window with loopback endpoint picker, BLE scan/connect, TX channel selector, on-screen piano, and activity log.

What makes this one work

Bluetooth LE MIDI on Windows is a minefield of silent-failure modes — packets return Success at the ATT layer while the device ignores them, pairings that don't encrypt, receive channels that aren't the advertised transmit channel. This app handles each of those explicitly.

Windows MIDI Services loopback

Piggybacks on the new WMS stack. Works with both MIDI 2.0 UMP loopback pairs and the MIDI 1.0 "BLOOP" basic loopback. Apps see the bridge as a normal virtual MIDI device.

🎹Per-device channel detector

Some pianos (FP-90X) silently receive on a channel that isn't the visible Transmit Channel. Click Detect…; the app plays N ascending notes on each channel 1..16. Count the notes you hear = the receive channel. Saved per BLE MAC.

🔒Correct pairing + write mode

Pair proactively before enabling notifications (several BLE-MIDI devices drop MIDI on an unencrypted link while still returning Success at ATT). Prefer WriteWithResponse; some firmware silently drops WriteWithoutResponse.

On-screen piano + CLI

Avalonia UI with a bidirectional on-screen keyboard for quick testing — plus a headless CLI mode (--scan, --connect, --detect-channels, --phase N) for scripted debugging of new devices.

📜Readable diagnostics

Activity panel with a Verbose toggle — shows status-byte names and hex for every message, plus the full GATT service/characteristic tree on connect. Save log… writes it to a file you can share.

🧹Clean quit

Exit unpairs the device so your phone / another PC can take it over, instead of leaving Windows stuck bonded to the keyboard. Tray mode is explicit — the X button actually exits.

The quirk Most BLE-MIDI "PC→piano silent" bugs aren't BLE bugs

After ruling out pairing, encryption, proprietary ISSC characteristics, and write-mode quirks on a Roland FP-90X, it turned out the piano receives MIDI on channel 4 while its front-panel Transmit Channel shows 1. Every NoteOn we were sending on channel 1 was accepted by the GATT layer and silently dropped by the piano's MIDI engine. No error, no clue.

The built-in Detect… button nails this in about 75 seconds without any DAW setup. The fix is persisted per BLE MAC, so you do it once per device and never think about it again.

Setup in four steps

One-time, about five minutes total. Full instructions and troubleshooting are in the README.

Install Windows MIDI Services

WMS ships with recent Windows 11 updates. If midi --version fails in a terminal, install it from the Microsoft MIDI releases page. On first launch of the app, Windows will also prompt to download the .NET 10 Desktop Runtime if it isn't already installed — one click from the built-in dialog.

Create a loopback endpoint

Open MIDI Settings from the Start menu → Create loopback pair → root name BT-MIDI Bridge. Or from a terminal: midi loopback create --root-name "BT-MIDI Bridge".

Download and run the app

Grab PerfectBluetoothMidi.exe from Releases. Single ~21 MB file — put it anywhere and double-click. No installer.

Scan, connect, (optional) detect channel

Put your BLE-MIDI device into advertising mode, click Scan, pick it from the list, click Connect. If nothing sounds when you press keys: click Detect… next to the TX channel dropdown and pick the channel with the audible burst.

Try it with Midiano tip

app.midiano.com is a beautiful Chrome Web MIDI app with a nice catalogue of songs that play themselves on your piano. Open it in Chrome / Edge, pick the opposite-side loopback endpoint (the app's card 1 tells you which name) as the MIDI output, and hit play on any song — your keyboard plays it.