Changelog¶
All notable changes to osc-bridge. Format loosely follows
Keep a Changelog. Version numbers follow
Semantic Versioning: MAJOR.MINOR.PATCH.
Until 1.0.0 the schema and runtime are still stabilising — expect
additive minor bumps every time a new device class surfaces something
the JSON can't yet express. Backwards-compat of existing device JSONs
is tracked explicitly under each release.
[0.13.0] — 2026-10-22¶
The catalogue catches up with MIDI Guide — 132 new drivers, drum machines addressable by sound name — and its community data is now properly licensed.
Added — named drum sounds (triggers)¶
- New optional
triggersblock in device JSONs: each note-triggered sound (drum voice, sample slot) gets an OSC address, e.g./drm1_mkiv/drum/kick.<address> [velocity] [note] [channel]sends the documented Note On; the note is range-checked, velocity defaults to 100. list_routes(MCP) returns the triggers of a device.- 15 drivers ship with a drum map (476 named sounds): Roland TR-8S, TR-1000, T-8; Elektron Analog Rytm MKII, Digitakt II, Syntakt, Model:Samples; KORG drumlogue; Behringer LM Drum; Vermona DRM1 MKIV; Alesis SR-16; Novation DrumStation; and more, plus the General MIDI percussion map.
Added — catalogue API for agents¶
list_devices(MCP) takes optionalquery,vendor,kindandlimit, and reports the firmware version a driver's source documents.osc-bridge mcp --http <host:port>: MCP over HTTP (endpoint/mcp, JSON responses), offering only the read-only catalogue tools.- The site publishes a static JSON API:
/api/v1/index.json(every driver with source, firmware and coverage) and each driver file under/api/v1/devices/.
Added — hardware detection¶
osc-bridge detectand thedetect_hardwareMCP tool: list MIDI ports, send the standard Identity Request, read manufacturer / model / firmware, match the catalogue (port name, manufacturer ID, driver slug) and return a ready-to-runosc-bridge runcommand with the right port numbers.
Added — SysEx librarian¶
osc-bridge backup/restoreand thebackup_presets/restore_presetsMCP tools: record a device's dump to a.syxfile and send it back, paced. Ports by index or name fragment.restore_presetsrefuses unlessconfirm_overwrite: true(destructive hint set).- The MCP server now exposes eight tools.
Changed — catalogue¶
- Resynchronised with MIDI Guide (pencilresearch/midi @ 91299d6): 244
drivers refreshed, 132 devices added as
<slug>.pencilresearch.fw-unknown.json(one source per file). Catalogue: 963 devices, 212 vendors, 981 driver files. scripts/import_pencilresearch.py --syncreplaces--bulk, which overwrote existing files. The sync refreshes MIDI Guide-only drivers in place (following upstream renames), keeps hand-added fields such asexpects, never touches the data of drivers mixing several sources, and applies the catalogue's structuralexpectsrule to new entries.- MCP: when several driver files share a slug, the most trustworthy source now wins (verified, then vendor doc, then OSC API, then Electra, then MIDI Guide) instead of whichever file was read first.
- Modbap Trinity moved from
devices/unknown/todevices/modbap/.
Fixed — MCP through npm¶
- The npm package now ships the device catalogue, and the binary finds it
next to itself (
src/catalogue.rs: current directory,$OSC_BRIDGE_HOME, then beside the executable). Before,npx @roomi-fields/osc-bridge mcpstarted from a client's working directory saw an empty catalogue, and--device devices/…only worked from a checkout. /bridge/statusand/bridge/docsare answered straight to the sender, not only to the configured--osc-clients — the MCPget_statustool asks from its own port and never got a reply.
Security — WebSocket origin check¶
- The WebSocket transport (0.12.0) accepted any browser page: a website open
in the same browser could drive your synths while
--ws-bindwas on. The handshake now refuses (403) origins other than pages served from this machine; non-browser clients are unaffected.--ws-allow-origin/ws_allow_originsadd trusted origins (nullforfile://,*for any).
Changed — MCP¶
- A tool that fails now answers with
isError: trueand the reason in its content, as the MCP spec asks, so the model can read it and react; only an unknown tool name is a protocol error. - A
Dockerfile(andglama.json) runs the MCP server in a container with the catalogue, for directories that evaluate servers by running them.
Fixed — licensing¶
- MIDI Guide data is CC BY-SA 4.0 (it was declared MIT in
sources.toml). Every MIDI Guide source entry now recordslicenseandattribution, and the README credits MIDI Guide and documents the adaptation.
Compatibility¶
- Device JSONs: additive (
triggersis optional). Existing driver paths are unchanged except Modbap Trinity.
[0.12.0] — 2026-08-20¶
Browser clients join the bridge: a WebSocket transport carries OSC to and from web pages, which cannot speak UDP.
Added — WebSocket transport¶
run --ws-bind <ADDR:PORT>and, for the orchestrator,ws_bindin the[osc]section ofbridge.toml: an optional WebSocket listener, disabled by default.- Binary WS frames are raw OSC packets — byte-identical to the UDP transport (rosc encoding), no JSON envelope, so one OSC codec serves both transports. Text frames are ignored with a warning.
- A connected WS client is equivalent to a dynamic
--osc-client: it receives every outbound message (decoded MIDI-in, SysEx replies,/bridge/statusresponses) and its frames go through the exact same dispatch as OSC over UDP — on all three loops (runfor MIDI devices,runfor OSC-transport devices,orchestrateincl. inter-device routes). - Synchronous
tungstenite(one accept thread, one thread per connection) — no async runtime, matching the existing thread-based architecture. A slow client drops frames past a 256-message backlog instead of stalling the bridge; disconnected clients are pruned silently. - First consumer: browser-based Web Audio instruments driven by hardware controllers through the bridge (#1).
Compatibility¶
- Device JSONs: unchanged — every
0.11.xdriver loads and emits identically; the catalogue is untouched. - CLI / config: purely additive. Without
--ws-bind/ws_bind, behaviour is byte-for-byte identical to0.11.0.
[0.11.0] — 2026-06-24¶
Adds a control-nature hint to the device surface, so a caller can tell what each control expects without guessing from the range alone.
Added — surface schema¶
- Every surface entry (
cc_params.entries[]and SysExparams.entries[]) may carry anexpectsfield describing the device-side nature of the control:continuous(default),switch,momentary,trigger,clock,discrete. - It is purely informative: osc-bridge emits the exact same bytes regardless
and adds no runtime behaviour. The signal realization (CV / Gate / Trig /
Clock) is the caller's concern — osc-bridge stays universal and only states the
device-side expectation. The field is open (any string is accepted) and the
recommended vocabulary is documented in
DEVICE_JSON_SCHEMA.md. list_routes(MCP) now returnsexpectson every cc/sysex entry; the livedevices.jsonindex carries per-nature counts.- Catalogue-wide structural pass: 1363 entries across 96 drivers annotated from
unambiguous structure — binary
[0,1]controls →switch(564), small-range NRPN/SysEx steppers →discrete(799). Hand-annotated Subsequent 37 (switches, stepped selectors, arpeggiator/panic triggers) and Osmose (pedals → momentary). momentary/trigger/clockare not auto-detected (name-based guessing mislabels envelope sustain as a pedal, etc.) — they staycontinuousuntil a driver is reviewed by hand.
Compatibility¶
- Device JSONs: unchanged behaviour — every unannotated entry is
continuous, so all0.10.xdrivers load and emit identically. The 849-driver catalogue is byte-compatible at runtime.
[0.10.1] — 2026-05-14¶
A polish release for the MCP server. No device-JSON or runtime changes.
Changed — MCP server¶
- All five tools now declare an
outputSchemaandannotations(title + read-only / idempotent / open-world hints). Tool results carrystructuredContentalongside the text block, so MCP clients get a typed, machine-readable payload — not just prose to re-parse. - Protocol version advertised at
initializebumped to2025-06-18(the revision that introducedoutputSchema/structuredContent).
Compatibility¶
- Device JSONs: unchanged — every
0.10.0driver loads as-is. - MCP clients on the older
2025-03-26revision still work; the text block in every tool result is unchanged.
[0.10.0] — 2026-05-14¶
osc-bridge stops being a hardware-only tool. A new OSC transport lets a driver target a software endpoint — a DAW or a live-coding environment — behind the same named OSC surface as a synth. Eight software targets ship in this release. The multi-device orchestrator gains full dispatch and declarative inter-device routing. And the whole 849-device catalogue is now reachable from an LLM through a built-in MCP server.
Added — OSC transport (software targets)¶
device.transportblock:kind = "osc"routes a driver to a UDP/OSC endpoint instead of a MIDI port (host/port/reply_port).Command.forward— emit a templated OSC message (typed args,{name}placeholders) to the target; the OSC-mode counterpart offrame.subscriptions[]— one-shot OSC emitted at startup, e.g. to subscribe to a DAW's state changes.replies[]extended withmatch_osc+match_args— decode an incoming OSC message from the target back into the device's named surface.transport.passthrough_prefix— passthrough mode for environments with a user-defined OSC surface: forward everything under/<prefix>/...verbatim, no per-command modelling.- New source tiers:
📡 vendor-osc-api,📡 third-party-osc, and✅ software-verified(tested end-to-end against a running instance of the host software).
Added — software drivers¶
- Ableton Live via AbletonOSC — ✅ software-verified on Live 12.2.7.
- Bitwig Studio (DrivenByMoss) and Reaper (native OSC) — declarative.
- Sonic Pi, SuperCollider, Pure Data, TouchDesigner, VCV Rack — passthrough.
- Each ships a companion
.mddocumenting host-side setup, ports, conventions.
Added — orchestrator¶
- Full dispatch:
osc-bridge orchestratenow runs the same command / param / cc_param / midi_out pipeline as single-device mode, not just perf-MIDI. - Loads OSC-transport (software) devices alongside hardware MIDI devices in
a single
bridge.toml. [[routes]]— declarative inter-device routing with optional linear value remap (map.from/map.to). Routes fire on any event the bridge emits, including MIDI-in knob turns and software replies./bridge/docsserved in orchestrator mode (was single-device only).bridge.tomldevice entries can override an OSC driver'shost/port/reply_port.
Added — MCP server¶
osc-bridge mcp— a Model Context Protocol server (JSON-RPC over stdio). Five tools:list_devices,get_device_docs,list_routes,send,get_status. Both a MIDI MCP (hardware over MIDI/SysEx) and an OSC MCP (DAWs and live-coding environments).- Catalogue index built once at startup — device tools don't re-walk the
devices/tree on every call.
Added — distribution¶
@roomi-fields/osc-bridgenpm wrapper:npm installdownloads the prebuilt native binary for the platform from the matching GitHub release.server.json(Official MCP Registry) and.claude-plugin/plugin.json.scripts/sync_version.py—Cargo.tomlis the single version source of truth, propagated to every manifest mirror; CI gate fails on drift.
Added — devices & docs¶
- Arturia MatrixBrute promoted to hardware-verified-partial (fw
2.0.3.1411): 78 hierarchically-named CC params, 39 global options as a
paramsblock (0x42/0x43), 2 SysEx preset commands, 2 reply patterns. - Ableton Push 3 hardware-verified driver (Control Mode, USB-C).
docs/TUTORIAL_FIRST_DEVICE.md— a 30-minute hands-on "first device JSON".- Pages site: Author column added,
📡 OSC-APIfilter chip.
Changed¶
- Per-variant driver convention — one source per JSON file, never
silently fused. Variants named
<device>.<source-tier>.fw-<version>.json;regen_supported_devices.pygroups them under one catalogue entry. Beetlecrab Tempera rewritten from the vendor doc (fw 2.2) as the reference. _sources[].type "electra-preset-private"normalised toelectra-presetacross 191 devices — a single Electra-preset tier; provenance still carried per entry byurl/preset_id.
Backwards compat¶
All existing device JSONs load unchanged — every new field is optional
(device.kind, transport, forward, subscriptions, match_osc,
passthrough_prefix). The hardware MIDI drivers are byte-for-byte unaffected.
Test suite: 131 passing.
[0.9.0] — 2026-04-14¶
Reconfigurable controllers become first-class citizens, driven by the Electra One MK2 as the hardware-verified reference. The Lua scripting subsystem grows from a narrow escape hatch (per-field transforms) into a full device-driver substrate — persistent state, native JSON, dynamic routing, multi-block SysEx emission, outbound OSC — all proven end-to-end against real hardware (firmware 4.1.4).
Added¶
src/routing.rs—DynamicRouteswith page-aware CC↔OSC lookup, mutable at runtime underArc<Mutex<_>>.- Scripting extensions (
src/scripting.rs): - Persistent per-device state (
ob.state). - Native JSON codec (
ob.json_decode/ob.json_encode). - Execution profiles (
Default10 ms / 1 MiB vsPresetIngest500 ms / 4 MiB). - Dynamic route registration (
ob.register_cc_route,clear_routes,set_current_page,get_current_page,list_routes). - Multi-block SysEx emission (
ob.emit_sysex). - Outbound OSC emission (
ob.emit_osc) for introspection. log_warn/log_error.- Device schema:
custom_commands(scripted OSC endpoints with no declarative frame), auto-loaded companion<stem>.mdserved via/bridge/docs. - Runtime:
try_dynamic_cc_in/try_dynamic_osc_outhelpers consulted ahead of the declarative pipeline;reply.scriptwired through withctx.bindings;/bridge/docsendpoint. - Electra One MK2 driver (
devices/electra-one/): /preset/uploadcustom_command — parses an Electra preset, rebuilds CC routes, sets current page, emits the SysEx data block (0x01 0x01) to the device./routes/list,/preset/current,/page/currentintrospection.- Reply script on
/page/switchedkeepingcurrent_pagein sync. electra-one.mdintegration guide served over/bridge/docs— hardware-verified against firmware 4.1.4.- CLI:
osc-send --from-file <path>for loading large string args (preset JSON) without shell quoting hell. - Tests:
routing(6),dynamic_routing(7),custom_commands(3),electra_one_driver(12), plus expandedscripting(27). Total 100.
Hardware-verified¶
- Electra One MK2 (firmware 4.1.4, serial EO2-4312746f, hw rev 3.0) — upload round-trip, route registration, pot mapping, SysEx ACK/NACK flow, all introspection endpoints, and rendering of all control types (fader, list, pad, adsr, adr, dx7envelope). Bumped from 📘 vendor-doc to ✅.
Known caveats (documented in the companion guide)¶
- Midir/Windows truncates incoming SysEx at 1024 bytes, affecting
/preset/geton large presets (the device side is fine). inputs: [{potId, valueId}]mandatory on every Electra control.- Colors must be hex 6-char (no palette names).
- Upload targets the currently-selected slot — pair with
arm_upload. - Envelope segments cycle via a touch-and-hold gesture, not multi-pot binding.
[0.8.0] — 2026-04-13¶
Massive library expansion via Electra One community presets — and a generic multi-source ingest pipeline.
Added¶
sources.toml— central declaration of every bulk-import source the project knows about. Currently:pencilresearch(git) andelectra-one-public(Firestore).scripts/sync_sources.py— generic driver that dispatches each source to the right module underscripts/sources/(git, firestore, …).scripts/sources/firestore.py— Firebase login + Firestore listing/fetch with predicate filtering and incremental skip.scripts/import_electra_preset.py— converts an Electra One preset (schemaVersion 2/3 — Editor "tiles" layout) into an osc-bridge device JSON. Handles cc7 / cc14 / nrpn / sysex inline message types. Auto-merges into existing devices when vendor + name match strictly; otherwise creates a new entry. SysEx common-prefix factored into the device'ssysex.header.scripts/enrich_electra_authors.py— second pass that resolves each imported preset'suserId→ display name and writes it into_sources[].authorfor credit.- New status marker 🎛️ electra-preset in
regen_supported_devices.pyto distinguish community Electra presets from manufacturer docs.
Imported¶
- +464 new devices, +95 enriched existing pencilresearch devices, from the 636 public Electra One presets. 71 skipped (Lua-only utilities with no MIDI bindings).
- Library size: 331 → 795 devices across 117 vendors.
- Notable additions: every Sequential Prophet (incl. Prophet-5/10 Rev4, Prophet 6, OB-6, OB-X8), MatrixBrute, Hydrasynth, Access Virus A/TI, Waldorf Iridium / Blofeld, Korg Wavestate, Elektron Digitone / Syntakt / Octatrack, Dreadbox Nymphes (+SysEx layer), and ~450 more.
Schema¶
_sources[]entries gain an optionalauthorfield when the source istype: "electra-preset". Each Electra import cites the preset URL, ID, revision, and the author's display name (credit only — no internal account identifier is stored).
Backwards compat¶
All previously-shipped devices continue to load. Existing pencilresearch
JSONs that gained an Electra layer keep their original _sources[] entry
(pencilresearch reference now appears alongside the Electra one).
[0.7.0] — 2026-04-13¶
Mass device library: 331 devices across 102 vendors.
Added¶
- Bulk import of pencilresearch/midi —
326 new devices generated from the canonical community CSV collection
(commit
deb41f2). Moog (13), Roland (37), Elektron (16), DSI (9), Sequential (7), Yamaha (7), Waldorf (8), Novation (8), Behringer (6), Dreadbox (3), and ~80 more vendors. 7 empty-skeleton CSVs skipped. scripts/import_pencilresearch.py— single-CSV, bulk, and--updatemodes. Records the upstream commit SHA in_sources[0].commitso re-imports can diff against a precise baseline. Preserves custom extensions (SysEx layer, replies, custom commands) across re-imports.scripts/regen_supported_devices.py— rebuildsdocs/SUPPORTED_DEVICES.mdfrom everydevices/**/*.json, grouped by vendor alphabetically. Single source of truth = the JSONs.- Schema:
_source(string) deprecated in favour of_sources(array of{type, url, commit?, imported_at}). Multiple sources can coexist (e.g. pencilresearch CC/NRPN baseline + vendor-doc SysEx layer). The legacy_sourcefield is still read for backwards-compat. - CI step: regenerates
SUPPORTED_DEVICES.mdand fails on diff — contributors must keep the catalogue in sync. - GitHub topics added for discoverability: osc, midi, sysex, hardware-synth, moog, arturia, novation, sequential, korg, roland, yamaha, elektron, dave-smith-instruments, waldorf, dreadbox, erica-synths, polyend.
- README compacted: a 3-row summary instead of an unbounded table.
Full catalogue lives in
docs/SUPPORTED_DEVICES.md.
Known limitations¶
Pencilresearch-imported devices are CC/NRPN only. SysEx (preset
management, display control, vendor-proprietary opcodes) is NOT
covered for those 326 devices — the _limitations field spells it out.
Extending a device with SysEx on top of the imported base is a
first-class contribution path; see CONTRIBUTING.md and the
update_device.md PR template.
[0.6.0] — 2026-04-13¶
Kanopi integration: N/N bridge — performance MIDI + multi-client + multi-device.
Added¶
midi_outoptional section on every device. When present, activates standard OSC performance routes automatically:/note/on,/note/off,/pitchbend,/aftertouch,/poly_aftertouch,/cc/{num},/program_change. Supportsdefault_channelandnote_offset(drum-machine mappings)./bridge/statusRPC endpoint — emits one/bridge/status/device <slug> okOSC message per active device to every configured client. Lets Kanopi verify the setup at boot.--osc-clientis now repeatable. Every listed client receives a copy of each outbound event.RuntimeOptions.osc_client: Option<...>→RuntimeOptions.osc_clients: Vec<SocketAddr>.- New subcommand:
osc-bridge orchestrate --config bridge.toml. Drives N devices in one process, dispatched byosc_prefix. Each entry can override the device's defaultosc_prefix(useful when two instances of the same model are wired up — e.g./matrixbrute-1//matrixbrute-2). Rate-limited per device, MIDI-in events emitted with the right prefix. docs/CR-kanopi-gaps.md— design rationale.examples/bridge.toml— sample orchestrator config.- Added
toml = "0.8"dependency.
Backwards compat¶
All existing device JSONs load unchanged. Zero regression on prior tests
(24 → 42 passing). CLI breaking change on --osc-client: the flag is
now a Vec, so passing it once still works as before; passing it
multiple times is the new feature.
[0.5.0] — 2026-04-13¶
Architecture: Lua scripting escape hatch.
Added¶
mlua(Lua 5.4 vendored) as an optional runtime dependency.src/scripting.rs— sandboxedScriptEnginewith 1 MiB memory cap, 10 ms deadline via instruction hook,ob.*helper library (u7_clamp,u14_lsb/msb,checksum_xor/sum,log). Loaders,os,io,debug,package,requireare stripped.- Schema: optional
transform/transform_reverseonParamEntryandCcParamEntry; optionalscriptonCommandandReplyPattern(the latter reserved). - Runtime wiring:
transformapplied pre-clamp on CC + SysEx param paths;scriptrun post-build on commands. Engine is lazy-init — devices without scripts pay zero overhead. osc-bridge lint <device.json>— validates schema, warns on every use oftransform/scriptper the design CR.devices/examples/scripted-example.jsonwith 3 integration tests.docs/scripting.mduser guide.
Backwards compat¶
All existing device JSONs load unchanged. 24 pre-existing tests green.
[0.4.0] — 2026-04-13¶
Novation Launch Control XL 3 (doc-derived).
Added¶
devices/novation/launch-control-xl-3.json— 6 SysEx commands (DAW mode on/off, RGB LED per control, display configure/text/bitmap)- 69 CC entries (12 feature controls + 57 palette-index LED setters)
- bitmap-ack reply. CC numbers cross-checked against Novation's published surface diagram PNG.
tests/launch_control_xl_3.rs— 8 integration tests verifying SysEx bytes against the reference guide.- README: Novation row added with source + entry count.
[0.3.0] — 2026-04-13¶
Electra One MK2 (doc-derived).
Added¶
devices/electra-one/electra-one.json— 31 SysEx commands (query preset/runtime/config, preset/page/control-set switch, display text, Lua eval via/lua, reboot, destructive ops) + 12 inbound events decoded viareplies(ACK/NACK, switch events, pot touch, list-change notifications).tests/electra_one.rs— 9 integration tests.- README: Electra One row + updated "Source" column distinguishing hardware-verified from doc-derived.
[0.2.1] — 2026-04-13¶
Honesty pass: exhaustive doc-derived maps, explicit source tracking.
Changed¶
- Polyend Synth: 110 → 195 CC entries (previously 85 silently skipped). Parsed via fixed-column layout from the official PDF. All 8 engines fully covered.
- Moog Subsequent 37: cleaner OSC naming (dropped redundant section prefix from param names).
- README: added explicit
Sourcecolumn (hardware-verified vs doc-derived) and per-device entry counts.
[0.2.0] — 2026-04-13¶
Schema extension: 14-bit CC pairs + NRPN addressing.
Added¶
- Moog Subsequent 37 (131 params: 89 CC, 98 NRPN, 31 as 14-bit CC pairs).
CcParamEntrygains optionalcc_lsb,nrpn_msb,nrpn_lsbfields. Runtime emits the correct MIDI sequence per entry: single CC, 14-bit CC pair, or full NRPN (CC 99/98/6 + CC 38 when 14-bit).
Backwards compat¶
Existing devices with single-CC entries continue to work unchanged;
the new fields are all Option<u8> with #[serde(default)].
[0.1.1] — 2026-04-13¶
Added¶
- Polyend Synth device (110 CC-mapped params across 8 engines,
program-change command). First CC-only device —
cc_paramssection introduced in the schema.
[0.1.0] — 2026-04-12¶
Initial public release.
Added¶
- Skeleton declarative bridge: OSC ↔ MIDI/SysEx driven by
devices/<vendor>/<name>.json. - Hardware-verified Arturia MiniLab 3 (264 SysEx params + 6 commands
- MIDI-in feedback, Ghidra static + empirical fuzz).
- CLI:
list,inspect,run,osc-send,osc-listen. - GPL-3.0 licence (inherits from the
sysex-controlsreverse engineering that seeded the MiniLab 3 parameter table).