>_EXECUTIVE SUMMARY
ztranslator is a self-contained, real-time MIDI translation engine written in pure Rust, meant to be embedded inside a host GUI/CLI application. It listens on MIDI input ports (via midir), matches each incoming message against per-translator triggers, runs a rules script on a small signed-32-bit integer VM, and fires an outgoing action — one of 39 Outgoing variants spanning MIDI out (incl. 14-bit / NRPN), keystroke / mouse / AppleScript synthesis (macOS), MIDI route / port / project control, MIDI clock + MTC generators, MMC transport, OSC, Art-Net + sACN DMX, HTTP / WebSocket / MQTT / raw TCP, RTP-MIDI, Ableton Link, CV / gate, gamepad rumble, serial, file write, notify / speak / clipboard, timer, preset control, a host-defined custom command, and a stryke-script hook. Beyond MIDI it accepts 26 incoming trigger types (OSC, DMX, sACN, serial, gamepad, HID, MIDI clock, MTC, MMC, Ableton Link, audio amplitude/onset/pitch, CV/gate, cron schedule, system events, HTTP, TCP, WebSocket, MQTT, RTP-MIDI). It imports BOME MIDI Translator Pro .bmtp projects (INI container + MID3/KAM3 XML payloads + Options rules blob) and exports native projects back to unsigned .bmtp (round-tripping through import), with serde JSON as the native store. The crate carries no UI of its own: the host wires the engine's EngineEvent stream to its interface and routes Outgoing::Custom back through a handler. 9,925 source lines (8,484 code) across 20 Rust files, a worker-thread engine, a faithful BOME rules VM, lossless .bmtp import + export, and a broad protocol I/O layer — the routing core behind a MIDI-controlled desktop application.
Source Distribution — 9,925 lines
Library: 17 files under src/ (engine, rules VM, model, bmtp import/export, actions, protocol sources, midi, error). Tests: 3 integration modules under tests/ (bmtp_import.rs, engine_pipeline.rs, rules_vm.rs). Line counts are physical wc -l; code-only (tokei, blanks + comments excluded) is 8,484.
#SUBSYSTEM BREAKDOWN
Source partitioned by role. The engine (worker thread + dispatch + protocol sources + generators + timers) is the largest slice at 42.1%; .bmtp import + export is second at 15.5% because BOME's binary container format needs dedicated INI / XML / options parsers on the way in and an unsigned re-serializer on the way out. The data model is 13.3% as the trigger/action set expanded to 26 incoming + 39 outgoing variants. The rules VM is a self-contained 723-line interpreter.
| Subsystem | Key Files | Lines | % | Share | Description |
|---|---|---|---|---|---|
| Engine | engine/mod, engine/timers | 4,180 | 42.1% | Worker-thread engine: opens MIDI input ports (midir), runs the dispatch loop, hosts every non-MIDI trigger source (OSC / Art-Net / sACN / serial / gamepad / HID / HTTP / WebSocket / MQTT / TCP / audio / CV / Ableton Link / RTP-MIDI) and the MIDI clock + MTC generators, emits EngineEvents, routes Outgoing::Custom to the host, applies outgoing delay, and schedules timers | |
| .bmtp Import / Export | bmtp/mod, bmtp/options, bmtp/payload, bmtp/export | 1,540 | 15.5% | BOME MIDI Translator Pro project I/O: INI container, MID3/KAM3 XML payloads, timer/EnDi payloads, and the Options rules blob on import; unsigned .bmtp re-serialization on export (round-trips through import). RSA signature ignored; undecoded encodings preserved verbatim for lossless round-trip | |
| Data Model | model | 1,323 | 13.3% | Project → Preset → Translator, each translator carrying one of 26 Incoming triggers and one of 39 Outgoing variants. serde-serializable (snake_case tagged enums); native projects via Project::load_json / save_json | |
| Rules VM | rules | 723 | 7.3% | Faithful BOME rules implementation on a signed-32-bit integer VM: assignment, arithmetic (+ - * / %) + bitwise (& | ^ >> <<), IF/THEN with 6 comparators, Goto/Label, Skip Next [n], Log, exit-and-execute/ignore. 10 locals + two-character globals; wrap-on-overflow; div/mod by zero = 0 | |
| Actions | actions/mod, actions/macos, keycodes | 716 | 7.2% | Outgoing OS-control actions: keystroke / mouse (incl. wheel) synthesis and AppleScript / launch via macOS CGEvent, plus say / afplay / pbcopy (speak / play-sound / clipboard); keystroke-name → platform keycode table. macOS-only — Error::Unsupported elsewhere | |
| Protocol Sources | sources, serial | 396 | 4.0% | Pure (de)coders for the non-MIDI protocols: OSC (rosc), Art-Net + sACN/E1.31 DMX, AppleMIDI/RTP-MIDI exchange + clock-sync + data packets, and serial hex/text framing — all unit-tested independent of the live sockets | |
| MIDI I/O | midi | 131 | 1.3% | MIDI message types and midir input/output port plumbing — cross-platform, builds on macOS / Linux / Windows | |
| Matcher | matcher | 122 | 1.2% | Per-translator incoming-trigger matching against live MIDI messages: note / CC / pitch-bend / channel selectivity, value capture into rules-VM inputs | |
| Error / Entry | error, lib | 67 | 0.7% | Crate Error type (Unsupported, NeedsAccessibility, parse / IO variants via thiserror) and the public lib.rs surface re-exports | |
| Tests | tests/bmtp_import, tests/engine_pipeline, tests/rules_vm | 727 | 7.3% | Integration modules (plus a tests/fixtures corpus) covering .bmtp import fidelity + export round-trip, end-to-end engine dispatch, and rules-VM semantics; the unit tests in-crate cover the protocol codecs, MTC/MMC, and trigger/action serde round-trips (65 #[test] functions in all) | |
| TOTAL | 9,925 | 100% | |||
$FILES BY SIZE
All 20 Rust source files, largest first. The engine dominates; the four bmtp/ files together (1,540 lines) are the cost of natively reading and re-writing BOME's binary project container.
| File | Lines | Role |
|---|---|---|
| src/engine/mod.rs | 4,083 | Worker-thread engine, dispatch loop, every non-MIDI trigger source, MIDI clock + MTC generators, port management, event sink, outgoing delay |
| src/model.rs | 1,323 | Project / Preset / Translator model, 39 Outgoing + 26 Incoming variants, serde JSON load/save |
| src/rules.rs | 723 | Rules compiler + signed-32-bit integer VM |
| src/bmtp/payload.rs | 716 | MID3/KAM3 XML + timer payload decoding |
| tests/bmtp_import.rs | 356 | .bmtp import-fidelity + export round-trip integration tests |
| src/sources.rs | 337 | OSC / Art-Net / sACN / RTP-MIDI packet (de)coders |
| src/bmtp/mod.rs | 304 | .bmtp INI container parse, bmtp::import entry point |
| src/keycodes.rs | 264 | Keystroke-name → platform keycode table |
| tests/engine_pipeline.rs | 261 | End-to-end engine dispatch integration tests |
| src/actions/macos.rs | 261 | macOS CGEvent keystroke / mouse (incl. wheel) / AppleScript synthesis, Accessibility check |
| src/bmtp/options.rs | 260 | Options rules-blob parser |
| src/bmtp/export.rs | 260 | Unsigned .bmtp re-serializer — Project → .bmtp, round-trips through import |
| src/actions/mod.rs | 191 | Action dispatch + macOS say / afplay / pbcopy; Unsupported/NeedsAccessibility gating |
| src/midi.rs | 131 | MIDI message types + midir port plumbing |
| src/matcher.rs | 122 | Per-translator incoming-trigger matching |
| tests/rules_vm.rs | 110 | Rules-VM semantics integration tests |
| src/engine/timers.rs | 97 | Timer trigger scheduler |
| src/serial.rs | 59 | Serial send + hex/text data framing |
| src/error.rs | 37 | Crate Error enum (thiserror) |
| src/lib.rs | 30 | Public crate surface re-exports |
| TOTAL | 9,925 | 20 files |
@EXECUTION PIPELINE
An incoming MIDI message flows through four stages on the engine's worker thread. The matcher selects translators whose Incoming trigger fits the message; each match runs its rules on the integer VM; the resulting Outgoing action is dispatched to MIDI out, the OS action layer, the timer scheduler, or the host's custom handler.
MIDI in (midir input port)
│
▼
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ midi.rs │────▶│ matcher.rs │────▶│ rules.rs │
│ (88) │ │ (97) │ │ (600) │
│ message │ │ per-entry │ │ integer VM │
│ types │ │ trigger │ │ 10 locals │
│ midir port │ │ match + │ │ globals │
│ │ │ capture │ │ IF/Goto │
└─────────────┘ └─────────────┘ └──────┬───────┘
│
┌────────────────────┤
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ engine/mod │ │ actions/ │
│ (996) │ │ (423) │
│ dispatch │────▶│ CGEvent │
│ event sink │ │ keystroke │
│ custom │ │ mouse/wheel │
│ handler │ │ AppleScript │
└──────┬───────┘ └──────────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌──────▼──────┐ ┌────▼──────┐ ┌────▼────────┐
│ midir out │ │ timers.rs │ │ host custom │
│ + route/ │ │ (90) │ │ + stryke │
│ port/proj │ │ scheduler │ │ hook │
└─────────────┘ └───────────┘ └─────────────┘
&RULES VM — BOME SEMANTICS
The rules language is a faithful reimplementation of BOME MIDI Translator Pro's rules, run on a small signed-32-bit integer VM. The behaviors below are pinned by tests/rules_vm.rs so refactors can't silently diverge from BOME.
Values & Variables
All values are signed 32-bit and wrap on overflow. Division and modulo by zero yield 0. Variables: 10 locals (oo pp qq rr ss tt uu vv ww xx, lifetime = one incoming event) and two-character globals (ga…z9, initialized to 0, lifetime = project).
Operators
Arithmetic + - * / % and bitwise & | ^ >> <<. Conditionals are IF a <cmp> b THEN <action> with the six comparators == != >= <= > <.
Control Flow
Goto / Label, Skip Next [n], and "exit rules and execute / ignore". Log emits to the host event sink. Outgoing values are mutated in place before the action fires.
Incoming Triggers
A translator's Incoming trigger is one of 26 variants — MIDI message / 14-bit, keystroke, timer, preset, enable/disable, OSC, Art-Net + sACN DMX, file watch, serial, gamepad, HID, MIDI clock, MTC, MMC, Ableton Link, audio, CV/gate, cron schedule, system event, HTTP, TCP, WebSocket, MQTT, or RTP-MIDI. The matcher captures message bytes into VM inputs so rules can branch on note / CC / channel / value.
+DEPENDENCIES
23 direct dependencies — 19 cross-platform, 4 macOS-only. No async runtime: the engine runs on a single dedicated worker thread and talks to the host over crossbeam-channel.
| Crate | Role | Scope |
|---|---|---|
| midir | Cross-platform MIDI input/output ports | all platforms |
| serde | Derive-based serialization of the project model | all platforms |
| serde_json | Native project storage (JSON) | all platforms |
| thiserror | Crate Error enum derivation | all platforms |
| crossbeam-channel | Engine ↔ host event / command channels | all platforms |
| serialport | Serial port I/O — incoming + outgoing serial triggers/actions | all platforms |
| rosc | OSC message (de)coding for OSC triggers and actions | all platforms |
| notify | Filesystem-watch triggers | all platforms |
| gilrs | Gamepad / controller input (axes + buttons → triggers) | all platforms |
| tiny_http | Tiny HTTP server for incoming HTTP triggers | all platforms |
| ureq | Blocking HTTP client for outgoing GET/POST actions | all platforms |
| tungstenite | WebSocket client/server (incoming + outgoing) | all platforms |
| rumqttc | MQTT client (incoming + outgoing messages) | all platforms |
| hidapi | Generic USB-HID input (Stream Deck / custom controllers) | all platforms |
| cron | Cron-expression parsing for time-of-day triggers | all platforms |
| chrono | Local-time computation for cron schedules | all platforms |
| if-addrs | Enumerate active network interfaces (system-event triggers) | all platforms |
| socket2 | Multicast socket options (SO_REUSEADDR/PORT) for sACN input | all platforms |
| rusty_link | Ableton Link tempo / beat sync (beat triggers, transport out) | all platforms |
| core-graphics | macOS CGEvent keystroke / mouse synthesis | macOS |
| core-foundation | macOS AppleScript / Accessibility plumbing | macOS |
| foreign-types | macOS Core Foundation / Core Graphics FFI wrappers | macOS |
| cpal | macOS CoreAudio audio-reactive input (peak level → trigger) | macOS |
Line counts measured with tokei 14.0.0 + wc -l across src/ + tests/. Numbers refresh as the crate adds commits.