Skip to content

DMXRouter 1.9.0

Choose a tag to compare

@fiverecords fiverecords released this 19 Apr 10:36
· 19 commits to main since this release
b056a58

New Features

  • RDM → Fixture Check workflow — right-click any discovered device (or a multi-selection) in the RDM panel and choose "Send to Fixture Check". DMXRouter resolves the device through a four-stage pipeline: (1) match an existing patch entry at the same universe + start address (so MVR-imported fixtures get reused, no duplicates), (2) look up a real GDTF in the local library by manufacturer + model, (3) synthesize a FixtureType from RDM slot labels (E1.20 SLOT_INFO / SLOT_DESCRIPTION) with proper semantic attributes for Pan/Tilt/Dim/Color/Gobo/Iris/Zoom/Frost/Prism/Shutter/CTC/RGB/CMY/W/A/UV, or (4) fall back to generic Ch1..ChN channels. Works without any MVR loaded — perfect for when you arrive at a venue and just want to check the rig live over RDM. Injected fixtures are tagged [RDM] in the Patch tree so they're visually distinguishable from MVR-imported ones, and File → Remove RDM-discovered Fixtures clears them in one click when you're done

  • MVR Import (My Virtual Rig) — import .mvr files exported from Capture, MA3, Vectorworks, WYSIWYG, Depence and other MVR-compatible lighting design applications to bring the entire fixture patch into DMXRouter. The new Fixture Check dock shows all imported fixtures grouped by MVR layer, with fixture ID, name, type, universe/address, and mode. Supports MVR spec versions 1.0 through 1.6 and reads embedded GDTF fixture definitions. Generic placeholder GDTFs are detected automatically through exporter-specific fingerprints — Capture's marker comment, WYSIWYG's "Dummy" attribute pattern, and Depence's "Dimmer-only attribute with no ChannelSet ranges" pattern — and shown in italic so you know which fixtures carry only channel-count information and need replacement with real manufacturer GDTFs. Import runs asynchronously so the UI stays responsive even on large shows

  • Fixture Check panel — a commissioning tool for verifying fixtures on the rig. Select any fixture from the imported patch to open a dedicated control panel with one slider per channel. Output takes hard priority over any incoming desk signal — once you grab a fixture in DMXRouter, only DMXRouter drives it until you release. Useful for walking through a rig during focus, for verifying cabling after a patch change, or for setting fixtures to safe positions before physical adjustments. The dock is split with the patch tree on the left and sliders on the right, separated by a draggable divider whose position is remembered across sessions

  • Home, Highlight and Release controls — Home sends each fixture's GDTF-declared default values (typically Pan/Tilt centred, color open, gobo open, dimmer closed), not a blanket zero. Highlight sends full-output values for quick visual identification. Release returns control to the desk instantly. Fade Out crossfades the override back to the desk's current output over a configurable duration (0.5s / 1s / 2s / 5s) so the handoff is seamless in a live environment. A Release All panic button releases every overridden fixture at once

  • Next and Previous fixture navigation — walk through the fixture list one by one without leaving the Check panel. Selection stays synchronized between the Patch tree and the Check panel in both directions

  • Overridden fixture indicators — fixtures currently being driven by DMXRouter appear in bold green in the Patch tree, so you can see at a glance what you are controlling across the whole show

  • GDTF Library Resolver — upgrades generic placeholder fixtures with real semantic GDTFs from a local library at ~/Documents/DMXRouter/GDTF/, scanned asynchronously at startup. The Resolve with GDTF Library button applies a four-tier match strategy per placeholder: (1) manual override — if the user has explicitly pinned this placeholder to a specific GDTF via the right-click "Assign GDTF manually…" menu, that GDTF is used unconditionally; (2) FixtureTypeID UUID lookup; (3) normalized manufacturer + name with aggressive corporate suffix stripping so "Robe" matches "Robe Lighting", "Martin" matches "Martin Professional", etc. across every supported variant (Professional / International / Technology / Lighting / Light / GmbH / Ltd / Inc / Corp / LLC / Electronics / AG / SA / SL / BV / NV); (4) mode resolution falls back through three tiers of its own — exact name match, then same DMX footprint (only when the footprint is plausible), then keyword match on the mode name so an MVR "Standard 16bit" pairs with a real GDTF's "Mode 1 - Standard 16 bit" through shared tokens. A summary dialog reports resolved, skipped, and mode-mismatch counts with detailed per-fixture warnings

  • Manual GDTF assignment — right-click any placeholder or RDM-synthesized fixture in the Patch tree to open "Assign GDTF manually…". A picker dialog opens showing the full local library with a live filter box; pick any installed GDTF and every fixture sharing the same placeholder type is upgraded. Covers the case where the MVR writes a fixture name that doesn't quite match the catalog (e.g., "Robin iForte LTX" vs "Robin iForte LTX FS") so auto-resolve can't pair them confidently. Manual assignments are persisted with the patch so they survive save/load, and can be cleared from the same context menu to revert to auto-resolve behaviour

  • GDTF Share online integration — built-in REST client for gdtf-share.com (the official ESTA fixture library) lets users search the entire public catalog and download real GDTF profiles without leaving DMXRouter. Two flows are provided: File → Browse GDTF Share... opens a searchable list of every fixture (filter by manufacturer, model or UUID, double-click to download); File → Download Missing GDTFs from Share... (also accessible from the placeholder advisory dialog and the amber banner) reads the UUIDs of the current patch's placeholder fixtures and pre-selects matching catalog entries so the full "MVR import → all fixtures semantic" round-trip is one click. After the batch download completes DMXRouter automatically invokes Resolve with GDTF Library so the patch flips from Dimmer1..DimmerN to Pan/Tilt/Color/Gobo/... with no further user interaction. A gdtf-share.com account is required (free to create); credentials are stored locally with light obfuscation so the login prompt appears at most once per machine

  • Import GDTF Files menu — File → Import GDTF Files... copies one or more .gdtf fixture definitions into the local library folder and automatically triggers a rescan. Useful when a specific fixture is not on gdtf-share.com but the manufacturer ships its own GDTF

  • Multi-cell fixture support — LED walls, pixel matrices and any GDTF using <GeometryReference> to replicate a channel template across physical positions are expanded at import time into a parent container with N individually-addressable cell sub-fixtures. In the patch tree the container is collapsible; expanding it reveals every cell. Selecting the container broadcasts slider moves and Home / Highlight / Release to every cell (quick "is the wall alive" check), while selecting a single cell controls only that cell (precision walkthrough). A typical LED wall with 100 RGB pixels becomes 101 entries in the patch: 1 container + 100 cells, each at its correct DMX offset

  • On-demand output for override-only universes — taking control of a fixture on a universe with no incoming desk data now causes DMXRouter to start emitting that universe automatically. The merge engine synthesises zero-based packets at ~30 Hz so the override layer has something to stamp on, and both the network transport and the Universe Monitor see the real bytes going out. When the last override is released the emission stops — no continuous traffic when nothing is being controlled. Closes the previous silent-override gap where a user could move a slider and see no activity in the monitor because there was no desk input feeding the engine

  • Fixture patch persistence — imported MVR patches are saved as part of the DMXRouter configuration file and restored automatically on load. The crash recovery system also preserves the patch, so a walkthrough session survives an unclean shutdown without having to reimport

  • About dialog credits — zlib is now credited in the About dialog's Third-party libraries section, matching the existing Qt LGPL compliance notice

How Fixture Check Reaches the Rig

Fixture Check does not implement its own transport layer — it plugs into the existing engine pipeline at the last moment before transmission. For a slider movement to reach a physical fixture, two conditions must be met:

  1. The MVR must carry a valid DMX address for the fixture — shown in the Address column as U5/357 (universe 5, channel 357). Fixtures with — in the address column cannot be controlled until their address is set in the original design file and re-exported
  2. The Engines panel must have an output configured for that universe — DMXRouter emits each universe through whichever engine outputs are configured for it, regardless of which protocol or interface they use. Without an engine for the fixture's universe, overrides are computed correctly but have no transport to ride on

Once both conditions are met the override is replicated automatically to every interface and protocol that engine is configured to serve (single universe → multiple outputs and protocols is fully supported). VLAN routing, merge priorities, sACN per-channel priority, and rate limiting all apply to overrides the same way they apply to desk output. The Fixture Check panel shows a warning banner when the currently selected fixture has no engine emitting its universe, so a missing engine is visible without leaving the dock.

When the user takes control of a fixture on a universe that has no incoming desk data, the merge engine automatically starts synthesising zero-based packets at ~30 Hz so the override layer has something to stamp on. The Universe Monitor reflects every byte that leaves the application, regardless of whether it originated from a desk merge or from a Fixture Check override. When the last override on that universe is released, on-demand emission stops — no continuous traffic when nothing is being driven.

GDTF 1.2 Spec Compliance

The GDTF parser now follows the DIN SPEC 15800 / GDTF 1.2 specification more completely:

  • Default attribute at DMXChannel level is the primary source for Home values, as the spec prescribes. Previous versions used the ChannelFunction DMXFrom attribute by mistake, which happened to always be 0 and caused Home to send zero on every channel. Pan and Tilt now correctly centre at 32768 (16-bit mid), colour wheels snap to Open, and so on
  • Highlight attribute at DMXChannel level is read directly when present, with heuristic fallback (locating ChannelFunctions named "Open", "Full" etc.) for GDTFs that omit it
  • Fallback chain for Default — if the DMXChannel does not declare a Default, the parser falls back to the ChannelFunction's Default attribute, then to DMXFrom as a last resort. This preserves compatibility with legacy GDTFs
  • 24-bit and 32-bit channels (GDTF Offset="c,f,u,b" with up to 4 byte offsets) are now parsed and encoded correctly. Extremely rare in show lighting but spec-legal for scientific and industrial fixtures
  • DMXBreak="Overwrite" is now fully supported via GeometryReference expansion. The DMXChannel declares the channel template once, and each <GeometryReference> on the geometry tree specifies where the template is applied (with its own DMX offset). At import time the fixture is expanded into a container + N cell sub-fixtures so every replicated position is independently addressable. Covers the typical LED wall export from MA3 / Vectorworks / Capture
  • MA3-exported MVRs and GDTFs — three compatibility fixes land together: (a) <GDTFSpec> values without the .gdtf extension are accepted (MA3 quirk), (b) trailing NUL/whitespace bytes past the XML root element are stripped before parsing (both MVR XML and nested GDTF description.xml), (c) the parser continues rather than aborting on trailing-garbage warnings

UI Improvements

  • Multi-fixture selection with broadcast control — the Patch tree now supports Ctrl+click and Shift+click to select multiple fixtures at once. When the selection spans fixtures of the same type, Fixture Check shows the normal slider set and every slider move, Home, Highlight or Release action is broadcast to every selected fixture simultaneously. When the selection mixes different fixture types, DMXRouter shows only the attributes COMMON to all selected fixtures (typically Dim / Pan / Tilt), letting you check basic movement on your whole rig in one pass without having to iterate fixture by fixture. Channel-range comboboxes (gobo/colour wheels) are suppressed in mixed selections since a DMX value that means "Gobo 3 Glass" on one fixture means something different on another, but the raw slider still works
  • Select All (Ctrl+A) — new button in the Fixture Check action row, and Ctrl+A shortcut when the Patch tree has focus, selects every fixture across the patch at once. Combined with the multi-fixture broadcast control this gives a one-click "home / highlight / release the whole rig" experience without having to iterate fixture by fixture. Release All remains the panic button that unconditionally releases every overridden fixture
  • Named channel ranges with wheel thumbnails — Fixture Check now recognises GDTF <ChannelSet> and <Wheel> data. When a channel has discrete named positions — gobo wheels, colour wheels, prism selectors, effect channels, shutter macros — the slider is accompanied by a combobox listing the named options such as "Open / Gobo 1 Glass / Gobo 2 Dots / Shake slow / Shake fast", with small thumbnails of the actual gobo pattern (or a colour swatch for colour wheels) extracted from the fixture's .gdtf archive. The raw slider remains alongside for dialling into the middle of a range (shake speed, rainbow spin rate, etc.) and stays bidirectionally synchronised with the combobox so the active selection is always visible. Wheel images are extracted on-demand to ~/Documents/DMXRouter/wheels/ and cached across sessions
  • Generic placeholder advisory — importing an MVR that contains generic placeholder GDTFs (Capture marker, WYSIWYG Dummy attribute, Depence Dimmer-only pattern — all detected automatically) now shows a guided dialog listing which fixture types need real semantic definitions, a one-click link to gdtf-share.com, and a direct shortcut to File → Import GDTF Files…. A persistent amber banner stays at the top of the Patch dock until the user resolves the placeholders, so the requirement does not get lost after closing the dialog. This eliminates the previous situation where users saw Dimmer1..DimmerN generic sliders on every fixture and had no in-application guidance on what to do next
  • Single combined Fixture Check dock — the previous two separate tabs (Patch and Check) are now a single dock with horizontal split: patch tree on the left, channel sliders on the right. The divider is draggable, both sides are collapsible, and the position is saved across sessions. The previous workflow of switching tabs to see the selected fixture's sliders is gone — patch navigation and slider control are visible simultaneously
  • Wider slider labels — the slider label column widened from 50px to 110px minimum to accommodate real GDTF attribute names (ColorSub_C, Gobo1Pos, AnimationWheel1Pos…) without right-side truncation. Labels that still do not fit show the full name on hover. Slider column is now the only one that stretches when the dock is resized, keeping labels and spin boxes at a consistent natural size
  • Navigation button glyph stability — the ◀ Prev / Next ▶ button arrows now use explicit QChar codepoints instead of raw UTF-8 byte sequences, eliminating the mojibake that could appear in some MSVC/MinGW source encoding configurations

RDM Panel Improvements

Several improvements requested by rental professionals, primarily focused on large-database workflows where the fixture count runs into the hundreds:

  • Auto Fetch toggle on Fetch All button — the "Fetch All" button in the RDM toolbar is now a toggle. Enabled once, it fetches extended info (personalities, sensors, hours) for every currently-discovered device AND keeps that behaviour on for any device discovered later, so walking from zone to zone on a large rig gets full data automatically without having to click after every discovery burst. The state persists across sessions — leave it on if you run the same venue regularly. Toggling off cancels any fetch in progress and clears the "already fetched" tracking so a later re-enable starts fresh
  • Column sorting in the Templates table — click any column header (Manufacturer, Model, Firmware, Created, Modified) to sort the template list. Click the same header again to toggle ascending/descending. Useful for finding recently-modified templates or grouping by manufacturer when the template count grows
  • Column sorting inside Fixture DB groups — the Fixture Database is grouped by "Manufacturer — Model" header rows, which intentionally stays that way (a flat 500-fixture list is unmanageable). Clicking any column header now sorts fixtures INSIDE each group by that column while leaving the group structure intact. Useful for finding recently-seen fixtures (Last Seen column, default) or for scanning a group for a specific serial number. The chosen column and direction are persisted across sessions
  • Keyboard navigation in Fixture DB — use Up / Down arrows to move between fixture rows (group headers are automatically skipped), and Left / Right to collapse / expand the current row's group. Works from any row inside a group, not just from its header, so you can drill through a 500-fixture list without reaching for the mouse. Click-to-toggle on the group header still works as before
  • Station Sync dialog — separate IP and port fields — the Station Sync configuration dialog now has separate "Source IP" and "Port" fields, matching the Web API Server configuration dialog. Previous versions used a single combined "host:port" field which was error-prone when typing on a phone or pasting a full URL. Existing settings (saved as "host:port" strings) are read back correctly and split automatically; the internal API stays unchanged so no migration is needed

Bug Fixes

  • Fixture Check overrides now reach sACN outputs — a universe-keying mismatch between the override layer and the output transport caused overrides destined for sACN engines to be calculated but never reach the network. Art-Net outputs were unaffected so the issue only manifested on installs that use sACN for their show output. The reachability banner in the Check panel also showed false "no engine output" warnings on Art-Net shows for the inverse reason; both paths now normalise universe numbers correctly before comparing

  • Login to gdtf-share.com no longer freezes the UI — the silent auto-login kicked when opening the Browse dialog previously ran inside a nested event loop, which blocked the UI for however long the server took to respond (several seconds on slow networks, minutes on firewall drops). Rewritten as a fully asynchronous flow so the UI stays responsive throughout

  • Ghost window after disconnecting a second monitor — if you closed DMXRouter on an extended second display and later opened it without that monitor connected, the window would restore to its saved off-screen coordinates. The result was a window that didn't render, couldn't be moved with Win+Arrow, and showed blank in the taskbar preview — recoverable only by re-connecting a monitor at the exact same position. DMXRouter now checks whether the saved geometry intersects any currently-connected screen; if not, it falls back to centering on the primary screen at a size that fits there. Also clamps the window size if the previous screen was larger than the new primary (e.g., 4K external → 1080p laptop)

  • RDM-discovered fixtures upgraded via GDTF library now emit correctly — devices sent to Fixture Check from the RDM panel and later upgraded to a real library GDTF could end up silently emitting nothing because the addressing convention used by RDM (break 0) did not match the GDTF's declared break (typically break 1). Same behaviour fixed for the manual "Assign GDTF" flow when the user picks a mode that differs from what the placeholder declared. The fixture's address is now remapped to the upgraded GDTF's break at the moment of type swap so overrides land on the correct DMX channels

  • Fixture patch refreshes on config load when the library is still indexing — opening a saved configuration at launch time could leave the patch using stale fixture parse results, because the GDTF library's asynchronous startup scan was still in progress when the refresh-from-library step ran and consequently found nothing to refresh against. Now defers the refresh until the library's first scan completes, so previously-saved shows pick up parser improvements (channel defaults, highlights, ranges) without needing a manual refresh

  • Multi-cell fixtures that spill past channel 512 now surface a warning — when a multi-cell fixture's parent start address plus an individual cell's DMX offset exceeds 512, that cell can't be addressed on its universe. Previous versions silently dropped the address, leaving a cell that showed as resolved in the patch but emitted nothing. Import now adds an explicit warning so the over-reach is visible and the user can re-patch the parent

  • Fixture Check sliders now stay in sync with mixed selections — selecting a set of fixtures that included an unresolved placeholder as the first entry caused the slider values to be read from that placeholder (always zero), ignoring any active overrides on the other selected fixtures. The first resolved fixture is now used as the reference for display regardless of selection order

  • Send to Fixture Check from RDM selects correctly in the Patch tree — the Patch tree's visual selection and the Check panel's slider set could disagree after sending multiple devices from the RDM panel, because the programmatic selection path wasn't emitting its change signal. Both views are now always in sync after the inject

  • Mode-picker dialog for manual GDTF assignments now applies correctly — choosing a mode from the ambiguity dialog after a manual GDTF assignment now remaps the fixture's break to match the chosen GDTF, same as the automatic Resolve with GDTF Library flow. Without this, post-dialog fixtures could appear resolved but silently stop emitting

  • Release All properly stops its internal timer — when using Release All during an active fade-out, the background tick timer kept running for one more cycle before self-cleaning. Harmless but visible in profilers; now stops immediately in step with state reset

Improvements

  • Reduced memory allocations on the network receive path — the interface-matching step that runs on every incoming Art-Net and sACN packet now reuses a pre-allocated buffer instead of allocating a fresh list per packet. After the first few seconds of traffic, the hot receive path does no heap allocations for interface matching. Benefits are most visible under heavy sustained traffic where the reduced allocator pressure lowers background CPU and improves jitter consistency
  • Self-contained build — bundled zlib 1.3.1 sources are now compiled as a static library inside the DMXRouter build. Removes the need for a system zlib package (previously an issue for MinGW builds where no such package ships by default), and makes the build fully reproducible across Windows, macOS, Linux, and ARM64

Technical Details

  • The fixture override path adds zero overhead to DMX output when no fixtures are being overridden — a single atomic check gates the entire override stage. The underlying per-universe override map uses a sparse structure that touches only the channels actually being written, keeping the hot path allocation-free even during active commissioning
  • Multi-byte channels (16/24/32-bit) are handled natively — the Check panel shows a single slider with the full range encoded for that resolution, and the override encoder writes all relevant bytes (coarse/fine/ultra/uber) to their respective offsets automatically
  • Break reconciliation between the MVR file format (default break 0) and GDTF definitions (default break 1) is handled automatically for single-break fixtures, covering the common Capture export case without any manual patch adjustments
  • GDTF Library uses a two-phase scan to stay fast even with thousands of files: phase 1 asynchronously indexes every .gdtf by reading only the FixtureType root element (UUID + Manufacturer + Name), and phase 2 parses the full GDTF only when the resolver actually needs it