loading…
Search for a command to run...
loading…
OSC ↔ MIDI/SysEx bridge for 849 synths and DAWs — a MIDI MCP and OSC MCP.
OSC ↔ MIDI/SysEx bridge for 849 synths and DAWs — a MIDI MCP and OSC MCP.
Release CI License: GPL-3.0-or-later
Declarative OSC bridge for music hardware and software — and an MCP server to drive it from an LLM.
849 hardware synthesizers over MIDI / SysEx, plus DAWs and live-coding environments over OSC (Ableton, Bitwig, Reaper, Sonic Pi, SuperCollider, Pure Data, TouchDesigner, VCV Rack). Every device gets a clean, named OSC surface described by one JSON file. Drive it from a live-coding client, a DAW, a script, the CLI — or from Claude via the built-in MCP server (a MIDI MCP and OSC MCP).

As an MCP server — drive synths and DAWs from Claude, nothing to install:
npx -y @roomi-fields/osc-bridge mcp
As a standalone bridge / CLI:
npm install -g @roomi-fields/osc-bridge # downloads the prebuilt binary
# or grab a binary directly from the Releases page
osc-bridge run --device devices/arturia/minilab3.json --out-port 4
MCP client config and the five tools → docs/MCP.md. Full quick-start with MIDI port discovery → § Install & quick start.
Modern synths — hardware and software alike — expose themselves over MIDI, SysEx, and OSC with proprietary, scattered protocols. Using them from live-coding environments, a DAW, a script, or an LLM is painful:
osc-bridge gives every supported synth a clean, named OSC surface:
~mb = NetAddr("127.0.0.1", 7777);
~mb.sendMsg("/minilab3/knob/3/cc_number", 64); // reconfigure knob 3
~mb.sendMsg("/minilab3/pad/0/color", 127, 0, 0); // pad 1 red
~mb.sendMsg("/minilab3/display/text", "Hello", "World");
Each synth is described by one JSON file. No Rust recompile required to add a device.
osc-bridge run picks it up.osc-bridge mcp exposes the whole catalogue to Claude (or any MCP client) — a MIDI MCP and OSC MCP. Discover devices, read a device's OSC surface, send OSC to synths and DAWs. See docs/MCP.md._sources[]: ✅ hardware-verified, ✅ software-verified, 📘 vendor-doc, 📡 vendor-osc-api / 📡 third-party-osc, 🎛️ electra-preset, 📦 pencilresearch. You always know whether a mapping was tested on the device or lifted from a spec sheet.--osc-client flag.osc-bridge orchestrate --config bridge.toml), each reachable under its own OSC prefix — so two MatrixBrutes live side-by-side as /matrixbrute-1 and /matrixbrute-2./bridge/docs returns the integration guide, /electra1/routes/list returns the authoritative address table, so clients (or LLM-driven integrators) never hardcode slugification or protocol details. See § Reconfigurable controllers below.transform / per-command script runs Lua 5.4 sandboxed (1 MiB / 10 ms caps, no os/io/loaders). Used sparingly — osc-bridge lint warns on every script use — but it lets the declarative core stay small without giving up on edge cases. See docs/scripting.md.849 devices across 187 vendors — Moog · Arturia · Novation · Korg · Sequential · Dave Smith Instruments · Roland · Yamaha · Elektron · Waldorf · Behringer · Dreadbox · Erica Synths · Polyend · Modal · Expressive E · Bastl · Chase Bliss · Make Noise · Electra One · Tasty Chips · Oberheim · Access · ASM · Black Corporation · Hologram · Strymon · Empress · Meris · Eventide · Ensoniq · Rhodes · Haken · Tubbutec · Ableton · Bitwig · Cockos (Reaper) · Sonic Pi · SuperCollider · Pure Data · TouchDesigner · VCV Rack · and ~85 more.
| Status | Count | Highlight |
|---|---|---|
✅ Hardware-verified (tested on the physical device — scope varies per driver, see _sources in each JSON) |
4 | Arturia MiniLab 3 · Electra One MK2 · Ableton Push 3 · Arturia MatrixBrute (firmware-RE partial) |
| ✅ Software-verified (tested end-to-end against a running instance of the host software) | 1 | Ableton Live 12.2.7 (via AbletonOSC) |
| 📘 Vendor-doc derived (from manufacturer programmer's references — bytes match the spec) | 193 | Novation Launch Control XL 3 · Polyend Synth · … |
| 📡 OSC-API (software targets) — DAWs and live coding environments, declarative or passthrough | 7 | Bitwig Studio · Reaper · Sonic Pi · SuperCollider · Pure Data · TouchDesigner · VCV Rack |
| 🎛️ Electra-preset derived (from the Electra One community preset library — covers SysEx + CC/NRPN, author's editorial choices) | 398 | Prophet 5/10 · Prophet 6 · OB-6 · OB-X8 · Matriarch · Hydrasynth · Virus TI · Digitone · … |
| 📦 Pencilresearch derived (from pencilresearch/midi — CC/NRPN only) | 244 | Moog · Sequential · DSI · Roland · Yamaha · Waldorf · Behringer · Dreadbox · … |
| 🚧 WIP / 📝 stub | 2 | GR Mega (placeholder) |
Searching for your device?
Your synth isn't there, or a doc-derived entry (📘 / 📡 / 🎛️ / 📦) needs promoting to ✅ after you test it on hardware? See the next section.
New here? The 30-minute tutorial builds a working driver end to end. Otherwise — three common cases, pick yours:
Your synth isn't listed → open a PR adding devices/<vendor>/<slug>.json.
python3 scripts/import_pencilresearch.py <path-to-csv> — generates the JSON for you.devices/ as a template and follow docs/DEVICE_JSON_SCHEMA.md.cargo run --release -- lint <file> and cargo test --release.python3 scripts/regen_supported_devices.py to refresh the catalogue.new_device.md template.Your synth is listed but not yet ✅, and you have the hardware → PR promoting it to ✅. Test every route, attach the log, flip the marker. promote_to_verified.md template.
Your synth is listed but a CC is wrong / needs SysEx added → PR updating the JSON. update_device.md template. Especially welcome on pencilresearch-imported devices where SysEx needs to be layered in.
Full contributor guide (schema extensions, bug reports, Lua escape hatch) → CONTRIBUTING.md. For devices whose protocol can't be expressed declaratively, see docs/scripting.md — use sparingly; osc-bridge lint warns on every use.
Most synths have a fixed set of controls — MiniLab 3's knobs always mean the same thing. The Electra One MK2 is different: its 216 controls are defined by a preset that you upload to the device, and the meaning of every CC changes when the preset changes. A static JSON spec can't describe that; the bridge treats it as a first-class case.
This integration is what validates the whole Lua scripting subsystem in anger.
The MK2 driver exercises every feature of the scripting.rs layer on real
hardware (firmware 4.1.4, verified 2026-04-14):
ob.json_decode / ob.json_encode) — parses a full
Electra preset (up to 100 KB of nested pages/devices/groups/controls/overlays)
in a single Lua block, under the 500 ms preset_ingest profile.ob.state) — the driver stores the active
preset name so /electra1/preset/current can report it on demand.ob.register_cc_route /
ob.clear_routes / ob.set_current_page) — every preset upload rebuilds
the bridge's routing table from scratch, zero restart.ob.emit_sysex) — the upload script emits
the wrapped SysEx preset data block directly from Lua.ob.emit_osc) — powers the introspection
endpoints: /routes/list, /preset/current, /page/current.ctx.bindings) — when the device
reports a page switch over SysEx, a reply script updates the bridge's active
page so CC routing tracks the hardware UI automatically.devices/electra-one/electra-one.md is
loaded at startup and served over /bridge/docs, so LLM-driven integrators
read the device-specific quirks (hex-color requirement, inputs[{potId}]
mandatory, envelope-segment cycling gesture, MIDI port selection, etc.)
without any code-side knowledge.Every item above has a unit test, an end-to-end test against the real .json
driver, and a hardware-verified green light. If you're building a driver for
another reconfigurable controller (Faderfox custom, programmable MIDI Fighter),
the Electra driver is the template — copy its custom_commands block, adapt
the JSON→routes parsing to your device's preset format, done.
Kanopi / your client osc-bridge Electra One MK2
───────────────────── ──────────────── ────────────────────
/electra1/preset/upload ───► parse preset JSON (preset_ingest
"<preset JSON>" profile: 500 ms / 4 MiB Lua)
┌─ ob.clear_routes()
├─ ob.register_cc_route × N
│ (one per cc7 control,
│ per-page, with channel)
└─ ob.emit_sysex(…) ──────────► F0 00 21 45 01 01 <json> F7
(reconfigures device)
◄────────── F0 00 21 45 7E 01 … ACK
(user turns knob on page 2) ◄────────── B4 4A 53 (CC#74 ch5 = 83)
route lookup: page=2, ch=4, cc=74
→ /electra1/page2/cutoff 0.65 ───► /electra1/page2/cutoff 0.65
(user switches page on device) ◄────────── F0 00 21 45 7E 06 03 F7
reply.script fires:
ob.set_current_page(3)
───► /electra1/page/switched 3
Every piece of device-specific knowledge is exposed over OSC — clients never hardcode slugification rules, page indexing, or SysEx opcodes:
| Send | Receive |
|---|---|
/bridge/status |
One /bridge/status/device <slug> <status> per connected device |
/bridge/docs |
/bridge/docs/device <slug> <markdown> — full integration guide (the device's companion .md, loaded automatically) |
/electra1/routes/list |
N× /electra1/routes/entry <addr> <ch> <cc> <page> <min> <max> then /electra1/routes/done |
/electra1/preset/current |
/electra1/preset/current <name> |
/electra1/page/current |
/electra1/page/current <n> |
An LLM-driven integrator needs exactly four steps to go from cold start to
routing knob turns: /bridge/status → /bridge/docs → /electra1/preset/upload
→ /electra1/routes/list. Everything else is in the markdown guide embedded
in the bridge itself.
The machinery (DynamicRoutes, ob.register_cc_route, ob.emit_sysex,
custom_commands, companion .md auto-loading) is device-agnostic. Adding
a reconfigurable Faderfox, a custom MIDI Fighter Twister layout, or any
programmable controller is the same recipe: a preset-parsing Lua block inside
the device JSON that calls ob.register_cc_route per control. No core changes.
Grab the latest osc-bridge.exe (Windows), osc-bridge (Linux/macOS) from
the Releases page.
git clone https://github.com/roomi-fields/osc-bridge
cd osc-bridge
cargo build --release
./target/release/osc-bridge list
# 1. Find your MIDI port indices
osc-bridge list
# 2. Start the bridge
osc-bridge run --device devices/arturia/minilab3.json \
--out-port 4 --in-port 0 \
--bind 127.0.0.1:7777 --osc-client 127.0.0.1:8888
# 3. From another terminal, send OSC
osc-bridge osc-send /minilab3/display/text "Hello" "World"
osc-bridge osc-send /minilab3/pad/0/color 127 0 0
osc-bridge osc-send /minilab3/knob/3/cc_number 100
Incoming MIDI events (knob turns, pads played, pitch-bend, SysEx GET replies)
are forwarded to --osc-client as OSC:
/minilab3/cc/18 95 0 ← knob moved
/minilab3/note/on 60 127 0
/minilab3/param/value 0 7 0 0 1 ← reply from a /param/get
Since the March 2026 cumulative update (KB5079473), Windows 11 ships
Microsoft's new USBMidi2-ACX driver which enforces stricter USB descriptor
checks. Devices that pass the old checks but fail the new ones appear in
Device Manager with Status: Unknown, or bind to a driver that exposes
them only through the new MIDI Services API — invisible to midir (and
therefore to osc-bridge) which queries the legacy MME interface.
Confirmed affected: Polyend Synth / Play / Tracker / Mess / Step (VID 16D0). Likely affected: any older USB-MIDI device whose descriptor doesn't meet the new spec.
Workaround — force the legacy usbaudio driver:
osc-bridge list should now show the device.Track Microsoft's progress on KB5079473 if you want a permanent fix — Pete Brown (Microsoft) acknowledged the packet-size issue publicly but classified it as non-blocking. Polyend's firmware-side fix is not announced at the time of writing.
osc-bridge inspect devices/arturia/minilab3.json
osc-bridge osc-listen --bind 127.0.0.1:8888
osc-bridge osc-send /minilab3/raw/syx "F0 00 20 6B 7F 42 02 00 16 04 7F 00 00 F7"
A device file declares three things:
Example snippet (devices/arturia/minilab3.json):
{
"commands": [
{
"osc": "/pad/{pad}/color",
"args": [
{"name":"pad","type":"u7","range":[0,7]},
{"name":"r","type":"u7"},
{"name":"g","type":"u7"},
{"name":"b","type":"u7"},
{"name":"mode","type":"enum",
"values":{"user":0,"arturia":1,"daw":2},"default":"user"}
],
"pre": [{"bind":"pad_id","expr":"pad + 4"}],
"frame": [2, "{mode}", 22, "{pad_id}", "{r}", "{g}", "{b}"]
}
],
"params": {
"get_frame": [32, "{pr}", "{p}", "{c}", "{r}"],
"set_frame": [33, "{pr}", "{p}", "{c}", "{r}", "{val}"],
"value_type": "u7",
"entries": [
{"osc":"/global/backlight", "pr":7, "p":0, "c":0, "r":0, "range":[0,1]}
]
}
}
osc-bridge isn't only for hardware synthesizers. Since version 0.10 it also
treats DAWs and live-coding environments as first-class devices, behind
the same /<env> OSC surface as a Prophet or a Matriarch. A driver JSON
declares device.transport.kind = "osc" and the bridge forwards OSC to the
target's UDP port instead of going through a MIDI cable.
Two flavors:
Declarative drivers — when the host software has a fixed, documented OSC
surface (Ableton via AbletonOSC,
Bitwig via DrivenByMoss, Reaper's
native OSC). The driver enumerates commands[] with typed args, plus
replies[] for incoming events.
Passthrough drivers — when the host software has no fixed OSC surface and
each user defines their own paths in their project (Sonic Pi, SuperCollider,
Pure Data, TouchDesigner, VCV Rack). The driver just declares
transport.passthrough_prefix and the bridge forwards anything under
/<env>/... verbatim. Replies travel the other way with the prefix added back.
Currently supported:
| Target | Mode | Status |
|---|---|---|
| Ableton Live 12.2.7 + AbletonOSC | declarative | ✅ software-verified |
| Bitwig Studio + DrivenByMoss | declarative | 📡 third-party-osc |
| Reaper 7 (Default.ReaperOSC) | declarative | 📡 vendor-osc-api |
| Sonic Pi 4.5 | passthrough | 📡 vendor-osc-api |
| SuperCollider sclang 3.13 | passthrough | 📡 vendor-osc-api |
| Pure Data 0.55-x | passthrough | 📡 vendor-osc-api |
| TouchDesigner 2023 | passthrough | 📡 vendor-osc-api |
| VCV Rack 2.5 + community OSC plugin | passthrough | 📡 third-party-osc |
Each comes with a .md companion under devices/<vendor>/ that documents the
required setup on the host side (Remote Script installation, ports, conventions).
Combined with osc-bridge orchestrate, you can drive a hardware MiniLab 3,
an Ableton Live, and a Sonic Pi loop from a single process. With the
new [[routes]] section in bridge.toml, a knob turn on the MiniLab can
drive an Ableton track volume or a Sonic Pi cue, without writing any client
code:
[osc]
bind = "127.0.0.1:7777"
clients = ["127.0.0.1:8888"]
[[devices]]
spec = "devices/arturia/minilab3.json"
midi_out_port = 4
midi_in_port = 0
[[routes]]
from = "/minilab3/cc/74"
to = "/ableton/track/0/volume"
map.from = [0, 127]
map.to = [0, 1]
osc-bridge ships a Model Context Protocol server — a MIDI MCP and OSC MCP. Point any MCP client at it and the model can browse the 849-device catalogue, read a device's OSC surface, and send OSC to synths and DAWs.
{
"mcpServers": {
"osc-bridge": {
"command": "npx",
"args": ["-y", "@roomi-fields/osc-bridge", "mcp"]
}
}
}
Five tools — list_devices, get_device_docs, list_routes, send,
get_status. Then in conversation: "What can the MatrixBrute do? Sweep its
filter cutoff." — the model calls list_routes("matrixbrute"), then send.
No glue code.
Full setup — Claude Desktop / Cursor config, the workflow, driving software targets → docs/MCP.md.
Started as a MatrixBrute OSC driver (patch format reverse-engineered from the GPL-3 sysex-controls and the community MBPV tool). Grew into a generic declarative bridge once the Arturia protocol family became clear.
GPL-3.0-or-later. Inherits GPL obligations from the sysex-controls reverse
engineering that seeded our MiniLab 3 parameter table.
Выполни в терминале:
claude mcp add osc-bridge -- npx Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development