// ZTRANSLATOR — ENGINEERING REPORT

Embeddable real-time MIDI translation engine in pure Rust · worker-thread engine · signed-32-bit rules VM · BOME .bmtp import + export · OS-control actions (keystroke / mouse / AppleScript)

>_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.

9,925
Source Lines
8,484
Code Lines
20
Rust Files
65
Test Functions
3
Integration Test Modules
23
Direct Dependencies
39
Outgoing Variants
26
Incoming Triggers

Source Distribution — 9,925 lines

9,198 library / 727 tests · 92.7% library

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.

SubsystemKey FilesLines%ShareDescription
Engineengine/mod, engine/timers4,18042.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 / Exportbmtp/mod, bmtp/options, bmtp/payload, bmtp/export1,54015.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 Modelmodel1,32313.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 VMrules7237.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
Actionsactions/mod, actions/macos, keycodes7167.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 Sourcessources, serial3964.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/Omidi1311.3%
MIDI message types and midir input/output port plumbing — cross-platform, builds on macOS / Linux / Windows
Matchermatcher1221.2%
Per-translator incoming-trigger matching against live MIDI messages: note / CC / pitch-bend / channel selectivity, value capture into rules-VM inputs
Error / Entryerror, lib670.7%
Crate Error type (Unsupported, NeedsAccessibility, parse / IO variants via thiserror) and the public lib.rs surface re-exports
Teststests/bmtp_import, tests/engine_pipeline, tests/rules_vm7277.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)
TOTAL9,925100%

$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.

FileLinesRole
src/engine/mod.rs4,083Worker-thread engine, dispatch loop, every non-MIDI trigger source, MIDI clock + MTC generators, port management, event sink, outgoing delay
src/model.rs1,323Project / Preset / Translator model, 39 Outgoing + 26 Incoming variants, serde JSON load/save
src/rules.rs723Rules compiler + signed-32-bit integer VM
src/bmtp/payload.rs716MID3/KAM3 XML + timer payload decoding
tests/bmtp_import.rs356.bmtp import-fidelity + export round-trip integration tests
src/sources.rs337OSC / Art-Net / sACN / RTP-MIDI packet (de)coders
src/bmtp/mod.rs304.bmtp INI container parse, bmtp::import entry point
src/keycodes.rs264Keystroke-name → platform keycode table
tests/engine_pipeline.rs261End-to-end engine dispatch integration tests
src/actions/macos.rs261macOS CGEvent keystroke / mouse (incl. wheel) / AppleScript synthesis, Accessibility check
src/bmtp/options.rs260Options rules-blob parser
src/bmtp/export.rs260Unsigned .bmtp re-serializer — Project.bmtp, round-trips through import
src/actions/mod.rs191Action dispatch + macOS say / afplay / pbcopy; Unsupported/NeedsAccessibility gating
src/midi.rs131MIDI message types + midir port plumbing
src/matcher.rs122Per-translator incoming-trigger matching
tests/rules_vm.rs110Rules-VM semantics integration tests
src/engine/timers.rs97Timer trigger scheduler
src/serial.rs59Serial send + hex/text data framing
src/error.rs37Crate Error enum (thiserror)
src/lib.rs30Public crate surface re-exports
TOTAL9,92520 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 (gaz9, 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.

CrateRoleScope
midirCross-platform MIDI input/output portsall platforms
serdeDerive-based serialization of the project modelall platforms
serde_jsonNative project storage (JSON)all platforms
thiserrorCrate Error enum derivationall platforms
crossbeam-channelEngine ↔ host event / command channelsall platforms
serialportSerial port I/O — incoming + outgoing serial triggers/actionsall platforms
roscOSC message (de)coding for OSC triggers and actionsall platforms
notifyFilesystem-watch triggersall platforms
gilrsGamepad / controller input (axes + buttons → triggers)all platforms
tiny_httpTiny HTTP server for incoming HTTP triggersall platforms
ureqBlocking HTTP client for outgoing GET/POST actionsall platforms
tungsteniteWebSocket client/server (incoming + outgoing)all platforms
rumqttcMQTT client (incoming + outgoing messages)all platforms
hidapiGeneric USB-HID input (Stream Deck / custom controllers)all platforms
cronCron-expression parsing for time-of-day triggersall platforms
chronoLocal-time computation for cron schedulesall platforms
if-addrsEnumerate active network interfaces (system-event triggers)all platforms
socket2Multicast socket options (SO_REUSEADDR/PORT) for sACN inputall platforms
rusty_linkAbleton Link tempo / beat sync (beat triggers, transport out)all platforms
core-graphicsmacOS CGEvent keystroke / mouse synthesismacOS
core-foundationmacOS AppleScript / Accessibility plumbingmacOS
foreign-typesmacOS Core Foundation / Core Graphics FFI wrappersmacOS
cpalmacOS 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.