<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mxwendler.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin</id>
	<title>MXWendler Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mxwendler.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin"/>
	<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Special:Contributions/Admin"/>
	<updated>2026-10-05T23:26:20Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6229</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6229"/>
		<updated>2026-09-29T21:21:19Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== Components ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || an unmodified PeerTube instance with the Stage Recorder plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux machine, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder does not have to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the recommended configuration for a venue || the recording machine is not affected; the portal host performs the transcoding; each side needs only a host name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or viewers watch from outside the venue || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Any instance reachable from outside the LAN is placed behind a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is adequate as a starting point and can be separated later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs the application to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library, the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, the video portal deployment under &amp;lt;code&amp;gt;portal\&amp;lt;/code&amp;gt; (Part 3) and this guide as &amp;lt;code&amp;gt;deployment.pdf&amp;lt;/code&amp;gt;, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that may be absent, note that a missing root at record start does not prevent the recording: the default root is used instead and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;&#039;Private&#039;&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;&#039;Public&#039;&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
The recorder is installed from a Debian package built for Ubuntu 24.04 (amd64), &amp;lt;code&amp;gt;tourette-stage-recorder_&amp;lt;version&amp;gt;_amd64.deb&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;tools/installer/linux/build_deb.py&amp;lt;/code&amp;gt; in the source tree builds it from a Linux build of the application).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install ./tourette-stage-recorder_&amp;lt;version&amp;gt;_amd64.deb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;apt&amp;lt;/code&amp;gt; resolves the dependencies (wxWidgets 3.2, GTK 3, ALSA, libcurl) and installs &amp;lt;code&amp;gt;ffmpeg&amp;lt;/code&amp;gt; as a recommendation; it renders the H.264 proxies for the portal. The package places:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Path !! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/opt/TouretteStageRecorder/&amp;lt;/code&amp;gt; || the application &amp;lt;code&amp;gt;mxw_recorder&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;files/&amp;lt;/code&amp;gt; tree, the video portal deployment under &amp;lt;code&amp;gt;portal/&amp;lt;/code&amp;gt; (Part 3)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/bin/tourette-stage-recorder&amp;lt;/code&amp;gt; || the launcher; it sets the working directory and starts the application&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/share/applications/tourette-stage-recorder.desktop&amp;lt;/code&amp;gt; || the entry in the applications menu&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/share/doc/tourette-stage-recorder/deployment.pdf&amp;lt;/code&amp;gt; || this guide&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. License.&#039;&#039;&#039; The Linux build has no dongle support; it reads the license file. Copy &amp;lt;code&amp;gt;mxr_license.lic&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;/opt/TouretteStageRecorder/&amp;lt;/code&amp;gt; before the first start:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo cp mxr_license.lic /opt/TouretteStageRecorder/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start &#039;&#039;Tourette Stage Recorder&#039;&#039; from the applications menu, or &amp;lt;code&amp;gt;tourette-stage-recorder&amp;lt;/code&amp;gt; from a terminal. The settings file is created at &amp;lt;code&amp;gt;~/.mxw_recorder/mxr_recorder.ini&amp;lt;/code&amp;gt; of the user who runs it; recordings go to &amp;lt;code&amp;gt;~/Documents/TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk, as on Windows.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; With &amp;lt;code&amp;gt;ufw&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ufw allow 7000/udp          # OSC&lt;br /&gt;
sudo ufw allow 5900,5800/tcp     # VNC and browser viewer, only with VNC on&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; As on Windows, a take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload, which requires an NVIDIA GPU with its driver; without one the original is uploaded. The recorder finds &amp;lt;code&amp;gt;ffmpeg&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;/usr/bin/ffmpeg&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Autostart.&#039;&#039;&#039; For a kiosk, start &amp;lt;code&amp;gt;tourette-stage-recorder&amp;lt;/code&amp;gt; from the desktop session&#039;s autostart. The application needs a display and OpenGL; a system service without a session is not sufficient.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;8. Restart policy.&#039;&#039;&#039; As on Windows, settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup; use &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; after changing them.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;portal/&amp;lt;/code&amp;gt; directory that both installers place next to the application (&amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\portal\&amp;lt;/code&amp;gt; on Windows, &amp;lt;code&amp;gt;/opt/TouretteStageRecorder/portal/&amp;lt;/code&amp;gt; on Linux; in the source tree it is &amp;lt;code&amp;gt;tools/installer/portal/&amp;lt;/code&amp;gt;). Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
The stack writes its database and media into &amp;lt;code&amp;gt;docker/volumes/&amp;lt;/code&amp;gt; next to its compose file, and its secrets into &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt;. Neither belongs under the installation directory, which is read-only for the operator. Copy &amp;lt;code&amp;gt;portal/&amp;lt;/code&amp;gt; to a writable location first, on the machine that will run the portal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp -r /opt/TouretteStageRecorder/portal ~/portal          # Linux&lt;br /&gt;
xcopy /E /I &amp;quot;C:\Program Files\Tourette Stage Recorder 5.0\portal&amp;quot; %USERPROFILE%\portal     (Windows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paths in this part refer to that copy. For a separate portal host (topology B or C), copy the directory to that machine.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;&#039;Start Docker Desktop when you sign in&#039;&#039;&#039;. Two properties of this configuration are relevant:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN address. For this reason the portal never connects to the recorder; no configuration is required for this, and no connection from the portal to the recorder should be set up.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
In the copy of the portal directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd ~/portal&lt;br /&gt;
python3 build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; no connection is made to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;&#039;internal&#039;&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build the image on a machine with internet access and transfer it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and the docker/ directory (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the complete configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;docker/volumes/&amp;lt;/code&amp;gt; of the portal directory on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/thumbnails&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;previews&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storyboards&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;captions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;torrents&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; install the new recorder version, copy its &amp;lt;code&amp;gt;portal/&amp;lt;/code&amp;gt; over the working copy (keeping &amp;lt;code&amp;gt;docker/volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;python3 build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals require the full take size per upload; renditions require approximately the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then verify the connection:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;&#039;uploading n %&#039;&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Required only when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker is suitable; Mosquitto is used in the examples below.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict anonymous access to the LAN (bind the listener to the LAN interface, or add a password file for other clients); the recorder itself does not support broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;&#039;keep&#039;&#039;&#039; and a &#039;&#039;&#039;publish&#039;&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; is logged and the links cannot be answered.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, verification of the connection&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, verification of the connection&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6228</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6228"/>
		<updated>2026-09-29T21:04:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== Components ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || an unmodified PeerTube instance with the Stage Recorder plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux machine, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder does not have to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the recommended configuration for a venue || the recording machine is not affected; the portal host performs the transcoding; each side needs only a host name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or viewers watch from outside the venue || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Any instance reachable from outside the LAN is placed behind a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is adequate as a starting point and can be separated later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs the application to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library and the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that may be absent, note that a missing root at record start does not prevent the recording: the default root is used instead and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;&#039;Private&#039;&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;&#039;Public&#039;&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
The recorder is installed from a &amp;lt;code&amp;gt;.deb&amp;lt;/code&amp;gt; package. Description will follow.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory from the source tree. Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;&#039;Start Docker Desktop when you sign in&#039;&#039;&#039;. Two properties of this configuration are relevant:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN address. For this reason the portal never connects to the recorder; no configuration is required for this, and no connection from the portal to the recorder should be set up.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
On the portal host, in a copy of the source tree (or only the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd tools/portal/docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; no connection is made to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;&#039;internal&#039;&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build the image on a machine with internet access and transfer it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and tools/portal/docker/ (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the complete configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;tools/portal/docker/volumes/&amp;lt;/code&amp;gt; on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/thumbnails&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;previews&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storyboards&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;captions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;torrents&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; pull the new source tree, &amp;lt;code&amp;gt;python3 tools/portal/build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals require the full take size per upload; renditions require approximately the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then verify the connection:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;&#039;uploading n %&#039;&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Required only when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker is suitable; Mosquitto is used in the examples below.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict anonymous access to the LAN (bind the listener to the LAN interface, or add a password file for other clients); the recorder itself does not support broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;&#039;keep&#039;&#039;&#039; and a &#039;&#039;&#039;publish&#039;&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; is logged and the links cannot be answered.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, verification of the connection&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, verification of the connection&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6227</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6227"/>
		<updated>2026-09-29T21:04:19Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== What gets deployed ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || an unmodified PeerTube instance with the Stage Recorder plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux box, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder does not have to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the recommended configuration for a venue || the recording machine is not affected; the portal host performs the transcoding; each side needs only a host name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or viewers watch from outside the venue || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Anything reachable from outside gets a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is adequate as a starting point and can be separated later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs the application to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library and the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that may be absent, note that a missing root at record start does not prevent the recording: the default root is used instead and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;&#039;Private&#039;&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;&#039;Public&#039;&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
The recorder is installed from a &amp;lt;code&amp;gt;.deb&amp;lt;/code&amp;gt; package. Description will follow.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory from the source tree. Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;&#039;Start Docker Desktop when you sign in&#039;&#039;&#039;. Two facts matter on this setup:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN IP. For this reason the portal never connects to the recorder; no configuration is required for this, and no connection from the portal to the recorder should be set up.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
On the portal host, in a copy of the source tree (or just the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd tools/portal/docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; no connection is made to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;&#039;internal&#039;&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build the image on a machine with internet access and transfer it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and tools/portal/docker/ (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the complete configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;tools/portal/docker/volumes/&amp;lt;/code&amp;gt; on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/thumbnails&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;previews&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storyboards&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;captions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;torrents&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; pull the new source tree, &amp;lt;code&amp;gt;python3 tools/portal/build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals require the full take size per upload; renditions require approximately the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then verify the connection:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;&#039;uploading n %&#039;&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Required only when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker is suitable; Mosquitto is used in the examples below.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict anonymous access to the LAN (bind the listener to the LAN interface, or add a password file for other clients); the recorder itself does not support broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;&#039;keep&#039;&#039;&#039; and a &#039;&#039;&#039;publish&#039;&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; is logged and the links cannot be answered.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, verification of the connection&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, verification of the connection&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6226</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6226"/>
		<updated>2026-09-29T20:57:51Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== What gets deployed ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || a stock PeerTube instance with our plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux box, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder never has to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the normal case for a venue || the recording PC stays untouched; the portal host does the transcoding; both sides only need a name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or people watch from home || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Anything reachable from outside gets a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is fine to start with and can be split later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library and the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the Settings tab&#039;s configuration tree once the application has run once.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that can go away, know that a missing root at record start is not fatal: the default root stands in and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;&#039;Private&#039;&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;&#039;Public&#039;&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
The recorder is installed from a &amp;lt;code&amp;gt;.deb&amp;lt;/code&amp;gt; package. Description will follow.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory from the source tree. Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;&#039;Start Docker Desktop when you sign in&#039;&#039;&#039;. Two facts matter on this setup:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN IP. That is why the portal never connects to the recorder — nothing to configure, but do not try to make it.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
On the portal host, in a copy of the source tree (or just the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd tools/portal/docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; nothing connects to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;&#039;internal&#039;&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build on a machine with internet access, carry the image over:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and tools/portal/docker/ (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the whole configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;tools/portal/docker/volumes/&amp;lt;/code&amp;gt; on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/thumbnails&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;previews&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storyboards&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;captions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;torrents&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; pull the new source tree, &amp;lt;code&amp;gt;python3 tools/portal/build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals cost the full take size per upload; renditions cost roughly the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then a smoke test:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;&#039;uploading n %&#039;&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Only needed when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker works; Mosquitto is the usual choice.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict &amp;lt;code&amp;gt;allow_anonymous&amp;lt;/code&amp;gt; to the LAN (bind to the LAN interface, or add a password file) — the recorder supports no broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;&#039;keep&#039;&#039;&#039; and a &#039;&#039;&#039;publish&#039;&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; warns and the links lead nowhere.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, smoke test&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, smoke test&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6225</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6225"/>
		<updated>2026-09-29T20:41:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== What gets deployed ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || a stock PeerTube instance with our plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux box, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder never has to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the normal case for a venue || the recording PC stays untouched; the portal host does the transcoding; both sides only need a name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or people watch from home || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Anything reachable from outside gets a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is fine to start with and can be split later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library and the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the Settings tab&#039;s configuration tree once the application has run once.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that can go away, know that a missing root at record start is not fatal: the default root stands in and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;&#039;Private&#039;&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;&#039;Public&#039;&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
There is no package; the recorder is built from the source tree on the target machine or on an identical one.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Packages&#039;&#039;&#039; (Debian/Ubuntu names; the tree links wxWidgets 3.2 GTK3 with OpenGL, PortAudio from its submodule, system zlib and libcurl):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install build-essential cmake git python3 \&lt;br /&gt;
    libwxgtk3.2-dev libgl1-mesa-dev libasound2-dev \&lt;br /&gt;
    zlib1g-dev libcurl4-openssl-dev ffmpeg&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ffmpeg&amp;lt;/code&amp;gt; (the command line tool) is what renders the portal proxies; the recorder looks for it at &amp;lt;code&amp;gt;/usr/bin/ffmpeg&amp;lt;/code&amp;gt; or wherever &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; points. Zlib and libcurl are fetched and built at configure time when the development packages are missing, so they are optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Build.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone --recurse-submodules &amp;lt;repo&amp;gt; mxw_recorder&lt;br /&gt;
cd mxw_recorder&lt;br /&gt;
mkdir -p build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake .. -DCMAKE_BUILD_TYPE=Release&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result is &amp;lt;code&amp;gt;build/mxw_recorder&amp;lt;/code&amp;gt;. Run it from the &#039;&#039;&#039;repository root&#039;&#039;&#039; — the &amp;lt;code&amp;gt;files/&amp;lt;/code&amp;gt; tree (skin, fonts, translations) is found relative to the working directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /path/to/mxw_recorder &amp;amp;&amp;amp; ./build/mxw_recorder&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Dongle.&#039;&#039;&#039; The Rockey4ND library talks to the dongle over USB; the user running the recorder needs access to that USB device. Add a udev rule for the dongle&#039;s vendor/product id (see &amp;lt;code&amp;gt;lsusb&amp;lt;/code&amp;gt; with the dongle plugged in) that grants the recorder&#039;s group read/write access, then replug.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Settings and recordings.&#039;&#039;&#039; The settings file is &amp;lt;code&amp;gt;mxr_recorder.ini&amp;lt;/code&amp;gt; in the application&#039;s user data directory (by default &amp;lt;code&amp;gt;~/.mxw_recorder/&amp;lt;/code&amp;gt;). Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; after the first start.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; With &amp;lt;code&amp;gt;ufw&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ufw allow 7000/udp          # OSC&lt;br /&gt;
sudo ufw allow 5900,5800/tcp     # VNC and browser viewer, only with VNC on&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Autostart.&#039;&#039;&#039; For a kiosk, start the recorder from the desktop session&#039;s autostart (it needs a display and OpenGL; a plain systemd service without a session will not do), with the working directory set to the repository root.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory from the source tree. Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;&#039;Start Docker Desktop when you sign in&#039;&#039;&#039;. Two facts matter on this setup:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN IP. That is why the portal never connects to the recorder — nothing to configure, but do not try to make it.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
On the portal host, in a copy of the source tree (or just the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd tools/portal/docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; nothing connects to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;&#039;internal&#039;&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build on a machine with internet access, carry the image over:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and tools/portal/docker/ (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the whole configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;tools/portal/docker/volumes/&amp;lt;/code&amp;gt; on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/thumbnails&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;previews&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storyboards&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;captions&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;torrents&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; pull the new source tree, &amp;lt;code&amp;gt;python3 tools/portal/build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals cost the full take size per upload; renditions cost roughly the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then a smoke test:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;&#039;uploading n %&#039;&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;&#039;Bring back to recorder&#039;&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Only needed when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker works; Mosquitto is the usual choice.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict &amp;lt;code&amp;gt;allow_anonymous&amp;lt;/code&amp;gt; to the LAN (bind to the LAN interface, or add a password file) — the recorder supports no broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;&#039;keep&#039;&#039;&#039; and a &#039;&#039;&#039;publish&#039;&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; warns and the links lead nowhere.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, smoke test&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, smoke test&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6224</id>
		<title>Stage Recorder Deployment</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_Deployment&amp;diff=6224"/>
		<updated>2026-09-29T20:40:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Deployment: Recorder and Video Portal =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Covers:&#039;&#039;&#039; Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails&lt;br /&gt;
&lt;br /&gt;
== What gets deployed ==&lt;br /&gt;
&lt;br /&gt;
A complete installation has up to four parts. Only the recorder is mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Part !! What it is !! Runs on&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recorder&#039;&#039;&#039; || the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC || the machine with the capture hardware and the license dongle&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Video portal&#039;&#039;&#039; || a stock PeerTube instance with our plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) || the same machine, or any Linux box, NAS or VM that runs Docker&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;MQTT broker&#039;&#039;&#039; || optional; needed only for MQTT remote control and status publishing || anywhere on the LAN, often the portal host&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Mail server&#039;&#039;&#039; || optional; an existing SMTP account for the reminder digest || not deployed, only configured&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The recorder never has to be reachable from the portal. Every transfer, including the portal&#039;s &#039;&#039;Bring back to recorder&#039;&#039; button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.&lt;br /&gt;
&lt;br /&gt;
== Choosing a topology ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topology !! When !! Trade-offs&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;A. One machine&#039;&#039;&#039; — recorder and portal on the recording PC || one venue, a few viewers on the same LAN, no spare hardware || simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;B. Two machines on the LAN&#039;&#039;&#039; — recorder plus a Linux portal host (NUC, NAS, VM) || the normal case for a venue || the recording PC stays untouched; the portal host does the transcoding; both sides only need a name and a port&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;C. Portal off site&#039;&#039;&#039; — a VPS or a server in the company network, reached over the internet || several venues share one portal, or people watch from home || put a TLS reverse proxy in front; uploads take the venue&#039;s upstream bandwidth, so use the transfer window; the recorder still needs no inbound port&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Rules that hold for every topology:&lt;br /&gt;
&lt;br /&gt;
* The portal is addressed by &#039;&#039;&#039;exactly one name&#039;&#039;&#039; — &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; in its &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;. PeerTube answers the login endpoint only when the &amp;lt;code&amp;gt;Host&amp;lt;/code&amp;gt; header matches it; an IP address or a second alias gets &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;. Pick a name that every browser and the recorder can resolve (DNS, mDNS or a &amp;lt;code&amp;gt;hosts&amp;lt;/code&amp;gt; entry), and use that same name in the recorder&#039;s &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;PEERTUBE_SECRET&amp;lt;/code&amp;gt; is generated once and never changed after the instance has data.&lt;br /&gt;
* Keep the portal on plain HTTP only inside a trusted LAN. Anything reachable from outside gets a reverse proxy with TLS (topology C).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Recommendation:&#039;&#039;&#039; B for a venue, C when the portal serves more than one venue. A is fine to start with and can be split later: the recorder only knows the portal as a URL, so moving the stack means copying the &amp;lt;code&amp;gt;docker/&amp;lt;/code&amp;gt; directory with its &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; to the new host and changing &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Network reference ==&lt;br /&gt;
&lt;br /&gt;
Inbound ports the recorder opens (all configurable in the settings tree):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Port !! Protocol !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| 7000 || UDP || OSC commands || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5900 || TCP || VNC remote UI, only with VNC on || &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5800 || TCP || browser viewer and the links in the reminder mails, only with VNC on; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; switches it off || &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Outbound connections the recorder makes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Target !! Port !! Purpose !! Key&lt;br /&gt;
|-&lt;br /&gt;
| MQTT broker || 1883 TCP || commands in, status out || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| portal || 9000 TCP (443 behind a proxy) || uploads, downloads, fetch-request polling || &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SMTP server || 587 TCP || reminder digest || &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Inbound port the portal opens: &#039;&#039;&#039;9000 TCP&#039;&#039;&#039; (&amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;), or 80/443 on the reverse proxy in topology C.&lt;br /&gt;
&lt;br /&gt;
The MQTT default &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;public&#039;&#039;&#039; broker. Either switch MQTT off or point it at a broker of your own (section &amp;quot;MQTT broker&amp;quot;) before the system goes live.&lt;br /&gt;
&lt;br /&gt;
== Part 1 — The recorder on Windows ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Install.&#039;&#039;&#039; Run &amp;lt;code&amp;gt;Tourette_Stage_Recorder_5.0.&amp;lt;build&amp;gt;.exe&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;tools/installer/&amp;lt;/code&amp;gt;. It installs to &amp;lt;code&amp;gt;C:\Program Files\Tourette Stage Recorder 5.0\&amp;lt;/code&amp;gt; with the FFmpeg libraries, &amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; (used to render H.264 proxies for the portal), the dongle library and the &amp;lt;code&amp;gt;files\&amp;lt;/code&amp;gt; tree, and registers the &amp;lt;code&amp;gt;.mxr&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt; file types. A desktop and a start-menu shortcut are created.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Dongle.&#039;&#039;&#039; Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. First start.&#039;&#039;&#039; Start from the shortcut. The settings file is created at &amp;lt;code&amp;gt;%APPDATA%\mxw_recorder\mxr_recorder.ini&amp;lt;/code&amp;gt;; recordings go to &amp;lt;code&amp;gt;Documents\TouretteStageRecorder&amp;lt;/code&amp;gt; until &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; says otherwise. Every key mentioned in this document appears in the Settings tab&#039;s configuration tree once the application has run once.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Recording root.&#039;&#039;&#039; Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; to the recording disk. If that path is a mount that can go away, know that a missing root at record start is not fatal: the default root stands in and the main tab shows a red banner.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; Windows asks on the first start; allow the application on the &#039;&#039;Private&#039;&#039; profile. If the rig&#039;s network is classified &#039;&#039;Public&#039;&#039;, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder OSC&amp;quot; dir=in action=allow protocol=UDP localport=7000&lt;br /&gt;
netsh advfirewall firewall add rule name=&amp;quot;MXW Recorder VNC&amp;quot; dir=in action=allow protocol=TCP localport=5900,5800&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Proxies for the portal.&#039;&#039;&#039; With &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; off (the default) every take that is not H.264 is encoded to an H.264 proxy with &amp;lt;code&amp;gt;h264_nvenc&amp;lt;/code&amp;gt; before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with &amp;lt;code&amp;gt;T003&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;T004&amp;lt;/code&amp;gt; and the original goes up instead. &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; overrides the lookup (&amp;lt;code&amp;gt;ffmpeg.exe&amp;lt;/code&amp;gt; next to the executable is found on its own).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;7. Restart policy.&#039;&#039;&#039; Settings under &amp;lt;code&amp;gt;/System&amp;lt;/code&amp;gt; are read once at startup. After changing any of them use the red &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
== Part 2 — The recorder on Linux ==&lt;br /&gt;
&lt;br /&gt;
There is no package; the recorder is built from the source tree on the target machine or on an identical one.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Packages&#039;&#039;&#039; (Debian/Ubuntu names; the tree links wxWidgets 3.2 GTK3 with OpenGL, PortAudio from its submodule, system zlib and libcurl):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo apt install build-essential cmake git python3 \&lt;br /&gt;
    libwxgtk3.2-dev libgl1-mesa-dev libasound2-dev \&lt;br /&gt;
    zlib1g-dev libcurl4-openssl-dev ffmpeg&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ffmpeg&amp;lt;/code&amp;gt; (the command line tool) is what renders the portal proxies; the recorder looks for it at &amp;lt;code&amp;gt;/usr/bin/ffmpeg&amp;lt;/code&amp;gt; or wherever &amp;lt;code&amp;gt;/System/FFmpeg Path&amp;lt;/code&amp;gt; points. Zlib and libcurl are fetched and built at configure time when the development packages are missing, so they are optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Build.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone --recurse-submodules &amp;lt;repo&amp;gt; mxw_recorder&lt;br /&gt;
cd mxw_recorder&lt;br /&gt;
mkdir -p build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake .. -DCMAKE_BUILD_TYPE=Release&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result is &amp;lt;code&amp;gt;build/mxw_recorder&amp;lt;/code&amp;gt;. Run it from the &#039;&#039;&#039;repository root&#039;&#039;&#039; — the &amp;lt;code&amp;gt;files/&amp;lt;/code&amp;gt; tree (skin, fonts, translations) is found relative to the working directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /path/to/mxw_recorder &amp;amp;&amp;amp; ./build/mxw_recorder&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Dongle.&#039;&#039;&#039; The Rockey4ND library talks to the dongle over USB; the user running the recorder needs access to that USB device. Add a udev rule for the dongle&#039;s vendor/product id (see &amp;lt;code&amp;gt;lsusb&amp;lt;/code&amp;gt; with the dongle plugged in) that grants the recorder&#039;s group read/write access, then replug.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Settings and recordings.&#039;&#039;&#039; The settings file is &amp;lt;code&amp;gt;mxr_recorder.ini&amp;lt;/code&amp;gt; in the application&#039;s user data directory (by default &amp;lt;code&amp;gt;~/.mxw_recorder/&amp;lt;/code&amp;gt;). Set &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt; after the first start.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Firewall.&#039;&#039;&#039; With &amp;lt;code&amp;gt;ufw&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ufw allow 7000/udp          # OSC&lt;br /&gt;
sudo ufw allow 5900,5800/tcp     # VNC and browser viewer, only with VNC on&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Autostart.&#039;&#039;&#039; For a kiosk, start the recorder from the desktop session&#039;s autostart (it needs a display and OpenGL; a plain systemd service without a session will not do), with the working directory set to the repository root.&lt;br /&gt;
&lt;br /&gt;
== Part 3 — The video portal ==&lt;br /&gt;
&lt;br /&gt;
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory from the source tree. Node.js is not needed on the host; the plugin is packed inside the image build.&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Docker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux (portal host or single machine):&#039;&#039;&#039; install Docker Engine and the Compose plugin from Docker&#039;s repository (&amp;lt;code&amp;gt;docker-ce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker-compose-plugin&amp;lt;/code&amp;gt;), add the operator to the &amp;lt;code&amp;gt;docker&amp;lt;/code&amp;gt; group, log in again. Enable the service so the stack comes back after a reboot: &amp;lt;code&amp;gt;sudo systemctl enable docker&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Windows (single machine):&#039;&#039;&#039; install Docker Desktop with the WSL 2 backend and enable &#039;&#039;Start Docker Desktop when you sign in&#039;&#039;. Two facts matter on this setup:&lt;br /&gt;
** WSL&#039;s &#039;&#039;&#039;mirrored networking&#039;&#039;&#039; mode makes the Linux side own the host&#039;s LAN address. A container can reach the Windows host only through &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt;, not through the LAN IP. That is why the portal never connects to the recorder — nothing to configure, but do not try to make it.&lt;br /&gt;
** Transcoding runs inside WSL and competes with capture. Cap it in &amp;lt;code&amp;gt;%USERPROFILE%\.wslconfig&amp;lt;/code&amp;gt; (for example &amp;lt;code&amp;gt;memory=8GB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;processors=4&amp;lt;/code&amp;gt;) and keep &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; to a single rendition.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Configure and start ===&lt;br /&gt;
&lt;br /&gt;
On the portal host, in a copy of the source tree (or just the &amp;lt;code&amp;gt;tools/portal/&amp;lt;/code&amp;gt; directory):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800&lt;br /&gt;
cd tools/portal/docker&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--env&amp;lt;/code&amp;gt; writes &amp;lt;code&amp;gt;docker/.env&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.env.example&amp;lt;/code&amp;gt; with fresh secrets. Open it and check:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Set it to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME&amp;lt;/code&amp;gt; || the one name the portal is reached by (see &amp;quot;Choosing a topology&amp;quot;); on a single machine &amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt; works for the recorder, but other browsers then need the machine&#039;s name — prefer the name&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;9000&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; on the LAN; &amp;lt;code&amp;gt;443&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; behind a TLS proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PEERTUBE_ADMIN_EMAIL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PT_INITIAL_ROOT_PASSWORD&amp;lt;/code&amp;gt; || the admin account; the setup logs in with this password on every start&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt; || the recorder&#039;s account and channel; the same values go into the recorder&#039;s &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_RECORDER_URL&amp;lt;/code&amp;gt; || informational, shown in the plugin settings; nothing connects to it&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the recorder uploads originals (&amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt;) and the disk can hold them; otherwise only renditions are kept&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;720p&amp;lt;/code&amp;gt; on a single machine, &amp;lt;code&amp;gt;720p,1080p&amp;lt;/code&amp;gt; on a dedicated host&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MXR_INSTANCE_NAME&amp;lt;/code&amp;gt; || the name in the browser tab and in the portal&#039;s mails&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
docker compose logs -f peertube        # wait for &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to &#039;&#039;internal&#039;&#039; (logged-in users only), configures transcoding and uploads the branding. Open &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:9000&amp;lt;/code&amp;gt; in a browser and log in as the recorder user once to confirm.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Offline portal host ===&lt;br /&gt;
&lt;br /&gt;
Build on a machine with internet access, carry the image over:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python3 tools/portal/build_portal.py --save mxr-peertube.tar&lt;br /&gt;
# copy mxr-peertube.tar and tools/portal/docker/ (with .env) to the host&lt;br /&gt;
docker load -i mxr-peertube.tar&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3.4 TLS and the outside world (topology C) ===&lt;br /&gt;
&lt;br /&gt;
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the whole configuration is one block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
portal.example.org {&lt;br /&gt;
    reverse_proxy 127.0.0.1:9000&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; set &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_PORT=443&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PEERTUBE_WEBSERVER_HTTPS=true&amp;lt;/code&amp;gt;; the proxy&#039;s address must be covered by &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;. In the recorder &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;https://portal.example.org&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;/Portal/Use Insecure TLS&amp;lt;/code&amp;gt; is only for a self-signed certificate on a LAN, never for a public host.&lt;br /&gt;
&lt;br /&gt;
=== 3.5 Where the data lives, backup, updates ===&lt;br /&gt;
&lt;br /&gt;
Everything is under &amp;lt;code&amp;gt;tools/portal/docker/volumes/&amp;lt;/code&amp;gt; on the host:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Directory !! Holds&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/db/&amp;lt;/code&amp;gt; || PostgreSQL — videos, chapters, users, the plugin&#039;s records and fetch queue&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/streaming-playlists/hls/&amp;lt;uuid&amp;gt;/&amp;lt;/code&amp;gt; || the transcoded renditions (what a fetch downloads when no original is kept)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/original-video-files/&amp;lt;/code&amp;gt; || uploaded originals, only with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/data/{thumbnails,previews,storyboards,captions,torrents}&amp;lt;/code&amp;gt; || derived assets&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volumes/config/&amp;lt;/code&amp;gt; || PeerTube&#039;s production configuration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Backup:&#039;&#039;&#039; &amp;lt;code&amp;gt;docker compose stop&amp;lt;/code&amp;gt;, copy &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; together, &amp;lt;code&amp;gt;docker compose start&amp;lt;/code&amp;gt;. Database and files belong together — a video row points at its files by uuid.&lt;br /&gt;
* &#039;&#039;&#039;Move to another host:&#039;&#039;&#039; the same copy, then &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt; there and a new &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; in the recorder if the name changed.&lt;br /&gt;
* &#039;&#039;&#039;Update:&#039;&#039;&#039; pull the new source tree, &amp;lt;code&amp;gt;python3 tools/portal/build_portal.py&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;. The setup updates the plugin and theme when their version changed.&lt;br /&gt;
* &#039;&#039;&#039;Disk:&#039;&#039;&#039; originals cost the full take size per upload; renditions cost roughly the proxy bitrate (&amp;lt;code&amp;gt;/Portal/Proxy Bitrate Mbit&amp;lt;/code&amp;gt;, default 12) times the duration. The recorder&#039;s own retention (&amp;lt;code&amp;gt;/Storage/*&amp;lt;/code&amp;gt;) never touches the portal; deleting on the portal is done in its admin, and the recorder&#039;s &#039;&#039;&#039;Re-sync with portal&#039;&#039;&#039; button then drops those takes from its index.&lt;br /&gt;
&lt;br /&gt;
== Part 4 — Connect the recorder to the portal ==&lt;br /&gt;
&lt;br /&gt;
In the recorder&#039;s Settings tab (password from &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/URL&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;http://&amp;lt;PEERTUBE_WEBSERVER_HOSTNAME&amp;gt;:9000&amp;lt;/code&amp;gt; — exactly the name from &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;, no IP&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Password&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_USER&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MXR_RECORDER_PASSWORD&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Channel&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MXR_RECORDER_CHANNEL&amp;lt;/code&amp;gt;, or empty for the user&#039;s default channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Privacy&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;internal&amp;lt;/code&amp;gt; (default): visible to logged-in users only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Upload Original&amp;lt;/code&amp;gt; || on only together with &amp;lt;code&amp;gt;MXR_KEEP_ORIGINAL=true&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Use Transfer While Recording&amp;lt;/code&amp;gt; || off (default) keeps the upload bandwidth and the disk away from a running take&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Portal/Transfer From Hour&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Portal/Transfer To Hour&amp;lt;/code&amp;gt; || a window, e.g. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;7&amp;lt;/code&amp;gt; for nights; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;24&amp;lt;/code&amp;gt; means always&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Save &amp;amp; Restart.&#039;&#039;&#039; Then a smoke test:&lt;br /&gt;
&lt;br /&gt;
* Record a short take, load it in the player, press &#039;&#039;&#039;Publish to portal&#039;&#039;&#039;. The file browser&#039;s flags column runs through &#039;&#039;uploading n %&#039;&#039;; the log says &amp;lt;code&amp;gt;portal: published &amp;lt;name&amp;gt; -&amp;gt; &amp;lt;url&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The Files tab&#039;s &#039;&#039;&#039;Portal&#039;&#039;&#039; view lists it after &#039;&#039;&#039;Reload&#039;&#039;&#039;. Open the portal page: title, tags and the markers as chapters are there.&lt;br /&gt;
* Delete the local file in the browser, press &#039;&#039;&#039;Fetch to local&#039;&#039;&#039; in the Portal view (or &#039;&#039;Bring back to recorder&#039;&#039; on the portal page): the file returns to its date folder, protected, with its markers.&lt;br /&gt;
&lt;br /&gt;
If the login fails with &amp;lt;code&amp;gt;http 403&amp;lt;/code&amp;gt;, the URL is not the configured host name. If the listing fails with &amp;lt;code&amp;gt;T008&amp;lt;/code&amp;gt;, check the account and the channel name.&lt;br /&gt;
&lt;br /&gt;
== Part 5 — MQTT broker ==&lt;br /&gt;
&lt;br /&gt;
Only needed when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker works; Mosquitto is the usual choice.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Linux:&#039;&#039;&#039; &amp;lt;code&amp;gt;sudo apt install mosquitto&amp;lt;/code&amp;gt;, then in &amp;lt;code&amp;gt;/etc/mosquitto/conf.d/lan.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
listener 1883&lt;br /&gt;
allow_anonymous true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;code&amp;gt;sudo systemctl enable --now mosquitto&amp;lt;/code&amp;gt;. Restrict &amp;lt;code&amp;gt;allow_anonymous&amp;lt;/code&amp;gt; to the LAN (bind to the LAN interface, or add a password file) — the recorder supports no broker authentication.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Windows:&#039;&#039;&#039; the Mosquitto installer from mosquitto.org, the same two lines in &amp;lt;code&amp;gt;mosquitto.conf&amp;lt;/code&amp;gt;, installed as a service.&lt;br /&gt;
&lt;br /&gt;
In the recorder: &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; on, &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; = the broker&#039;s name or IP, &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; unique per recorder when several share a broker. Save &amp;amp; Restart. The broker&#039;s log shows &amp;lt;code&amp;gt;mxr-client-…&amp;lt;/code&amp;gt; connecting.&lt;br /&gt;
&lt;br /&gt;
== Part 6 — Reminder mails ==&lt;br /&gt;
&lt;br /&gt;
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a &#039;&#039;keep&#039;&#039; and a &#039;&#039;publish&#039;&#039; link per take. The links point at the recorder&#039;s web port, so they work only for people who can reach the recorder on port 5800.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Use Reminders&amp;lt;/code&amp;gt; || on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Server&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Port&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Use TLS&amp;lt;/code&amp;gt; || the SMTP account, default port 587 with STARTTLS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/User&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/Password&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/Mail/From&amp;lt;/code&amp;gt; || its credentials and sender address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recipients&amp;lt;/code&amp;gt; || comma-separated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Recorder URL&amp;lt;/code&amp;gt; || how recipients reach the recorder, default &amp;lt;code&amp;gt;http://&amp;lt;hostname&amp;gt;:5800&amp;lt;/code&amp;gt;; must match the VNC web port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Mail/Send Hour&amp;lt;/code&amp;gt; || default &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; must be on with a non-zero web port, otherwise &amp;lt;code&amp;gt;N001&amp;lt;/code&amp;gt; warns and the links lead nowhere.&lt;br /&gt;
&lt;br /&gt;
== Checklists ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single machine, Windows (topology A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Installer, dongle, first start, &amp;lt;code&amp;gt;/Recording/Root&amp;lt;/code&amp;gt;&lt;br /&gt;
* Docker Desktop with WSL 2, &amp;lt;code&amp;gt;.wslconfig&amp;lt;/code&amp;gt; limits, &amp;lt;code&amp;gt;MXR_TRANSCODE_RESOLUTIONS=720p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;pc-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; checked, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;, &amp;quot;mxr setup: done&amp;quot;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/*&amp;lt;/code&amp;gt; in the recorder, Save &amp;amp; Restart, smoke test&lt;br /&gt;
* Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC&lt;br /&gt;
* Transfer window set to the hours without shows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two machines (topology B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Recorder as in Part 1 or 2&lt;br /&gt;
* Portal host: Docker Engine enabled at boot, &amp;lt;code&amp;gt;build_portal.py --env --hostname &amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;docker compose up -d&amp;lt;/code&amp;gt;&lt;br /&gt;
* Name resolution for &amp;lt;code&amp;gt;&amp;lt;portal-name&amp;gt;&amp;lt;/code&amp;gt; on the recorder and on the viewers&#039; machines&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = http://&amp;lt;portal-name&amp;gt;:9000&amp;lt;/code&amp;gt;, smoke test&lt;br /&gt;
* Backup plan for &amp;lt;code&amp;gt;volumes/&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Off site (topology C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Everything from B on the server&lt;br /&gt;
* Reverse proxy with TLS, &amp;lt;code&amp;gt;.env&amp;lt;/code&amp;gt; on 443/https, &amp;lt;code&amp;gt;PEERTUBE_TRUST_PROXY&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;/Portal/URL = https://…&amp;lt;/code&amp;gt;, transfer window for the venue&#039;s uplink&lt;br /&gt;
* Only 443 open on the server; the recorder needs no inbound port at all&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6223</id>
		<title>Stage Recorder MQTT Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6223"/>
		<updated>2026-09-29T20:40:44Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (MQTT) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling and monitoring Stage Recorder over an &#039;&#039;&#039;MQTT&#039;&#039;&#039; broker. MQTT is an optional bridge over the OSC command tree; see [[Stage Recorder OSC Interface]] for the full command semantics and [[Stage Recorder User Interface]] for on-screen operation.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Inbound MQTT messages are converted into OSC packets and injected into the OSC receive loop on localhost — there is no separate MQTT command handler. The entire OSC routing tree therefore applies to MQTT as well. MQTT additionally provides &#039;&#039;&#039;outbound status&#039;&#039;&#039; publishing that OSC does not.&lt;br /&gt;
&lt;br /&gt;
MQTT runs on a dedicated background thread with automatic reconnection.&lt;br /&gt;
&lt;br /&gt;
== Transport and Connection ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || TCP || —&lt;br /&gt;
|-&lt;br /&gt;
| Broker address || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Broker port || &#039;&#039;&#039;1883&#039;&#039;&#039; || — (fixed)&lt;br /&gt;
|-&lt;br /&gt;
| Client ID || &amp;lt;code&amp;gt;mxr-client-&amp;lt;4 random chars&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Subscribe pattern || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Enabled || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| QoS || 1 || —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To disable MQTT, set &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Topic Structure ==&lt;br /&gt;
&lt;br /&gt;
Inbound (command) topics follow this pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/channel/&amp;lt;n&amp;gt;/&amp;lt;receiver&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/sync_control&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/schedule&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; is matched by the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; wildcard in the default subscribe pattern &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt;. The value is not validated; it exists to distinguish multiple recorders on one broker. With the default pattern the recorder accepts commands from any system-id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Topic → OSC mapping:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! MQTT topic pattern !! OSC address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Topics that match none of these patterns generate error &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Payload Format ==&lt;br /&gt;
&lt;br /&gt;
The payload is a &#039;&#039;&#039;space-separated plain-text string&#039;&#039;&#039;. Each whitespace-delimited token is type-detected, in order:&lt;br /&gt;
&lt;br /&gt;
# parses as a &#039;&#039;&#039;long integer&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
# parses as a &#039;&#039;&#039;double&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt;&lt;br /&gt;
# otherwise → stored as &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting argument list is forwarded to OSC exactly as described in [[Stage Recorder OSC Interface]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command reference:&#039;&#039;&#039; the available &amp;lt;code&amp;gt;&amp;lt;receiver&amp;gt;&amp;lt;/code&amp;gt; commands and their arguments are identical to OSC:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload examples&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;open &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;seek &amp;lt;ms&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_speed &amp;lt;0.0..1.0&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_with_duration &amp;lt;seconds&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_preemptive [seconds]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_camera &amp;lt;camera&amp;gt; [cell]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_end_time &amp;lt;unix&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;ch...&amp;gt; player|recorder &amp;lt;command&amp;gt; [args]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;open &amp;lt;filepath&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;taskadd_local &amp;lt;unix&amp;gt; &amp;lt;osc_address&amp;gt; [args]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The payload is split on spaces, except after &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt;: the rest of the payload is the file name, spaces included.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  open M:/takes/2026.09.25/taz_Integrated Camera_Channel01.mp4&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;open&amp;quot;  &amp;quot;M:/takes/2026.09.25/taz_Integrated Camera_Channel01.mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  play&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  seek 15000&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;seek&amp;quot;  15000&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  set_speed 0.1&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;set_speed&amp;quot;  0.1f&lt;br /&gt;
          (slow motion at a tenth of normal speed)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  set_speed 1&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;set_speed&amp;quot;  1&lt;br /&gt;
          (back to normal speed — note &amp;quot;1&amp;quot; is tokenized as int32,&lt;br /&gt;
           not float, which the handler accepts as well)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_with_duration 3600&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;&lt;br /&gt;
          (pre-roll = configured Preemptive Recording Time)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive 5&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;  5&lt;br /&gt;
          (recording begins 5 s before the message arrived)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  set_camera 3&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;set_camera&amp;quot;  3&lt;br /&gt;
          (the running recording switches to input pair 3)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  set_camera Integrated Camera 2&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;set_camera&amp;quot;  &amp;quot;Integrated Camera&amp;quot;  2&lt;br /&gt;
          (cell 2 of a multi-source recording; the name is reassembled&lt;br /&gt;
           from the space separated tokens)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/sync_control&lt;br /&gt;
Payload:  1 2 recorder start&lt;br /&gt;
-&amp;gt; OSC:   /mxr/sync_control  1  2  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Status Publishing (Outbound) ==&lt;br /&gt;
&lt;br /&gt;
The recorder and player publish state changes to the broker automatically. Messages are enqueued from the recording/playback threads and sent on the MQTT worker thread. &amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; comes from &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is the 1-based channel index; &amp;lt;code&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; is the absolute path.&lt;br /&gt;
&lt;br /&gt;
=== Recorder Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording begins&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording ends&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;camera &amp;lt;cell&amp;gt; &amp;lt;capture device&amp;gt;&amp;lt;/code&amp;gt; || A camera switch took effect on that cell&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A camera switch is only reported once it has actually been carried out on the recording thread, so a refused or impossible switch stays silent (and is logged as &amp;lt;code&amp;gt;R011&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;R010&amp;lt;/code&amp;gt;). A &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; query answers with the recording state and, while recording, with one &amp;lt;code&amp;gt;camera&amp;lt;/code&amp;gt; message per cell - enough for a remote control to rebuild its state after a reconnect.&lt;br /&gt;
&lt;br /&gt;
=== Player Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || A file is loaded and the player becomes active&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || The player is torn down / file unloaded&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || Playback resumed (from the transport button or a &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; command)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || Playback paused&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || Soft stop (paused and rewound to 0). A subsequent hard stop unloads the file and reports &amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;player_started&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt; messages carry the filename, so a control surface can show &#039;&#039;which&#039;&#039; file is loaded; the bare &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; messages report the live transport state. Note these are published on the &amp;lt;code&amp;gt;.../player/status&amp;lt;/code&amp;gt; topic — &#039;&#039;&#039;not&#039;&#039;&#039; on the bare &amp;lt;code&amp;gt;.../player&amp;lt;/code&amp;gt; command topic, which the application subscribes to.&lt;br /&gt;
&lt;br /&gt;
=== On-Demand Status Query ===&lt;br /&gt;
&lt;br /&gt;
Publish &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; to a command topic and the matching &amp;lt;code&amp;gt;.../status&amp;lt;/code&amp;gt; topic is published immediately with the current state, in the same format as the spontaneous messages:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Query topic (inbound) !! Response topic (outbound) !! Response payload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;player_stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If nothing has been recorded/loaded yet, the filename is empty (e.g. &amp;lt;code&amp;gt;stopped &amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;player_stopped &amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — query and response:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# query (inbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder&lt;br /&gt;
Payload:  status&lt;br /&gt;
&lt;br /&gt;
# response (outbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder/status&lt;br /&gt;
Payload:  started C:\recordings\2026-04-16_143012_ch2.mp4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Codes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Message !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO001&amp;lt;/code&amp;gt; || MQTT cannot resolve broker address || DNS lookup for the broker failed&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO002&amp;lt;/code&amp;gt; || MQTT receive callback exception || Unhandled exception in the receive handler&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt; || MQTT JSON payload not yet implemented || Payload starts with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt; || MQTT cannot assign topic &amp;lt;code&amp;gt;&amp;lt;topic&amp;gt;&amp;lt;/code&amp;gt; || Topic matches no known pattern&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* JSON payloads are not implemented (error &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The broker port is fixed at 1883.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder OSC Interface]] — full command semantics and the configuration reference.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6222</id>
		<title>Stage Recorder OSC Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6222"/>
		<updated>2026-09-29T20:40:43Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (OSC) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling Stage Recorder over &#039;&#039;&#039;OSC&#039;&#039;&#039; (Open Sound Control). For the equivalent MQTT interface see [[Stage Recorder MQTT Interface]]; for the on-screen interface see [[Stage Recorder User Interface]].&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OSC is the primary remote-control protocol. MQTT commands are internally converted to OSC and injected into the same receive loop, so the entire address space below applies equally to both protocols.&lt;br /&gt;
&lt;br /&gt;
All OSC processing happens on the main (render) thread: messages arrive on a UDP thread, are queued, and drained one per rendered frame. OSC bundles are supported — each message in a bundle is processed individually, in order.&lt;br /&gt;
&lt;br /&gt;
== Transport ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || UDP || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen address || ANY (0.0.0.0) || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen port || &#039;&#039;&#039;7000&#039;&#039;&#039; || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The port is read once at startup; changing it requires a restart.&lt;br /&gt;
&lt;br /&gt;
== Address Space ==&lt;br /&gt;
&lt;br /&gt;
Every address must begin with &amp;lt;code&amp;gt;/mxr&amp;lt;/code&amp;gt;; the first token is stripped before dispatch.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player     &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder   &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/sync_control           [args]&lt;br /&gt;
/mxr/schedule               &amp;lt;command&amp;gt; [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;1-based&#039;&#039;&#039; channel index.&lt;br /&gt;
&lt;br /&gt;
== Player Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;filename:string&amp;gt;&amp;lt;/code&amp;gt; || Open a media file. Resets markers. The file is opened asynchronously and starts paused at position 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || — || Resume playback (unpause). Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || — || Pause playback. Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop playback. With soft-stop enabled, the first call rewinds to 0 and pauses; the second call (or if soft-stop is disabled) unloads the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;milliseconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Seek to an absolute position in milliseconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; || — || Jump to the previous cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; || — || Jump to the next cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current position.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_speed&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;speed:float&amp;gt;&amp;lt;/code&amp;gt; || Frame-based slow motion. &amp;lt;code&amp;gt;0.0&amp;lt;/code&amp;gt; holds the current frame, &amp;lt;code&amp;gt;1.0&amp;lt;/code&amp;gt; is normal speed; values outside the range are clamped. Below normal speed consecutive frames are blended in a shader so motion stays smooth, and audio is muted — it cannot be stretched without shifting pitch. Also accepted as &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current player status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* Commands that need an open file (&amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;go_marker_*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt;) are silently ignored when no file is loaded.&lt;br /&gt;
* &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; is asynchronous. &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;set_speed&amp;lt;/code&amp;gt; sent while the file is still opening (in a bundle, or without waiting for &amp;lt;code&amp;gt;player_started&amp;lt;/code&amp;gt;) are kept and applied the moment the player activates, in the order seek, speed, play/pause. Other commands sent that early are ignored.&lt;br /&gt;
* Soft-stop is configured via &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example bundle — open, seek to start, play:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#bundle&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;open&amp;quot;  &amp;quot;/media/clip.mp4&amp;quot;&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;seek&amp;quot;  0&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Recorder Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; || — || Begin recording with the channel&#039;s selected recording profile. Any active playback on the channel is stopped first.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop the active recording. Writes cue markers into the file as metadata, then auto-loads the recorded clip into the player (paused at 0).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;seconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Start recording and schedule an automatic stop after the given number of seconds. Registers a task visible in the Schedule tab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;[seconds:int32]&amp;lt;/code&amp;gt; || Start recording &#039;&#039;including material captured before the command arrived&#039;&#039;, to compensate for reaction time. Without an argument the configured &#039;&#039;Preemptive Recording Time&#039;&#039; is used; with one, that many seconds, clamped to 0–100 and to what the buffer currently holds. Requires &#039;&#039;Preemptive Recording Time&#039;&#039; to be above 0 — see the notes below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_camera&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;camera&amp;gt; [cell:int32]&amp;lt;/code&amp;gt; || Switch the camera feeding a running recording. See the notes below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_end_time&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;unix_timestamp:int32&amp;gt;&amp;lt;/code&amp;gt; || Update the scheduled stop time of an active recording. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current recording position. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current recorder status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* On &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, the finished file is immediately opened in the channel&#039;s player.&lt;br /&gt;
* The scheduled stop from &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; is also polled on every render frame as a safety net.&lt;br /&gt;
* Timestamps use the Unix epoch; the &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt; wire type is subject to the Y2038 limit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Camera switching:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;set_camera&amp;lt;/code&amp;gt; changes the source of a running recording without interrupting it. The file keeps the frame size, the encoder and the timeline it was opened with — only the picture content changes, from the next frame on.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;camera&amp;gt;&amp;lt;/code&amp;gt; is an &#039;&#039;&#039;input pair index&#039;&#039;&#039; (1-based &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;), an &#039;&#039;&#039;input pair name&#039;&#039;&#039;, or a &#039;&#039;&#039;capture device name&#039;&#039;&#039;. Names are matched case-insensitively, input pairs first.&lt;br /&gt;
* &amp;lt;code&amp;gt;[cell]&amp;lt;/code&amp;gt; addresses one source of a multi-source recording (1-based) and defaults to the master source, which also drives the output frame rate.&lt;br /&gt;
* Sources of a different resolution or aspect ratio are &#039;&#039;&#039;scaled aspect preserving&#039;&#039;&#039; into the cell and centred; the remaining bars are black. A camera cannot change the frame size of a file that is already being written.&lt;br /&gt;
* The target must be a &#039;&#039;&#039;running capture source&#039;&#039;&#039;, that is, configured as an input pair. Opening a device on demand would block the render thread for as long as the driver needs, so an unknown or stopped camera is refused and logged as &amp;lt;code&amp;gt;R011&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Switching also works while the preemptive buffer is armed: it is the same encoder throughout, so the switch is not a splice and the pre-roll stays decodable across it.&lt;br /&gt;
* A switch applies to the &#039;&#039;&#039;running take&#039;&#039;&#039;. The next recording starts from the input pairs of the recording profile again.&lt;br /&gt;
* Only the &#039;&#039;&#039;video&#039;&#039;&#039; source changes. The audio stream was opened with the channel count and sample rate of the first input pair&#039;s audio input and keeps running unchanged — the recording does not follow the new camera&#039;s audio.&lt;br /&gt;
* Every switch that took effect is published as &amp;lt;code&amp;gt;camera &amp;lt;cell&amp;gt; &amp;lt;capture device&amp;gt;&amp;lt;/code&amp;gt; on the recorder status topic — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — switch channel 1 to the camera of input pair 2:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/channel/1/recorder  &amp;quot;set_camera&amp;quot;  2&lt;br /&gt;
/mxr/channel/1/recorder  &amp;quot;set_camera&amp;quot;  &amp;quot;Stage Wide&amp;quot;&lt;br /&gt;
/mxr/channel/1/recorder  &amp;quot;set_camera&amp;quot;  &amp;quot;Integrated Camera&amp;quot;  2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preemptive recording:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; only reaches back in time when &#039;&#039;Settings → Recording Profile → Preemptive Recording Time&#039;&#039; is above 0. That setting is what keeps the encoders running continuously and the buffer filled; at 0 nothing is buffered.&lt;br /&gt;
* If no buffer is armed the recording still starts, but without pre-roll, and error &amp;lt;code&amp;gt;R008&amp;lt;/code&amp;gt; is logged. A remote caller cannot otherwise distinguish the two cases.&lt;br /&gt;
* After the setting is changed, the buffer needs that many seconds to fill before a full pre-roll is available. In the user interface the &amp;lt;code&amp;gt;+n&amp;lt;/code&amp;gt; button stays disabled until then; over the network an early &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; simply returns less pre-roll than requested.&lt;br /&gt;
* The recording begins at the nearest keyframe at or before the requested point, so the result may contain slightly more than the requested seconds. A shorter GOP in the recording profile tightens this.&lt;br /&gt;
* The reported start time and the recording&#039;s own timeline begin at the &#039;&#039;pre-roll&#039;&#039; start, not at the moment the command arrived.&lt;br /&gt;
&lt;br /&gt;
== Sync Control ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This endpoint has two independent forms.&lt;br /&gt;
&lt;br /&gt;
=== Open a Sync-Set File ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;quot;open&amp;quot;  &amp;quot;&amp;lt;filepath:string&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Opens a sync-set (&amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt;). For each stored channel it stops the recorder, opens the stored file in the player, pauses, and seeks to 0; it also restores the saved channel selection.&lt;br /&gt;
&lt;br /&gt;
=== Fan-Out Command to Multiple Channels ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch1:int32&amp;gt;  [ch2:int32 ...]  &amp;lt;receiver:string&amp;gt;  &amp;lt;command:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1..N || int32 || Target channel indices (1-based). All leading integers form the channel set.&lt;br /&gt;
|-&lt;br /&gt;
| N+1 || string || Receiver: &amp;lt;code&amp;gt;&amp;quot;player&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;recorder&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| N+2 || string || Command (any valid player or recorder command)&lt;br /&gt;
|-&lt;br /&gt;
| N+3.. || mixed || Optional command arguments&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
One message per target channel is emitted as a single OSC bundle, so all channels are addressed atomically.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channels 1, 2 and 4:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  4  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — seek all channels to 30 000 ms:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  3  &amp;quot;player&amp;quot;  &amp;quot;seek&amp;quot;  30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  &amp;lt;unix_timestamp:int32&amp;gt;  &amp;lt;osc_address:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || string || Must be &amp;lt;code&amp;gt;&amp;quot;taskadd_local&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 2 || int32 || Unix epoch time at which the task fires&lt;br /&gt;
|-&lt;br /&gt;
| 3 || string || OSC address to send when the task fires (e.g. &amp;lt;code&amp;gt;/mxr/channel/1/recorder&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 4.. || mixed || Arguments to include in the fired message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
At execution time the scheduler sends the stored address and arguments as an OSC message to the local port. Tasks are one-shot and are removed after firing. The task list persists in the project file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channel 2 at a specific time:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — record for exactly 3600 seconds:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Argument Types ==&lt;br /&gt;
&lt;br /&gt;
OSC arguments are typed on the wire. The following types are accepted:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! OSC type tag !! Type !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; || string || UTF-8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; || int32 || Most common numeric type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; || int64 || Treated as int32 internally&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; || float ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Unrecognised types are logged and skipped.&lt;br /&gt;
&lt;br /&gt;
== Quick Reference ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Player&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  open &amp;lt;file&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  play | pause | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  seek &amp;lt;ms&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  go_marker_back | go_marker_forward | set_marker | status&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  set_speed &amp;lt;0.0..1.0&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Recorder&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_with_duration &amp;lt;seconds&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_preemptive [seconds]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_camera &amp;lt;camera&amp;gt; [cell]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_end_time &amp;lt;unix_timestamp&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_marker | status&lt;br /&gt;
&lt;br /&gt;
# Sync — fan-out / open sync-set&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch&amp;gt; [ch ...]  player|recorder  &amp;lt;command&amp;gt;  [args]&lt;br /&gt;
/mxr/sync_control  open  &amp;lt;filepath&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Scheduler&lt;br /&gt;
/mxr/schedule  taskadd_local  &amp;lt;unix_timestamp&amp;gt;  &amp;lt;osc_address&amp;gt;  [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration Reference ==&lt;br /&gt;
&lt;br /&gt;
Keys are stored in the platform-native configuration (Windows Registry; INI file on Linux/macOS).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Type !! Default !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;7000&amp;lt;/code&amp;gt; || UDP port to listen on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Enable/disable MQTT&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || MQTT broker hostname&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr-client-&amp;lt;rnd&amp;gt;&amp;lt;/code&amp;gt; || MQTT client identifier&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || MQTT subscription topic filter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || System identifier used in the outbound status topic prefix&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Two-stage stop behaviour for the player&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt; || Password for the Settings tab&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; || Serve the user interface to VNC viewers on the LAN (restart required)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Port&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;5900&amp;lt;/code&amp;gt; || VNC port&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Password&amp;lt;/code&amp;gt; || string || &#039;&#039;(empty)&#039;&#039; || Not enforced in this build (no VNC authentication without OpenSSL); a set value is logged as a warning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Frame Rate&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; || Screen captures per second sent to viewers&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Scale&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;100&amp;lt;/code&amp;gt; || Size of the picture sent to viewers, in percent (25–100, steps of 5)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Name&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;Tourette Stage Recorder&amp;lt;/code&amp;gt; || Name a viewer shows in its title bar&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/VNC/Web Port&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;5800&amp;lt;/code&amp;gt; || Browser viewer: &amp;lt;code&amp;gt;http://&amp;amp;lt;recorder&amp;amp;gt;:&amp;amp;lt;port&amp;amp;gt;/&amp;lt;/code&amp;gt;. 0 switches it off&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/Use 10 Bit Recording&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; || Run capture, compositing, encoding and textures at 10 bit (restart required)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/Use 10 Bit Display&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; || Also ask the window and the program outputs for a 10 bit visual (restart required)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder MQTT Interface]] — the same command tree over an MQTT broker, plus outbound status.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_User_Interface&amp;diff=6221</id>
		<title>Stage Recorder User Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_User_Interface&amp;diff=6221"/>
		<updated>2026-09-29T20:40:42Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — User Interface =&lt;br /&gt;
&lt;br /&gt;
Stage Recorder is a professional multi-channel media recorder and player. This page documents the on-screen interface. For controlling the application over the network, see [[Stage Recorder OSC Interface]] and [[Stage Recorder MQTT Interface]].&lt;br /&gt;
&lt;br /&gt;
The interface is a single full-screen window built with Dear ImGui on an OpenGL surface. It is designed for touch panels as well as mouse operation — every text field opens an on-screen keyboard when focused.&lt;br /&gt;
&lt;br /&gt;
== Window Layout ==&lt;br /&gt;
&lt;br /&gt;
The window is divided into a large content area and a &#039;&#039;&#039;tab bar&#039;&#039;&#039; along the bottom edge. The tab bar switches the content area between the four main views and also hosts global actions:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Tab / Button !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Channels&#039;&#039;&#039; || Live recorder/player operation — the main working view. See [[#Channels Tab]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Schedule&#039;&#039;&#039; || Time-based recording tasks and iCal import/export. See [[#Schedule Tab]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Files&#039;&#039;&#039; || Browse, preview, load and delete recorded media. See [[#Files Tab]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Settings&#039;&#039;&#039; || Inputs, outputs, recording/playback profiles and system configuration. See [[#Settings Tab]].&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;(right edge)&#039;&#039; || Current date and time.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; || Appears in red only when a setting was changed that requires a restart to take effect. Saves the project and offers to relaunch the application.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== On-Screen Keyboard ===&lt;br /&gt;
&lt;br /&gt;
Every editable text field (channel names, project name, profile names, filter text, settings values, passwords) opens a virtual keyboard when tapped or clicked. Press &#039;&#039;&#039;Enter&#039;&#039;&#039; to commit; the keyboard is intended for kiosk/touch installations without a physical keyboard.&lt;br /&gt;
&lt;br /&gt;
== Channels Tab ==&lt;br /&gt;
&lt;br /&gt;
The Channels tab is the primary operating view. It shows:&lt;br /&gt;
&lt;br /&gt;
* a &#039;&#039;&#039;project name bar&#039;&#039;&#039; at the top,&lt;br /&gt;
* one panel per licensed &#039;&#039;&#039;channel&#039;&#039;&#039; (up to four side by side per screen width),&lt;br /&gt;
* a shared &#039;&#039;&#039;Channel Control&#039;&#039;&#039; strip at the bottom for synchronised operation.&lt;br /&gt;
&lt;br /&gt;
The number of channels is determined by the license dongle. Without a dongle the application starts with no channels and shows a warning.&lt;br /&gt;
&lt;br /&gt;
=== Project Name Bar ===&lt;br /&gt;
&lt;br /&gt;
Displays the current project name and its file path. The &#039;&#039;&#039;...&#039;&#039;&#039; button opens a popup to rename the project; renaming also moves the project&#039;s working directory.&lt;br /&gt;
&lt;br /&gt;
=== Channel Panel ===&lt;br /&gt;
&lt;br /&gt;
Each channel is an independent recorder &#039;&#039;and&#039;&#039; player. A channel automatically shows the &#039;&#039;&#039;player&#039;&#039;&#039; when a file is loaded, and the &#039;&#039;&#039;recorder&#039;&#039;&#039; otherwise.&lt;br /&gt;
&lt;br /&gt;
The panel contains, top to bottom:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Channel name&#039;&#039;&#039; — click to edit.&lt;br /&gt;
* &#039;&#039;&#039;⚙ (cog) button&#039;&#039;&#039; — toggles the channel between &#039;&#039;operation mode&#039;&#039; and &#039;&#039;settings mode&#039;&#039;. In settings mode the channel shows its recording-profile and playback-profile selectors instead of the video preview.&lt;br /&gt;
* &#039;&#039;&#039;Video preview&#039;&#039;&#039; — the live camera image (recorder) or the current frame (player). Multi-source recording profiles show a grid of source previews.&lt;br /&gt;
* &#039;&#039;&#039;Sound button&#039;&#039;&#039; — overlaid on the top-left of the preview. When more than one player is active, this acts as a radio button selecting which channel&#039;s audio is routed to the outputs (only one channel plays audio at a time).&lt;br /&gt;
* &#039;&#039;&#039;Seek slider&#039;&#039;&#039; — playback position / duration; drag to seek (player only).&lt;br /&gt;
* &#039;&#039;&#039;Transport controls&#039;&#039;&#039;:&lt;br /&gt;
** Player: skip-to-start, previous marker, next marker, &#039;&#039;&#039;...&#039;&#039;&#039; (open file), &#039;&#039;&#039;Play&#039;&#039;&#039;, &#039;&#039;&#039;Pause&#039;&#039;&#039;, &#039;&#039;&#039;Stop&#039;&#039;&#039;.&lt;br /&gt;
** Recorder: &#039;&#039;&#039;Record&#039;&#039;&#039; and &#039;&#039;&#039;Stop&#039;&#039;&#039; (shown when no file is loaded).&lt;br /&gt;
* &#039;&#039;&#039;Camera selector&#039;&#039;&#039; — while a recording runs, one combo per recorded source shows which camera feeds it and switches it on the spot. See [[#Switching Cameras During a Recording]].&lt;br /&gt;
* &#039;&#039;&#039;Marker controls / aux panel&#039;&#039;&#039; — cue-point list. The aux panel opens automatically when the first marker is set during recording, or when a loaded file already contains markers.&lt;br /&gt;
&lt;br /&gt;
==== Two-Stage Stop (Soft Stop) ====&lt;br /&gt;
&lt;br /&gt;
The player &#039;&#039;&#039;Stop&#039;&#039;&#039; button is two-stage when soft-stop is enabled (default):&lt;br /&gt;
&lt;br /&gt;
# First press — pause and rewind to position 0 (the file stays loaded).&lt;br /&gt;
# Second press — unload the file (the channel returns to recorder view).&lt;br /&gt;
&lt;br /&gt;
Soft-stop can be disabled via &#039;&#039;&#039;Settings → /Playback/Use Softstop&#039;&#039;&#039;. The same behaviour applies to the `stop` command received over OSC/MQTT.&lt;br /&gt;
&lt;br /&gt;
==== Switching Cameras During a Recording ====&lt;br /&gt;
&lt;br /&gt;
While a channel records, a &#039;&#039;&#039;Camera&#039;&#039;&#039; combo appears above the transport row — one per recorded source, labelled &#039;&#039;Camera 1&#039;&#039;, &#039;&#039;Camera 2&#039;&#039; … for a multi-source profile. Picking another entry switches that source without interrupting the recording: the file keeps its frame size and timeline, and the picture changes from the next frame on.&lt;br /&gt;
&lt;br /&gt;
* The list offers every configured &#039;&#039;&#039;input pair&#039;&#039;&#039;; an entry whose capture source is not running is greyed out. A camera that should be switchable therefore has to be set up as an input pair in &#039;&#039;&#039;Settings&#039;&#039;&#039; — it is then started with the application.&lt;br /&gt;
* A camera with a different resolution or aspect ratio is &#039;&#039;&#039;scaled aspect preserving&#039;&#039;&#039; and centred in the frame, with black bars on the remaining sides. The frame size of a file that is already being written cannot change.&lt;br /&gt;
* The preview follows the switch, so the channel always shows what is actually being recorded.&lt;br /&gt;
* Switching also works while the preemptive buffer is armed, including inside the pre-roll.&lt;br /&gt;
&lt;br /&gt;
The same switch can be triggered remotely — see [[Stage Recorder OSC Interface#Recorder Commands]] (&amp;lt;code&amp;gt;set_camera&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Recording → Playback Hand-off ====&lt;br /&gt;
&lt;br /&gt;
When a recording is stopped, its cue markers are written into the file as metadata and the finished clip is immediately opened in the same channel&#039;s player (paused at position 0), so it can be reviewed at once.&lt;br /&gt;
&lt;br /&gt;
=== Channel Control (Synchronised Operation) ===&lt;br /&gt;
&lt;br /&gt;
The strip below the channel panels drives &#039;&#039;&#039;several channels at once&#039;&#039;&#039;. Select the target channels with the checkboxes, then use the shared transport row:&lt;br /&gt;
&lt;br /&gt;
* skip-to-start · previous marker · next marker · &#039;&#039;&#039;Play&#039;&#039;&#039; · &#039;&#039;&#039;Pause&#039;&#039;&#039; · &#039;&#039;&#039;Stop&#039;&#039;&#039; · &#039;&#039;&#039;Record&#039;&#039;&#039; (red) · &#039;&#039;&#039;Set marker&#039;&#039;&#039;,&lt;br /&gt;
* a shared seek slider,&lt;br /&gt;
* &#039;&#039;&#039;Open sync-set&#039;&#039;&#039; (📄) and &#039;&#039;&#039;Save sync-set&#039;&#039;&#039; (💾) buttons.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;sync-set&#039;&#039;&#039; (`.mxr_syncset`) stores, per channel, the loaded filename and the channel selection, so a multi-channel arrangement can be recalled in one action. Internally, these controls emit the same commands as the network protocol, fanned out to the selected channels — see [[Stage Recorder OSC Interface#Sync Control]].&lt;br /&gt;
&lt;br /&gt;
== Schedule Tab ==&lt;br /&gt;
&lt;br /&gt;
The Schedule tab manages time-based recording tasks. Each task starts (and optionally stops) a recording on one or more channels at a given wall-clock time.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Create new task&#039;&#039;&#039; — opens a dialog with a calendar date picker, start-time spinners (hour/min/sec), an optional &#039;&#039;&#039;Include stop&#039;&#039;&#039; duration, and channel checkboxes.&lt;br /&gt;
* &#039;&#039;&#039;Export .ics&#039;&#039;&#039; — writes all tasks to an iCal file (RFC 5545).&lt;br /&gt;
* &#039;&#039;&#039;Import .ics&#039;&#039;&#039; — drag a `.ics` file onto the window &#039;&#039;while the Schedule tab is open&#039;&#039;. A dialog lists every calendar event with a checkbox to import it and a channel assignment; events without an assigned channel are highlighted and skipped. Generic calendar events (with an end time) are imported as fixed-duration recordings.&lt;br /&gt;
&lt;br /&gt;
Each row in the &#039;&#039;&#039;task list&#039;&#039;&#039; shows the task name, a live countdown, and the scheduled time. Tasks can be &#039;&#039;&#039;Edit&#039;&#039;&#039;ed or, with &#039;&#039;&#039;Ctrl+Click&#039;&#039;&#039; on the ✖ button, deleted. A channel that is currently mid-recording under a scheduled stop shows a red &#039;&#039;&#039;Recording&#039;&#039;&#039; indicator.&lt;br /&gt;
&lt;br /&gt;
Tasks are stored in the project file and persist across restarts. See also [[Stage Recorder OSC Interface#Scheduler]].&lt;br /&gt;
&lt;br /&gt;
== Files Tab ==&lt;br /&gt;
&lt;br /&gt;
The Files tab browses recorded media within the current project directory.&lt;br /&gt;
&lt;br /&gt;
The header offers a &#039;&#039;&#039;project selector&#039;&#039;&#039; (choose which project directory to browse), a &#039;&#039;&#039;Filter&#039;&#039;&#039; field (comma-separated substrings), &#039;&#039;&#039;Reload&#039;&#039;&#039; (rebuild thumbnails/metadata) and &#039;&#039;&#039;Open project directory in file browser&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Each file row shows:&lt;br /&gt;
&lt;br /&gt;
* the file name with its &#039;&#039;&#039;duration&#039;&#039;&#039; and &#039;&#039;&#039;size&#039;&#039;&#039;,&lt;br /&gt;
* a &#039;&#039;&#039;thumbnail&#039;&#039;&#039; (generated in the background and cached; click to enlarge),&lt;br /&gt;
* one &#039;&#039;&#039;Player n&#039;&#039;&#039; button per channel to load the file into that channel (the button is disabled/highlighted if the file is already loaded there).&lt;br /&gt;
&lt;br /&gt;
Right-click a file for a &#039;&#039;&#039;Delete&#039;&#039;&#039; option (files in use cannot be deleted). Sync-set files (`.mxr_syncset`) instead show a &#039;&#039;&#039;Sync Control&#039;&#039;&#039; button that recalls the stored arrangement.&lt;br /&gt;
&lt;br /&gt;
Thumbnails and file metadata are cached on disk and validated against each file&#039;s modification time, so browsing large directories stays responsive.&lt;br /&gt;
&lt;br /&gt;
== Settings Tab ==&lt;br /&gt;
&lt;br /&gt;
The Settings tab is password-protected (default key `123456`, configurable at `/System/SettingsKey`). It presents several tables:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Contents&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Input pairs&#039;&#039;&#039; || Per channel: a display name, the &#039;&#039;&#039;video&#039;&#039;&#039; capture source, a capture &#039;&#039;&#039;size&#039;&#039;&#039; (Default, a preset, or Custom WIDTHxHEIGHT), and the &#039;&#039;&#039;audio&#039;&#039;&#039; capture source.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Output pairs&#039;&#039;&#039; || Per channel: a display name, the target &#039;&#039;&#039;monitor&#039;&#039;&#039; (video output), and the &#039;&#039;&#039;audio sink&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Recording profiles&#039;&#039;&#039; || Per channel: name, selected input pair(s), &#039;&#039;&#039;codec&#039;&#039;&#039;, and &#039;&#039;&#039;GOP&#039;&#039;&#039; size. Multi-source recording is available; sources whose resolution does not match the first selected source are disabled. GOP does not apply to ProRes; NVENC H.264 enforces a minimum GOP of 4.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Playback profiles&#039;&#039;&#039; || Per channel: name and the set of output pairs the player feeds.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;System configuration&#039;&#039;&#039; || A raw editable tree of every application configuration key (network ports, MQTT settings, etc.). Boolean, integer and string values are edited in place.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Changing most hardware-related settings sets the &#039;&#039;&#039;Save &amp;amp; Restart&#039;&#039;&#039; flag: the change is stored but only takes effect after the application is relaunched.&lt;br /&gt;
&lt;br /&gt;
The full configuration key reference is on the [[Stage Recorder OSC Interface#Configuration Reference]] page.&lt;br /&gt;
&lt;br /&gt;
== Remote User Interface (VNC) ==&lt;br /&gt;
&lt;br /&gt;
The complete on-screen interface can be operated from another machine on the local network with any VNC viewer (RealVNC, TightVNC, UltraVNC, macOS Screen Sharing, …). The recorder acts as a VNC server; the operator connects to the recorder&#039;s IP address and port and sees the same window the local operator sees, including the live previews, and drives it with mouse and keyboard.&lt;br /&gt;
&lt;br /&gt;
Enable it in &#039;&#039;&#039;Settings → &amp;lt;code&amp;gt;/System/IO/VNC/Use VNC&amp;lt;/code&amp;gt;&#039;&#039;&#039; (off by default; the VNC keys appear in the configuration tree from the first start on) and restart. Further keys: &amp;lt;code&amp;gt;Port&amp;lt;/code&amp;gt; (5900), &amp;lt;code&amp;gt;Frame Rate&amp;lt;/code&amp;gt; (captures per second, 10), &amp;lt;code&amp;gt;Scale&amp;lt;/code&amp;gt; (size of the picture sent to viewers in percent, 25–100 in steps of 5, default 100 — VNC viewers do not scale, so a control laptop with a smaller screen than the recorder needs this). &amp;lt;code&amp;gt;Name&amp;lt;/code&amp;gt; is what the viewer shows in its title bar (default &#039;&#039;Tourette Stage Recorder&#039;&#039;). &amp;lt;code&amp;gt;Password&amp;lt;/code&amp;gt; is &#039;&#039;&#039;not enforced&#039;&#039;&#039; in this build — the server has no VNC authentication without OpenSSL — so use it only on a trusted network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From a browser:&#039;&#039;&#039; no viewer software is needed. Open &amp;lt;code&amp;gt;http://&amp;amp;lt;recorder ip&amp;amp;gt;:5800/&amp;lt;/code&amp;gt; (key &amp;lt;code&amp;gt;Web Port&amp;lt;/code&amp;gt;, 0 switches it off) on any machine, tablet or phone on the network — the page scales the recorder&#039;s window to fit, mouse, touch and keyboard drive the interface, and it reconnects by itself after the recorder restarts. On touch devices a keyboard button in the corner raises the on-screen keyboard. The viewer is noVNC, built into the recorder; nothing is installed or served from disk.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* Local and remote input act on the same interface at the same time; the last event wins.&lt;br /&gt;
* Only changed parts of the screen are sent, so a static interface costs almost nothing; a moving preview sends the tiles it covers at the configured frame rate.&lt;br /&gt;
* There is no authentication in this build. Use it on a trusted network behind a firewall only.&lt;br /&gt;
* The connection carries the &#039;&#039;interface&#039;&#039;, not a program signal: for the picture on stage displays use the output windows, for control from other software use OSC or MQTT.&lt;br /&gt;
&lt;br /&gt;
== Colour Depth ==&lt;br /&gt;
&lt;br /&gt;
The application can run its whole picture path at &#039;&#039;&#039;10 bit&#039;&#039;&#039;: capture upload, the preview and program textures, the recording composite and the encoder. It is switched on with &#039;&#039;&#039;Settings → &amp;lt;code&amp;gt;/System/Use 10 Bit Recording&amp;lt;/code&amp;gt;&#039;&#039;&#039; (&#039;&#039;&#039;off by default&#039;&#039;&#039;) and is read once at startup, so a change needs a restart.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Sources&#039;&#039;&#039; — a camera or capture card delivering &#039;&#039;&#039;P010&#039;&#039;&#039; or &#039;&#039;&#039;P016&#039;&#039;&#039; enters the pipeline at ten bits. An 8-bit source does not gain detail, but it no longer picks up the banding that repeated 8-bit conversions add while it is scaled and composited.&lt;br /&gt;
* &#039;&#039;&#039;Recording&#039;&#039;&#039; — the file is written at ten bits when the selected codec can store them. The codec list only offers encoders this build actually has; with the shipped Windows build that means &#039;&#039;&#039;hevc_nvenc&#039;&#039;&#039; and &#039;&#039;&#039;ProRes&#039;&#039;&#039; store 10 bit, while &#039;&#039;&#039;h264_nvenc&#039;&#039;&#039; and &#039;&#039;&#039;h264_qsv&#039;&#039;&#039; are 8-bit by design and record at their own depth. The log names the depth each codec can store.&lt;br /&gt;
* &#039;&#039;&#039;Display&#039;&#039;&#039; — sending ten bits to the screen and to the program outputs is a &#039;&#039;&#039;separate switch&#039;&#039;&#039;, &amp;lt;code&amp;gt;/System/Use 10 Bit Display&amp;lt;/code&amp;gt;, &#039;&#039;&#039;off by default&#039;&#039;&#039;. It is the only part that depends on the graphics driver, the cable and the panel all supporting it. With it off, everything up to the framebuffer still runs at ten bits and recordings are unaffected.&lt;br /&gt;
&lt;br /&gt;
Switching the pipeline off restores the previous 8-bit behaviour exactly.&lt;br /&gt;
&lt;br /&gt;
== Secondary Monitor Output ==&lt;br /&gt;
&lt;br /&gt;
Every non-primary monitor detected at startup receives a borderless &#039;&#039;&#039;output window&#039;&#039;&#039; that displays the channel routed to it (via the output-pair &#039;&#039;&#039;Monitor&#039;&#039;&#039; setting). These windows carry the live program image full-screen with no UI chrome.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder OSC Interface]] — control the application over UDP/OSC.&lt;br /&gt;
* [[Stage Recorder MQTT Interface]] — control and monitor the application over an MQTT broker.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6220</id>
		<title>Stage Recorder MQTT Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6220"/>
		<updated>2026-09-21T10:02:36Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (MQTT) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling and monitoring Stage Recorder over an &#039;&#039;&#039;MQTT&#039;&#039;&#039; broker. MQTT is an optional bridge over the OSC command tree; see [[Stage Recorder OSC Interface]] for the full command semantics and [[Stage Recorder User Interface]] for on-screen operation.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Inbound MQTT messages are converted into OSC packets and injected into the OSC receive loop on localhost — there is no separate MQTT command handler. The entire OSC routing tree therefore applies to MQTT as well. MQTT additionally provides &#039;&#039;&#039;outbound status&#039;&#039;&#039; publishing that OSC does not.&lt;br /&gt;
&lt;br /&gt;
MQTT runs on a dedicated background thread with automatic reconnection.&lt;br /&gt;
&lt;br /&gt;
== Transport and Connection ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || TCP || —&lt;br /&gt;
|-&lt;br /&gt;
| Broker address || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Broker port || &#039;&#039;&#039;1883&#039;&#039;&#039; || — (fixed)&lt;br /&gt;
|-&lt;br /&gt;
| Client ID || &amp;lt;code&amp;gt;mxr-client-&amp;lt;4 random chars&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Subscribe pattern || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Enabled || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| QoS || 1 || —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To disable MQTT, set &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Topic Structure ==&lt;br /&gt;
&lt;br /&gt;
Inbound (command) topics follow this pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/channel/&amp;lt;n&amp;gt;/&amp;lt;receiver&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/sync_control&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/schedule&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; is matched by the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; wildcard in the default subscribe pattern &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt;. The value is not validated; it exists to distinguish multiple recorders on one broker. With the default pattern the recorder accepts commands from any system-id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Topic → OSC mapping:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! MQTT topic pattern !! OSC address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Topics that match none of these patterns generate error &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Payload Format ==&lt;br /&gt;
&lt;br /&gt;
The payload is a &#039;&#039;&#039;space-separated plain-text string&#039;&#039;&#039;. Each whitespace-delimited token is type-detected, in order:&lt;br /&gt;
&lt;br /&gt;
# parses as a &#039;&#039;&#039;long integer&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
# parses as a &#039;&#039;&#039;double&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt;&lt;br /&gt;
# otherwise → stored as &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting argument list is forwarded to OSC exactly as described in [[Stage Recorder OSC Interface]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command reference:&#039;&#039;&#039; the available &amp;lt;code&amp;gt;&amp;lt;receiver&amp;gt;&amp;lt;/code&amp;gt; commands and their arguments are identical to OSC:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload examples&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;open &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;seek &amp;lt;ms&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_speed &amp;lt;0.0..1.0&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_with_duration &amp;lt;seconds&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_preemptive [seconds]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_end_time &amp;lt;unix&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;ch...&amp;gt; player|recorder &amp;lt;command&amp;gt; [args]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;open &amp;lt;filepath&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;taskadd_local &amp;lt;unix&amp;gt; &amp;lt;osc_address&amp;gt; [args]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  play&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  seek 15000&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;seek&amp;quot;  15000&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  set_speed 0.1&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;set_speed&amp;quot;  0.1f&lt;br /&gt;
          (slow motion at a tenth of normal speed)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  set_speed 1&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;set_speed&amp;quot;  1&lt;br /&gt;
          (back to normal speed — note &amp;quot;1&amp;quot; is tokenized as int32,&lt;br /&gt;
           not float, which the handler accepts as well)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_with_duration 3600&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;&lt;br /&gt;
          (pre-roll = configured Preemptive Recording Time)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive 5&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;  5&lt;br /&gt;
          (recording begins 5 s before the message arrived)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/sync_control&lt;br /&gt;
Payload:  1 2 recorder start&lt;br /&gt;
-&amp;gt; OSC:   /mxr/sync_control  1  2  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Status Publishing (Outbound) ==&lt;br /&gt;
&lt;br /&gt;
The recorder and player publish state changes to the broker automatically. Messages are enqueued from the recording/playback threads and sent on the MQTT worker thread. &amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; comes from &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is the 1-based channel index; &amp;lt;code&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; is the absolute path.&lt;br /&gt;
&lt;br /&gt;
=== Recorder Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording begins&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording ends&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Player Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || A file is loaded and the player becomes active&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || The player is torn down / file unloaded&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || Playback resumed (from the transport button or a &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; command)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || Playback paused&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || Soft stop (paused and rewound to 0). A subsequent hard stop unloads the file and reports &amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;player_started&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt; messages carry the filename, so a control surface can show &#039;&#039;which&#039;&#039; file is loaded; the bare &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; messages report the live transport state. Note these are published on the &amp;lt;code&amp;gt;.../player/status&amp;lt;/code&amp;gt; topic — &#039;&#039;&#039;not&#039;&#039;&#039; on the bare &amp;lt;code&amp;gt;.../player&amp;lt;/code&amp;gt; command topic, which the application subscribes to.&lt;br /&gt;
&lt;br /&gt;
=== On-Demand Status Query ===&lt;br /&gt;
&lt;br /&gt;
Publish &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; to a command topic and the matching &amp;lt;code&amp;gt;.../status&amp;lt;/code&amp;gt; topic is published immediately with the current state, in the same format as the spontaneous messages:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Query topic (inbound) !! Response topic (outbound) !! Response payload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;player_stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If nothing has been recorded/loaded yet, the filename is empty (e.g. &amp;lt;code&amp;gt;stopped &amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;player_stopped &amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — query and response:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# query (inbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder&lt;br /&gt;
Payload:  status&lt;br /&gt;
&lt;br /&gt;
# response (outbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder/status&lt;br /&gt;
Payload:  started C:\recordings\2026-04-16_143012_ch2.mp4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Codes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Message !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO001&amp;lt;/code&amp;gt; || MQTT cannot resolve broker address || DNS lookup for the broker failed&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO002&amp;lt;/code&amp;gt; || MQTT receive callback exception || Unhandled exception in the receive handler&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt; || MQTT JSON payload not yet implemented || Payload starts with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt; || MQTT cannot assign topic &amp;lt;code&amp;gt;&amp;lt;topic&amp;gt;&amp;lt;/code&amp;gt; || Topic matches no known pattern&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* JSON payloads are not implemented (error &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The broker port is fixed at 1883.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder OSC Interface]] — full command semantics and the configuration reference.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6219</id>
		<title>Stage Recorder OSC Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6219"/>
		<updated>2026-09-21T10:02:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (OSC) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling Stage Recorder over &#039;&#039;&#039;OSC&#039;&#039;&#039; (Open Sound Control). For the equivalent MQTT interface see [[Stage Recorder MQTT Interface]]; for the on-screen interface see [[Stage Recorder User Interface]].&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OSC is the primary remote-control protocol. MQTT commands are internally converted to OSC and injected into the same receive loop, so the entire address space below applies equally to both protocols.&lt;br /&gt;
&lt;br /&gt;
All OSC processing happens on the main (render) thread: messages arrive on a UDP thread, are queued, and drained one per rendered frame. OSC bundles are supported — each message in a bundle is processed individually, in order.&lt;br /&gt;
&lt;br /&gt;
== Transport ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || UDP || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen address || ANY (0.0.0.0) || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen port || &#039;&#039;&#039;7000&#039;&#039;&#039; || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The port is read once at startup; changing it requires a restart.&lt;br /&gt;
&lt;br /&gt;
== Address Space ==&lt;br /&gt;
&lt;br /&gt;
Every address must begin with &amp;lt;code&amp;gt;/mxr&amp;lt;/code&amp;gt;; the first token is stripped before dispatch.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player     &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder   &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/sync_control           [args]&lt;br /&gt;
/mxr/schedule               &amp;lt;command&amp;gt; [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;1-based&#039;&#039;&#039; channel index.&lt;br /&gt;
&lt;br /&gt;
== Player Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;filename:string&amp;gt;&amp;lt;/code&amp;gt; || Open a media file. Resets markers. The file is opened asynchronously and starts paused at position 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || — || Resume playback (unpause). Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || — || Pause playback. Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop playback. With soft-stop enabled, the first call rewinds to 0 and pauses; the second call (or if soft-stop is disabled) unloads the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;milliseconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Seek to an absolute position in milliseconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; || — || Jump to the previous cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; || — || Jump to the next cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current position.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_speed&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;speed:float&amp;gt;&amp;lt;/code&amp;gt; || Frame-based slow motion. &amp;lt;code&amp;gt;0.0&amp;lt;/code&amp;gt; holds the current frame, &amp;lt;code&amp;gt;1.0&amp;lt;/code&amp;gt; is normal speed; values outside the range are clamped. Below normal speed consecutive frames are blended in a shader so motion stays smooth, and audio is muted — it cannot be stretched without shifting pitch. Also accepted as &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current player status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* Commands that need an open file (&amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;go_marker_*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt;) are silently ignored when no file is loaded.&lt;br /&gt;
* &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; is asynchronous — commands sent immediately afterwards may run before the file is ready.&lt;br /&gt;
* Soft-stop is configured via &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example bundle — open, seek to start, play:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#bundle&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;open&amp;quot;  &amp;quot;/media/clip.mp4&amp;quot;&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;seek&amp;quot;  0&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Recorder Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; || — || Begin recording with the channel&#039;s selected recording profile. Any active playback on the channel is stopped first.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop the active recording. Writes cue markers into the file as metadata, then auto-loads the recorded clip into the player (paused at 0).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;seconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Start recording and schedule an automatic stop after the given number of seconds. Registers a task visible in the Schedule tab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;[seconds:int32]&amp;lt;/code&amp;gt; || Start recording &#039;&#039;including material captured before the command arrived&#039;&#039;, to compensate for reaction time. Without an argument the configured &#039;&#039;Preemptive Recording Time&#039;&#039; is used; with one, that many seconds, clamped to 0–100 and to what the buffer currently holds. Requires &#039;&#039;Preemptive Recording Time&#039;&#039; to be above 0 — see the notes below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_end_time&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;unix_timestamp:int32&amp;gt;&amp;lt;/code&amp;gt; || Update the scheduled stop time of an active recording. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current recording position. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current recorder status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* On &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, the finished file is immediately opened in the channel&#039;s player.&lt;br /&gt;
* The scheduled stop from &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; is also polled on every render frame as a safety net.&lt;br /&gt;
* Timestamps use the Unix epoch; the &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt; wire type is subject to the Y2038 limit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preemptive recording:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; only reaches back in time when &#039;&#039;Settings → Recording Profile → Preemptive Recording Time&#039;&#039; is above 0. That setting is what keeps the encoders running continuously and the buffer filled; at 0 nothing is buffered.&lt;br /&gt;
* If no buffer is armed the recording still starts, but without pre-roll, and error &amp;lt;code&amp;gt;R008&amp;lt;/code&amp;gt; is logged. A remote caller cannot otherwise distinguish the two cases.&lt;br /&gt;
* After the setting is changed, the buffer needs that many seconds to fill before a full pre-roll is available. In the user interface the &amp;lt;code&amp;gt;+n&amp;lt;/code&amp;gt; button stays disabled until then; over the network an early &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; simply returns less pre-roll than requested.&lt;br /&gt;
* The recording begins at the nearest keyframe at or before the requested point, so the result may contain slightly more than the requested seconds. A shorter GOP in the recording profile tightens this.&lt;br /&gt;
* The reported start time and the recording&#039;s own timeline begin at the &#039;&#039;pre-roll&#039;&#039; start, not at the moment the command arrived.&lt;br /&gt;
&lt;br /&gt;
== Sync Control ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This endpoint has two independent forms.&lt;br /&gt;
&lt;br /&gt;
=== Open a Sync-Set File ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;quot;open&amp;quot;  &amp;quot;&amp;lt;filepath:string&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Opens a sync-set (&amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt;). For each stored channel it stops the recorder, opens the stored file in the player, pauses, and seeks to 0; it also restores the saved channel selection.&lt;br /&gt;
&lt;br /&gt;
=== Fan-Out Command to Multiple Channels ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch1:int32&amp;gt;  [ch2:int32 ...]  &amp;lt;receiver:string&amp;gt;  &amp;lt;command:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1..N || int32 || Target channel indices (1-based). All leading integers form the channel set.&lt;br /&gt;
|-&lt;br /&gt;
| N+1 || string || Receiver: &amp;lt;code&amp;gt;&amp;quot;player&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;recorder&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| N+2 || string || Command (any valid player or recorder command)&lt;br /&gt;
|-&lt;br /&gt;
| N+3.. || mixed || Optional command arguments&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
One message per target channel is emitted as a single OSC bundle, so all channels are addressed atomically.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channels 1, 2 and 4:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  4  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — seek all channels to 30 000 ms:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  3  &amp;quot;player&amp;quot;  &amp;quot;seek&amp;quot;  30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  &amp;lt;unix_timestamp:int32&amp;gt;  &amp;lt;osc_address:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || string || Must be &amp;lt;code&amp;gt;&amp;quot;taskadd_local&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 2 || int32 || Unix epoch time at which the task fires&lt;br /&gt;
|-&lt;br /&gt;
| 3 || string || OSC address to send when the task fires (e.g. &amp;lt;code&amp;gt;/mxr/channel/1/recorder&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 4.. || mixed || Arguments to include in the fired message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
At execution time the scheduler sends the stored address and arguments as an OSC message to the local port. Tasks are one-shot and are removed after firing. The task list persists in the project file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channel 2 at a specific time:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — record for exactly 3600 seconds:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Argument Types ==&lt;br /&gt;
&lt;br /&gt;
OSC arguments are typed on the wire. The following types are accepted:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! OSC type tag !! Type !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; || string || UTF-8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; || int32 || Most common numeric type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; || int64 || Treated as int32 internally&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; || float ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Unrecognised types are logged and skipped.&lt;br /&gt;
&lt;br /&gt;
== Quick Reference ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Player&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  open &amp;lt;file&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  play | pause | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  seek &amp;lt;ms&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  go_marker_back | go_marker_forward | set_marker | status&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  set_speed &amp;lt;0.0..1.0&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Recorder&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_with_duration &amp;lt;seconds&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_preemptive [seconds]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_end_time &amp;lt;unix_timestamp&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_marker | status&lt;br /&gt;
&lt;br /&gt;
# Sync — fan-out / open sync-set&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch&amp;gt; [ch ...]  player|recorder  &amp;lt;command&amp;gt;  [args]&lt;br /&gt;
/mxr/sync_control  open  &amp;lt;filepath&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Scheduler&lt;br /&gt;
/mxr/schedule  taskadd_local  &amp;lt;unix_timestamp&amp;gt;  &amp;lt;osc_address&amp;gt;  [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration Reference ==&lt;br /&gt;
&lt;br /&gt;
Keys are stored in the platform-native configuration (Windows Registry; INI file on Linux/macOS).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Type !! Default !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;7000&amp;lt;/code&amp;gt; || UDP port to listen on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Enable/disable MQTT&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || MQTT broker hostname&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr-client-&amp;lt;rnd&amp;gt;&amp;lt;/code&amp;gt; || MQTT client identifier&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || MQTT subscription topic filter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || System identifier used in the outbound status topic prefix&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Two-stage stop behaviour for the player&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt; || Password for the Settings tab&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder MQTT Interface]] — the same command tree over an MQTT broker, plus outbound status.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6218</id>
		<title>Stage Recorder MQTT Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_MQTT_Interface&amp;diff=6218"/>
		<updated>2026-09-20T19:32:22Z</updated>

		<summary type="html">&lt;p&gt;Admin: probe&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (MQTT) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling and monitoring Stage Recorder over an &#039;&#039;&#039;MQTT&#039;&#039;&#039; broker. MQTT is an optional bridge over the OSC command tree; see [[Stage Recorder OSC Interface]] for the full command semantics and [[Stage Recorder User Interface]] for on-screen operation.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Inbound MQTT messages are converted into OSC packets and injected into the OSC receive loop on localhost — there is no separate MQTT command handler. The entire OSC routing tree therefore applies to MQTT as well. MQTT additionally provides &#039;&#039;&#039;outbound status&#039;&#039;&#039; publishing that OSC does not.&lt;br /&gt;
&lt;br /&gt;
MQTT runs on a dedicated background thread with automatic reconnection.&lt;br /&gt;
&lt;br /&gt;
== Transport and Connection ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || TCP || —&lt;br /&gt;
|-&lt;br /&gt;
| Broker address || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Broker port || &#039;&#039;&#039;1883&#039;&#039;&#039; || — (fixed)&lt;br /&gt;
|-&lt;br /&gt;
| Client ID || &amp;lt;code&amp;gt;mxr-client-&amp;lt;4 random chars&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Subscribe pattern || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Enabled || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| QoS || 1 || —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To disable MQTT, set &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Topic Structure ==&lt;br /&gt;
&lt;br /&gt;
Inbound (command) topics follow this pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/channel/&amp;lt;n&amp;gt;/&amp;lt;receiver&amp;gt;&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/sync_control&lt;br /&gt;
mxr/&amp;lt;system-id&amp;gt;/schedule&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; is matched by the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; wildcard in the default subscribe pattern &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt;. The value is not validated; it exists to distinguish multiple recorders on one broker. With the default pattern the recorder accepts commands from any system-id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Topic → OSC mapping:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! MQTT topic pattern !! OSC address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;rest&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Topics that match none of these patterns generate error &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Payload Format ==&lt;br /&gt;
&lt;br /&gt;
The payload is a &#039;&#039;&#039;space-separated plain-text string&#039;&#039;&#039;. Each whitespace-delimited token is type-detected, in order:&lt;br /&gt;
&lt;br /&gt;
# parses as a &#039;&#039;&#039;long integer&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
# parses as a &#039;&#039;&#039;double&#039;&#039;&#039; → stored as &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt;&lt;br /&gt;
# otherwise → stored as &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The resulting argument list is forwarded to OSC exactly as described in [[Stage Recorder OSC Interface]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Command reference:&#039;&#039;&#039; the available &amp;lt;code&amp;gt;&amp;lt;receiver&amp;gt;&amp;lt;/code&amp;gt; commands and their arguments are identical to OSC:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload examples&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;open &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;seek &amp;lt;ms&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_with_duration &amp;lt;seconds&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;start_preemptive [seconds]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_end_time &amp;lt;unix&amp;gt;&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/sync_control&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;ch...&amp;gt; player|recorder &amp;lt;command&amp;gt; [args]&amp;lt;/code&amp;gt; · &amp;lt;code&amp;gt;open &amp;lt;filepath&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/schedule&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;taskadd_local &amp;lt;unix&amp;gt; &amp;lt;osc_address&amp;gt; [args]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  play&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/1/player&lt;br /&gt;
Payload:  seek 15000&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/1/player  &amp;quot;seek&amp;quot;  15000&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_with_duration 3600&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;&lt;br /&gt;
          (pre-roll = configured Preemptive Recording Time)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/channel/2/recorder&lt;br /&gt;
Payload:  start_preemptive 5&lt;br /&gt;
-&amp;gt; OSC:   /mxr/channel/2/recorder  &amp;quot;start_preemptive&amp;quot;  5&lt;br /&gt;
          (recording begins 5 s before the message arrived)&lt;br /&gt;
&lt;br /&gt;
Topic:    mxr/studio1/sync_control&lt;br /&gt;
Payload:  1 2 recorder start&lt;br /&gt;
-&amp;gt; OSC:   /mxr/sync_control  1  2  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Status Publishing (Outbound) ==&lt;br /&gt;
&lt;br /&gt;
The recorder and player publish state changes to the broker automatically. Messages are enqueued from the recording/playback threads and sent on the MQTT worker thread. &amp;lt;code&amp;gt;&amp;lt;system-id&amp;gt;&amp;lt;/code&amp;gt; comes from &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is the 1-based channel index; &amp;lt;code&amp;gt;&amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; is the absolute path.&lt;br /&gt;
&lt;br /&gt;
=== Recorder Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording begins&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || Recording ends&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Player Status ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Topic !! Payload !! When&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || A file is loaded and the player becomes active&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_stopped &amp;lt;filename&amp;gt;&amp;lt;/code&amp;gt; || The player is torn down / file unloaded&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || Playback resumed (from the transport button or a &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; command)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || Playback paused&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || Soft stop (paused and rewound to 0). A subsequent hard stop unloads the file and reports &amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;player_started&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;player_stopped&amp;lt;/code&amp;gt; messages carry the filename, so a control surface can show &#039;&#039;which&#039;&#039; file is loaded; the bare &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; messages report the live transport state. Note these are published on the &amp;lt;code&amp;gt;.../player/status&amp;lt;/code&amp;gt; topic — &#039;&#039;&#039;not&#039;&#039;&#039; on the bare &amp;lt;code&amp;gt;.../player&amp;lt;/code&amp;gt; command topic, which the application subscribes to.&lt;br /&gt;
&lt;br /&gt;
=== On-Demand Status Query ===&lt;br /&gt;
&lt;br /&gt;
Publish &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; to a command topic and the matching &amp;lt;code&amp;gt;.../status&amp;lt;/code&amp;gt; topic is published immediately with the current state, in the same format as the spontaneous messages:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Query topic (inbound) !! Response topic (outbound) !! Response payload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/recorder/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxr/&amp;lt;id&amp;gt;/channel/&amp;lt;n&amp;gt;/player/status&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;player_started &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;player_stopped &amp;lt;file&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If nothing has been recorded/loaded yet, the filename is empty (e.g. &amp;lt;code&amp;gt;stopped &amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;player_stopped &amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — query and response:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# query (inbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder&lt;br /&gt;
Payload:  status&lt;br /&gt;
&lt;br /&gt;
# response (outbound)&lt;br /&gt;
Topic:    mxr/1/channel/2/recorder/status&lt;br /&gt;
Payload:  started C:\recordings\2026-04-16_143012_ch2.mp4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Codes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Code !! Message !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO001&amp;lt;/code&amp;gt; || MQTT cannot resolve broker address || DNS lookup for the broker failed&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO002&amp;lt;/code&amp;gt; || MQTT receive callback exception || Unhandled exception in the receive handler&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt; || MQTT JSON payload not yet implemented || Payload starts with &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IO004&amp;lt;/code&amp;gt; || MQTT cannot assign topic &amp;lt;code&amp;gt;&amp;lt;topic&amp;gt;&amp;lt;/code&amp;gt; || Topic matches no known pattern&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* JSON payloads are not implemented (error &amp;lt;code&amp;gt;IO003&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The broker port is fixed at 1883.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder OSC Interface]] — full command semantics and the configuration reference.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6217</id>
		<title>Stage Recorder OSC Interface</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Stage_Recorder_OSC_Interface&amp;diff=6217"/>
		<updated>2026-09-20T19:30:50Z</updated>

		<summary type="html">&lt;p&gt;Admin: Sync from source docs: content, links and protocol updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Stage Recorder — Remote Control (OSC) =&lt;br /&gt;
&lt;br /&gt;
This page documents controlling Stage Recorder over &#039;&#039;&#039;OSC&#039;&#039;&#039; (Open Sound Control). For the equivalent MQTT interface see [[Stage Recorder MQTT Interface]]; for the on-screen interface see [[Stage Recorder User Interface]].&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OSC is the primary remote-control protocol. MQTT commands are internally converted to OSC and injected into the same receive loop, so the entire address space below applies equally to both protocols.&lt;br /&gt;
&lt;br /&gt;
All OSC processing happens on the main (render) thread: messages arrive on a UDP thread, are queued, and drained one per rendered frame. OSC bundles are supported — each message in a bundle is processed individually, in order.&lt;br /&gt;
&lt;br /&gt;
== Transport ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Default !! Config key&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || UDP || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen address || ANY (0.0.0.0) || —&lt;br /&gt;
|-&lt;br /&gt;
| Listen port || &#039;&#039;&#039;7000&#039;&#039;&#039; || &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The port is read once at startup; changing it requires a restart.&lt;br /&gt;
&lt;br /&gt;
== Address Space ==&lt;br /&gt;
&lt;br /&gt;
Every address must begin with &amp;lt;code&amp;gt;/mxr&amp;lt;/code&amp;gt;; the first token is stripped before dispatch.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player     &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder   &amp;lt;command&amp;gt; [args]&lt;br /&gt;
/mxr/sync_control           [args]&lt;br /&gt;
/mxr/schedule               &amp;lt;command&amp;gt; [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;n&amp;gt;&amp;lt;/code&amp;gt; is a &#039;&#039;&#039;1-based&#039;&#039;&#039; channel index.&lt;br /&gt;
&lt;br /&gt;
== Player Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/player&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;filename:string&amp;gt;&amp;lt;/code&amp;gt; || Open a media file. Resets markers. The file is opened asynchronously and starts paused at position 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt; || — || Resume playback (unpause). Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt; || — || Pause playback. Requires an open file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop playback. With soft-stop enabled, the first call rewinds to 0 and pauses; the second call (or if soft-stop is disabled) unloads the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;milliseconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Seek to an absolute position in milliseconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_back&amp;lt;/code&amp;gt; || — || Jump to the previous cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;go_marker_forward&amp;lt;/code&amp;gt; || — || Jump to the next cue marker.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current position.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current player status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* Commands that need an open file (&amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;pause&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;seek&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;go_marker_*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt;) are silently ignored when no file is loaded.&lt;br /&gt;
* &amp;lt;code&amp;gt;open&amp;lt;/code&amp;gt; is asynchronous — commands sent immediately afterwards may run before the file is ready.&lt;br /&gt;
* Soft-stop is configured via &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example bundle — open, seek to start, play:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#bundle&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;open&amp;quot;  &amp;quot;/media/clip.mp4&amp;quot;&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;seek&amp;quot;  0&lt;br /&gt;
/mxr/channel/1/player  &amp;quot;play&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Recorder Commands ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/channel/&amp;lt;n&amp;gt;/recorder&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Argument 1 !! Argument 2 !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; || — || Begin recording with the channel&#039;s selected recording profile. Any active playback on the channel is stopped first.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt; || — || Stop the active recording. Writes cue markers into the file as metadata, then auto-loads the recorded clip into the player (paused at 0).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;seconds:int32&amp;gt;&amp;lt;/code&amp;gt; || Start recording and schedule an automatic stop after the given number of seconds. Registers a task visible in the Schedule tab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;[seconds:int32]&amp;lt;/code&amp;gt; || Start recording &#039;&#039;including material captured before the command arrived&#039;&#039;, to compensate for reaction time. Without an argument the configured &#039;&#039;Preemptive Recording Time&#039;&#039; is used; with one, that many seconds, clamped to 0–100 and to what the buffer currently holds. Requires &#039;&#039;Preemptive Recording Time&#039;&#039; to be above 0 — see the notes below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_end_time&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;&amp;lt;unix_timestamp:int32&amp;gt;&amp;lt;/code&amp;gt; || Update the scheduled stop time of an active recording. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;set_marker&amp;lt;/code&amp;gt; || — || Insert a cue marker at the current recording position. Only effective while recording.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; || — || Query the current recorder status. The reply is published over MQTT — see [[Stage Recorder MQTT Interface#Status Publishing (Outbound)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes:&#039;&#039;&#039;&lt;br /&gt;
* On &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, the finished file is immediately opened in the channel&#039;s player.&lt;br /&gt;
* The scheduled stop from &amp;lt;code&amp;gt;start_with_duration&amp;lt;/code&amp;gt; is also polled on every render frame as a safety net.&lt;br /&gt;
* Timestamps use the Unix epoch; the &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt; wire type is subject to the Y2038 limit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preemptive recording:&#039;&#039;&#039;&lt;br /&gt;
* &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; only reaches back in time when &#039;&#039;Settings → Recording Profile → Preemptive Recording Time&#039;&#039; is above 0. That setting is what keeps the encoders running continuously and the buffer filled; at 0 nothing is buffered.&lt;br /&gt;
* If no buffer is armed the recording still starts, but without pre-roll, and error &amp;lt;code&amp;gt;R008&amp;lt;/code&amp;gt; is logged. A remote caller cannot otherwise distinguish the two cases.&lt;br /&gt;
* After the setting is changed, the buffer needs that many seconds to fill before a full pre-roll is available. In the user interface the &amp;lt;code&amp;gt;+n&amp;lt;/code&amp;gt; button stays disabled until then; over the network an early &amp;lt;code&amp;gt;start_preemptive&amp;lt;/code&amp;gt; simply returns less pre-roll than requested.&lt;br /&gt;
* The recording begins at the nearest keyframe at or before the requested point, so the result may contain slightly more than the requested seconds. A shorter GOP in the recording profile tightens this.&lt;br /&gt;
* The reported start time and the recording&#039;s own timeline begin at the &#039;&#039;pre-roll&#039;&#039; start, not at the moment the command arrived.&lt;br /&gt;
&lt;br /&gt;
== Sync Control ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/sync_control&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This endpoint has two independent forms.&lt;br /&gt;
&lt;br /&gt;
=== Open a Sync-Set File ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;quot;open&amp;quot;  &amp;quot;&amp;lt;filepath:string&amp;gt;&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Opens a sync-set (&amp;lt;code&amp;gt;.mxr_syncset&amp;lt;/code&amp;gt;). For each stored channel it stops the recorder, opens the stored file in the player, pauses, and seeks to 0; it also restores the saved channel selection.&lt;br /&gt;
&lt;br /&gt;
=== Fan-Out Command to Multiple Channels ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch1:int32&amp;gt;  [ch2:int32 ...]  &amp;lt;receiver:string&amp;gt;  &amp;lt;command:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1..N || int32 || Target channel indices (1-based). All leading integers form the channel set.&lt;br /&gt;
|-&lt;br /&gt;
| N+1 || string || Receiver: &amp;lt;code&amp;gt;&amp;quot;player&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;recorder&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| N+2 || string || Command (any valid player or recorder command)&lt;br /&gt;
|-&lt;br /&gt;
| N+3.. || mixed || Optional command arguments&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
One message per target channel is emitted as a single OSC bundle, so all channels are addressed atomically.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channels 1, 2 and 4:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  4  &amp;quot;recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — seek all channels to 30 000 ms:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/sync_control  1  2  3  &amp;quot;player&amp;quot;  &amp;quot;seek&amp;quot;  30000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Address:&#039;&#039;&#039; &amp;lt;code&amp;gt;/mxr/schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  &amp;lt;unix_timestamp:int32&amp;gt;  &amp;lt;osc_address:string&amp;gt;  [args...]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Position !! Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| 1 || string || Must be &amp;lt;code&amp;gt;&amp;quot;taskadd_local&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 2 || int32 || Unix epoch time at which the task fires&lt;br /&gt;
|-&lt;br /&gt;
| 3 || string || OSC address to send when the task fires (e.g. &amp;lt;code&amp;gt;/mxr/channel/1/recorder&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 4.. || mixed || Arguments to include in the fired message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
At execution time the scheduler sends the stored address and arguments as an OSC message to the local port. Tasks are one-shot and are removed after firing. The task list persists in the project file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — start recorder on channel 2 at a specific time:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example — record for exactly 3600 seconds:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/mxr/schedule  &amp;quot;taskadd_local&amp;quot;  1711900800  &amp;quot;/mxr/channel/2/recorder&amp;quot;  &amp;quot;start_with_duration&amp;quot;  3600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Argument Types ==&lt;br /&gt;
&lt;br /&gt;
OSC arguments are typed on the wire. The following types are accepted:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! OSC type tag !! Type !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; || string || UTF-8&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; || int32 || Most common numeric type&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; || int64 || Treated as int32 internally&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; || float ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Unrecognised types are logged and skipped.&lt;br /&gt;
&lt;br /&gt;
== Quick Reference ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Player&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  open &amp;lt;file&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  play | pause | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  seek &amp;lt;ms&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/player  go_marker_back | go_marker_forward | set_marker | status&lt;br /&gt;
&lt;br /&gt;
# Recorder&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start | stop&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_with_duration &amp;lt;seconds&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  start_preemptive [seconds]&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_end_time &amp;lt;unix_timestamp&amp;gt;&lt;br /&gt;
/mxr/channel/&amp;lt;n&amp;gt;/recorder  set_marker | status&lt;br /&gt;
&lt;br /&gt;
# Sync — fan-out / open sync-set&lt;br /&gt;
/mxr/sync_control  &amp;lt;ch&amp;gt; [ch ...]  player|recorder  &amp;lt;command&amp;gt;  [args]&lt;br /&gt;
/mxr/sync_control  open  &amp;lt;filepath&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Scheduler&lt;br /&gt;
/mxr/schedule  taskadd_local  &amp;lt;unix_timestamp&amp;gt;  &amp;lt;osc_address&amp;gt;  [args]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration Reference ==&lt;br /&gt;
&lt;br /&gt;
Keys are stored in the platform-native configuration (Windows Registry; INI file on Linux/macOS).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Type !! Default !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/OSC/Receive Port&amp;lt;/code&amp;gt; || long || &amp;lt;code&amp;gt;7000&amp;lt;/code&amp;gt; || UDP port to listen on&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Use MQTT&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Enable/disable MQTT&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Broker Address&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;broker.hivemq.com&amp;lt;/code&amp;gt; || MQTT broker hostname&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Client ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr-client-&amp;lt;rnd&amp;gt;&amp;lt;/code&amp;gt; || MQTT client identifier&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/Subscribe Pattern&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;mxr/+/&amp;lt;/code&amp;gt; || MQTT subscription topic filter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/IO/MQTT/System ID&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; || System identifier used in the outbound status topic prefix&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/Playback/Use Softstop&amp;lt;/code&amp;gt; || bool || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || Two-stage stop behaviour for the player&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/System/SettingsKey&amp;lt;/code&amp;gt; || string || &amp;lt;code&amp;gt;123456&amp;lt;/code&amp;gt; || Password for the Settings tab&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Stage Recorder MQTT Interface]] — the same command tree over an MQTT broker, plus outbound status.&lt;br /&gt;
* [[Stage Recorder User Interface]] — on-screen operation.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Tutorials&amp;diff=6216</id>
		<title>Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Tutorials&amp;diff=6216"/>
		<updated>2026-08-09T18:13:18Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove mis-titled Streamdeck tutorial link (page was a Wii-tutorial copy, being deleted)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==General==&lt;br /&gt;
*[[Tutorial Opening Different Media]]&lt;br /&gt;
*[[Tutorial Setting up Stage Designer Output Windows]]&lt;br /&gt;
*[[Tutorial Triggering Four Media with the Keyboard]]&lt;br /&gt;
*[[Tutorial Coupling Video with Effects and Audio Signals]]&lt;br /&gt;
*[[Tutorial Creating Predefined Layer Position]]&lt;br /&gt;
*[[Tutorial Feedback]]&lt;br /&gt;
*[[Tutorial Creating an I/O Event]]&lt;br /&gt;
*[[Tutorial Creating an Autostart Showfile]]&lt;br /&gt;
*[[Tutorial Creating Compositions (Sets and Patches)]]&lt;br /&gt;
*[[Tutorial Creating Multiple Compositions and Patches]]&lt;br /&gt;
*[[Tutorial Creating and Playing an RTF Text File]]&lt;br /&gt;
*[[Tutorial Licensing New Features]]&lt;br /&gt;
*[[Tutorial Loading and Using JavaScripts in MXWendler]]&lt;br /&gt;
*[[Tutorial Configuring a Virtual Camera]]&lt;br /&gt;
&lt;br /&gt;
==Playlist==&lt;br /&gt;
*[[Tutorial Creating Playlists (Cue Lists)]]&lt;br /&gt;
*[[Tutorial Playlists with Images and Keystone Correction]]&lt;br /&gt;
*[[Tutorial Playlists with Timeline]]&lt;br /&gt;
*[[Tutorial Playlists with Multi-Timeline]]&lt;br /&gt;
*[[Tutorial Playlists with Time and Date Conditions]]&lt;br /&gt;
*[[Tutorial Playlists with Timecode]]&lt;br /&gt;
*[[Tutorial Playlists with Subtitles]]&lt;br /&gt;
*[[Tutorial Playlists with IO - Commands]]&lt;br /&gt;
*[[Tutorial Playlists with PDF and Frame Step]]&lt;br /&gt;
*[[Tutorial Resetting Runtime Counter with IO Commands in Playlist]]&lt;br /&gt;
*[[Tutorial Playlists with Fade Clip]]&lt;br /&gt;
*[[Tutorial Playlists with Auto Step]]&lt;br /&gt;
*[[Tutorial Playlists with Reset Counter]]&lt;br /&gt;
*[[Tutorial Playlists with Shutdown]]&lt;br /&gt;
*[[Tutorial Playlists with Load Show]]&lt;br /&gt;
*[[Tutorial Playlists with OSC Command]]&lt;br /&gt;
*[[Tutorial Playlists with Sys Command]]&lt;br /&gt;
*[[Tutorial Playlists with PJlink Command]]&lt;br /&gt;
*[[Tutorial Playlists in Rehearsal Mode]]&lt;br /&gt;
*[[Tutorial Creating an Automated Show with Daily Event and Playlist Conditions]]&lt;br /&gt;
&lt;br /&gt;
==Keystone==&lt;br /&gt;
*[[Tutorial Simultaneous Playback of two Videos with two Video Projectors]]&lt;br /&gt;
*[[Tutorial Mapping with UV View]]&lt;br /&gt;
*[[Tutorial Masked Output]]&lt;br /&gt;
*[[Tutorial Colored Output with Animations]]&lt;br /&gt;
*[[Tutorial Capture Output Sections with Artnet DMX and Network Grabbers]]&lt;br /&gt;
*[[Tutorial SVG Mapping with the MXWendler Automatic Calibration]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==IO Devices==&lt;br /&gt;
*[[Reference Open Sound Control - OSC]]&lt;br /&gt;
*[[Reference JavaScript]]&lt;br /&gt;
*[[Tutorial Using the Akai APC Mini (Note On/Off)]]&lt;br /&gt;
*[[Tutorial Connecting the grandMA 2Port Node with MXWendler via Art-Net]]&lt;br /&gt;
*[[Tutorial Connecting Jands Vista2 with MXWendler via Art-Net]]&lt;br /&gt;
*[[Tutorial Set up the CITP Footage Library on the Media Server]]&lt;br /&gt;
*[[Tutorial Time-sync and sending IO Commands over OSC Protocol]]&lt;br /&gt;
*[[Tutorial Controlling MXWendler via TouchOSC]]&lt;br /&gt;
*[[Tutorial Optimum Audio Settings with an Integrated Audio Interface]]&lt;br /&gt;
*[[Tutorial Optimum Audio Settings with an External Audio Interface]]&lt;br /&gt;
*[[Tutorial Eventmaster Toolset Controlling MXWendler by e.g. e2 S3 Image Processor]]&lt;br /&gt;
&lt;br /&gt;
==FXServer==&lt;br /&gt;
*[[Tutorial FXServer Output Windows]]&lt;br /&gt;
&lt;br /&gt;
*[[Tutorial How to Setup a Datapath Fx4 for MXWendler with the Wall Designer Software]]&lt;br /&gt;
&lt;br /&gt;
*[[Tutorial How to Optimize Video Footages With Blender]]&lt;br /&gt;
&lt;br /&gt;
==Standalone Encoder==&lt;br /&gt;
*[[Tutorial Standalone Encoder / Video Batch Encoder]]&lt;br /&gt;
&lt;br /&gt;
==EDID Manager==&lt;br /&gt;
*[[Tutorial MXWendler EDID Manager]]&lt;br /&gt;
&lt;br /&gt;
==NDI Tools==&lt;br /&gt;
*[[Tutorial NDI Tools ]]&lt;br /&gt;
*[[Tutorial Sending and Receiving Multiple Video Streams with NDI]]&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
*[[Tutorial Sending and Receiving Media Through Spout]]&lt;br /&gt;
*[[Tutorial Connecting Winamp Generative Visuals with MXWendler via Spout]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Tutorials&amp;diff=6215</id>
		<title>Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Tutorials&amp;diff=6215"/>
		<updated>2026-08-09T17:25:23Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove Wiimote tutorial link (feature removed)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==General==&lt;br /&gt;
*[[Tutorial Opening Different Media]]&lt;br /&gt;
*[[Tutorial Setting up Stage Designer Output Windows]]&lt;br /&gt;
*[[Tutorial Triggering Four Media with the Keyboard]]&lt;br /&gt;
*[[Tutorial Coupling Video with Effects and Audio Signals]]&lt;br /&gt;
*[[Tutorial Creating Predefined Layer Position]]&lt;br /&gt;
*[[Tutorial Feedback]]&lt;br /&gt;
*[[Tutorial Creating an I/O Event]]&lt;br /&gt;
*[[Tutorial Creating an Autostart Showfile]]&lt;br /&gt;
*[[Tutorial Creating Compositions (Sets and Patches)]]&lt;br /&gt;
*[[Tutorial Creating Multiple Compositions and Patches]]&lt;br /&gt;
*[[Tutorial Creating and Playing an RTF Text File]]&lt;br /&gt;
*[[Tutorial Licensing New Features]]&lt;br /&gt;
*[[Tutorial Loading and Using JavaScripts in MXWendler]]&lt;br /&gt;
*[[Tutorial Configuring a Virtual Camera]]&lt;br /&gt;
&lt;br /&gt;
==Playlist==&lt;br /&gt;
*[[Tutorial Creating Playlists (Cue Lists)]]&lt;br /&gt;
*[[Tutorial Playlists with Images and Keystone Correction]]&lt;br /&gt;
*[[Tutorial Playlists with Timeline]]&lt;br /&gt;
*[[Tutorial Playlists with Multi-Timeline]]&lt;br /&gt;
*[[Tutorial Playlists with Time and Date Conditions]]&lt;br /&gt;
*[[Tutorial Playlists with Timecode]]&lt;br /&gt;
*[[Tutorial Playlists with Subtitles]]&lt;br /&gt;
*[[Tutorial Playlists with IO - Commands]]&lt;br /&gt;
*[[Tutorial Playlists with PDF and Frame Step]]&lt;br /&gt;
*[[Tutorial Resetting Runtime Counter with IO Commands in Playlist]]&lt;br /&gt;
*[[Tutorial Playlists with Fade Clip]]&lt;br /&gt;
*[[Tutorial Playlists with Auto Step]]&lt;br /&gt;
*[[Tutorial Playlists with Reset Counter]]&lt;br /&gt;
*[[Tutorial Playlists with Shutdown]]&lt;br /&gt;
*[[Tutorial Playlists with Load Show]]&lt;br /&gt;
*[[Tutorial Playlists with OSC Command]]&lt;br /&gt;
*[[Tutorial Playlists with Sys Command]]&lt;br /&gt;
*[[Tutorial Playlists with PJlink Command]]&lt;br /&gt;
*[[Tutorial Playlists in Rehearsal Mode]]&lt;br /&gt;
*[[Tutorial Creating an Automated Show with Daily Event and Playlist Conditions]]&lt;br /&gt;
&lt;br /&gt;
==Keystone==&lt;br /&gt;
*[[Tutorial Simultaneous Playback of two Videos with two Video Projectors]]&lt;br /&gt;
*[[Tutorial Mapping with UV View]]&lt;br /&gt;
*[[Tutorial Masked Output]]&lt;br /&gt;
*[[Tutorial Colored Output with Animations]]&lt;br /&gt;
*[[Tutorial Capture Output Sections with Artnet DMX and Network Grabbers]]&lt;br /&gt;
*[[Tutorial SVG Mapping with the MXWendler Automatic Calibration]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==IO Devices==&lt;br /&gt;
*[[Reference Open Sound Control - OSC]]&lt;br /&gt;
*[[Reference JavaScript]]&lt;br /&gt;
*[[Tutorial Using the Akai APC Mini (Note On/Off)]]&lt;br /&gt;
*[[Tutorial Connecting the grandMA 2Port Node with MXWendler via Art-Net]]&lt;br /&gt;
*[[Tutorial Connecting Jands Vista2 with MXWendler via Art-Net]]&lt;br /&gt;
*[[Tutorial Set up the CITP Footage Library on the Media Server]]&lt;br /&gt;
*[[Tutorial Time-sync and sending IO Commands over OSC Protocol]]&lt;br /&gt;
*[[Tutorial Controlling MXWendler via TouchOSC]]&lt;br /&gt;
*[[Tutorial Optimum Audio Settings with an Integrated Audio Interface]]&lt;br /&gt;
*[[Tutorial Optimum Audio Settings with an External Audio Interface]]&lt;br /&gt;
*[[Tutorial Controlling StageDesigner with Elgato Streamdeck]]&lt;br /&gt;
*[[Tutorial Eventmaster Toolset Controlling MXWendler by e.g. e2 S3 Image Processor]]&lt;br /&gt;
&lt;br /&gt;
==FXServer==&lt;br /&gt;
*[[Tutorial FXServer Output Windows]]&lt;br /&gt;
&lt;br /&gt;
*[[Tutorial How to Setup a Datapath Fx4 for MXWendler with the Wall Designer Software]]&lt;br /&gt;
&lt;br /&gt;
*[[Tutorial How to Optimize Video Footages With Blender]]&lt;br /&gt;
&lt;br /&gt;
==Standalone Encoder==&lt;br /&gt;
*[[Tutorial Standalone Encoder / Video Batch Encoder]]&lt;br /&gt;
&lt;br /&gt;
==EDID Manager==&lt;br /&gt;
*[[Tutorial MXWendler EDID Manager]]&lt;br /&gt;
&lt;br /&gt;
==NDI Tools==&lt;br /&gt;
*[[Tutorial NDI Tools ]]&lt;br /&gt;
*[[Tutorial Sending and Receiving Multiple Video Streams with NDI]]&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
*[[Tutorial Sending and Receiving Media Through Spout]]&lt;br /&gt;
*[[Tutorial Connecting Winamp Generative Visuals with MXWendler via Spout]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Triggering&amp;diff=6214</id>
		<title>Triggering</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Triggering&amp;diff=6214"/>
		<updated>2026-08-09T17:25:22Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove link to TUIO tutorial (feature removed)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MXWENDLER enables you to trigger a whole series of events and animations with a keystone, or a MIDI / DMX event. &lt;br /&gt;
&lt;br /&gt;
*[[About Events]]&lt;br /&gt;
*[[Creating events]]&lt;br /&gt;
*[[Events / Widgets and Their Addresses / Intrinsic Values]]&lt;br /&gt;
*[[Examples of events]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=About_Events&amp;diff=6213</id>
		<title>About Events</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=About_Events&amp;diff=6213"/>
		<updated>2026-08-09T17:25:21Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove TUIO/Wii from trigger tool list (feature removed)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MXWendler enables you to trigger a whole series of events and animations with a keystroke or a MIDI/DMX event. All events work according to the same principle: a trigger activates an event, which sends a specific value to a receiver at a specific time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Events are managed in the IO Devices Settings:&lt;br /&gt;
&lt;br /&gt;
1. Open &#039;DMX/MIDI/Keyboard Events&#039; in the settings: &#039;&#039;&#039;(A)&#039;&#039;&#039;&lt;br /&gt;
:&#039;&#039;&#039;Menu: Settings &amp;amp;rarr; IO Devices &amp;amp;rarr; DMX/MIDI/Keyboard Events&#039;&#039;&#039;&lt;br /&gt;
2. Determine the trigger by selecting the respective tool: DMX, MIDI, Keyboard or Timer. &#039;&#039;&#039;(B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Create an event with the &#039;+&#039; button. &#039;&#039;&#039;(C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
4. Activate an event. &#039;&#039;&#039;(D)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
5. Specify the various event settings (receiver / event type / time / value). &#039;&#039;&#039;(E)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Events_1.png|728px]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Hardware&amp;diff=6212</id>
		<title>Hardware</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Hardware&amp;diff=6212"/>
		<updated>2026-08-09T17:25:20Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove TUIO and WiiRemote controller support (feature removed)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=== Building an Optimum System ===&lt;br /&gt;
&lt;br /&gt;
In general, you can be sure that any dedicated graphics card available today can run the MXWendler software. But there are performance differences, so feel free to ask at support[at]mxwendler.net.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Operating System&lt;br /&gt;
*Windows 7, Windows 8, Windows 8.1, Windows 10 - all 32 and 64 Bit&lt;br /&gt;
*Max OS X 10.7, 10.8, 10.9&lt;br /&gt;
Processor&lt;br /&gt;
*We equally work with AMD and Intel Processors. &lt;br /&gt;
*Many PCI devices: The AMD Threadripper series is recommended for the high number of PCI Lanes&lt;br /&gt;
*High Core speed: The Intel i7 and i9 series have a usually higher core speed&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
Graphic card&lt;br /&gt;
*Our reference hardware in matter of graphic cards is AMD, especially the Radeon Pro series.&lt;br /&gt;
*NVidia Quadro series.&lt;br /&gt;
*More than 2Gb dedicated Memory is recommended.&lt;br /&gt;
*SLI or dual-GPU setups are not recommended.&lt;br /&gt;
Disk&lt;br /&gt;
*M.2 disks for fast access supported (Samsung 970 Plus)&lt;br /&gt;
*SSD &lt;br /&gt;
*Raid for HD content supported&lt;br /&gt;
*Any disk possible&lt;br /&gt;
External Controller&lt;br /&gt;
*Midi supported ( any standard midi )&lt;br /&gt;
*Midi motor fader supported&lt;br /&gt;
*DMX supported ( Enttec, Soundlight, e:cue )&lt;br /&gt;
*OSC supported&lt;br /&gt;
*Art-Net supported&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
Memory&lt;br /&gt;
*Recommended 16GB&lt;br /&gt;
Audio&lt;br /&gt;
*Windows: Multichannel ASIO Audio supported&lt;br /&gt;
*Windows: System Audio&lt;br /&gt;
*Mac: Multichannel Core Audio supported&lt;br /&gt;
&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
System resource requirements, based on different performance needs:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Minimum&#039;&#039;&#039;&lt;br /&gt;
*CPU: Intel i7 7700k, Amd 1900x  &lt;br /&gt;
*GPU: AMD: RadeonPro wx3100, NVIDIA: Quadro P620&lt;br /&gt;
*Disk: SSD Samsung 970 Evo or SATA 7200 Rpm&lt;br /&gt;
*RAM: 8GB&lt;br /&gt;
&#039;&#039;&#039;Medium&#039;&#039;&#039;&lt;br /&gt;
*CPU: Intel i7 9700k, Amd 2920x&lt;br /&gt;
*GPU: AMD: RadeonPro wx7100, NVIDIA: Quadro P2200&lt;br /&gt;
*Disk: M.2 Samsung 970 Plus Evo&lt;br /&gt;
*RAM: 16GB&lt;br /&gt;
&#039;&#039;&#039;High&#039;&#039;&#039;&lt;br /&gt;
*CPU: Intel i9 9900k, AMD Ryzen 9 3900x, Amd 2950x&lt;br /&gt;
*GPU: AMD: RadeonPro wx8200, NVIDIA: Quadro P4000&lt;br /&gt;
*Disk: M.2 Samsung 970 Plus Evo or 970 Pro&lt;br /&gt;
*RAM: 32GB+&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Python_plugin_reference&amp;diff=6211</id>
		<title>Python plugin reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Python_plugin_reference&amp;diff=6211"/>
		<updated>2026-08-09T16:00:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: docs: audio streams — mxw.audio capture + audio-producing media plugins (device-rate adaptive)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MXWendler wiki page: How to create a Python plugin (media and playlist) --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Intended location: https://wiki.mxwendler.net/index.php?title=Python_plugin_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_command_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_imgui_reference --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MXWendler StageDesigner can be extended with &#039;&#039;&#039;Python plugins&#039;&#039;&#039;. A plugin is a plain folder containing a manifest file and a Python module; MXWendler discovers it at startup, shows it in the user interface and calls a defined set of Python functions (&#039;&#039;hooks&#039;&#039;) at the right moments.&lt;br /&gt;
&lt;br /&gt;
Two plugin types exist:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Media plugins&#039;&#039;&#039; produce pixels: they appear as a media source that can be placed in a clip like any video file. Examples: a web browser media, a generative OpenGL cube.&lt;br /&gt;
* &#039;&#039;&#039;Playlist plugins&#039;&#039;&#039; are items in the playlist grid: they run logic when their cue plays. Examples: advance the playlist at a given time of day, write video files, ping a host.&lt;br /&gt;
&lt;br /&gt;
The embedded interpreter is &#039;&#039;&#039;Python 3.12&#039;&#039;&#039;. The general Python command interface (module &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt;) is documented in the [[Python command reference|Python command reference]].&lt;br /&gt;
&lt;br /&gt;
== Plugin anatomy ==&lt;br /&gt;
&lt;br /&gt;
A plugin is one folder with at least two files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
plugins/media/python/plugin_my_effect/&lt;br /&gt;
    mxw_plugin.ini      the manifest: identity, menu entries, addressing&lt;br /&gt;
    mxw_main.py         the Python module with the hook functions&lt;br /&gt;
    (more .py files)    optional: importable as &amp;quot;from plugin_my_effect.xyz import ...&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folder name is the Python package name: additional modules in the folder are imported with absolute imports, e.g. &amp;lt;code&amp;gt;from plugin_my_effect.helpers import foo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Plugin locations ===&lt;br /&gt;
&lt;br /&gt;
Plugins are searched in several directories. &#039;&#039;&#039;User-controlled locations always override the bundled system location&#039;&#039;&#039;, so a user can replace a built-in plugin by placing a same-named folder in a higher-precedence directory — even without write access to the installation.&lt;br /&gt;
&lt;br /&gt;
Media plugins, descending precedence:&lt;br /&gt;
&lt;br /&gt;
# The open &amp;lt;code&amp;gt;.mxw&amp;lt;/code&amp;gt; project&#039;s &amp;lt;code&amp;gt;plugins/media/python/&amp;lt;/code&amp;gt; tree (opt-in via settings, highest precedence)&lt;br /&gt;
# Directories configured explicitly in the settings (Python tab)&lt;br /&gt;
# The per-user data directory, e.g. &amp;lt;code&amp;gt;%APPDATA%/MXWendler/plugins/media/python/&amp;lt;/code&amp;gt;&lt;br /&gt;
# The installation / resource directory: &amp;lt;code&amp;gt;plugins/media/python/&amp;lt;/code&amp;gt; (also &amp;lt;code&amp;gt;plugins/media/python_dev/&amp;lt;/code&amp;gt;, same precedence, for internal/unpublished plugins)&lt;br /&gt;
&lt;br /&gt;
Playlist plugins, descending precedence:&lt;br /&gt;
&lt;br /&gt;
# The open &amp;lt;code&amp;gt;.mxw&amp;lt;/code&amp;gt; project&#039;s &amp;lt;code&amp;gt;plugins/playlist/python/&amp;lt;/code&amp;gt; tree (opt-in via settings, highest precedence)&lt;br /&gt;
# Directories configured explicitly in the settings (Python tab)&lt;br /&gt;
# The per-user data directory: &amp;lt;code&amp;gt;.../plugins/playlist/python/&amp;lt;/code&amp;gt;&lt;br /&gt;
# The installation / resource directory: &amp;lt;code&amp;gt;plugins/playlist/python/&amp;lt;/code&amp;gt; (also &amp;lt;code&amp;gt;plugins/playlist/python_dev/&amp;lt;/code&amp;gt;, same precedence, for internal/unpublished plugins)&lt;br /&gt;
&lt;br /&gt;
=== The manifest: mxw_plugin.ini ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[mxw_plugin]                            ; must be here&lt;br /&gt;
plugin_version = 1                      ; must be V1&lt;br /&gt;
plugin_script_language = Python         ; must be Python&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Common keys:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Used by !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_menu_parent&amp;lt;/code&amp;gt; || both || Menu the plugin is listed under (e.g. &amp;lt;code&amp;gt;Media&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IO&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_menu_name&amp;lt;/code&amp;gt; || both || Display name in the menu&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_grid_name&amp;lt;/code&amp;gt; || both || Short name shown in the grid / media list&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_tooltip&amp;lt;/code&amp;gt; || both || Tooltip text&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_menu_level&amp;lt;/code&amp;gt; (media) / &amp;lt;code&amp;gt;plugin_action_level&amp;lt;/code&amp;gt; (playlist) || both || &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; (default, visible), &amp;lt;code&amp;gt;development&amp;lt;/code&amp;gt; (visible in debug builds only), &amp;lt;code&amp;gt;disabled&amp;lt;/code&amp;gt; (invisible)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Media-only keys:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_media_scheme&amp;lt;/code&amp;gt; || The URI scheme this plugin handles, e.g. &amp;lt;code&amp;gt;generative&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;web&amp;lt;/code&amp;gt;. Media is addressed as &amp;lt;code&amp;gt;&amp;amp;lt;scheme&amp;amp;gt;://&amp;amp;lt;payload&amp;amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_media_payload&amp;lt;/code&amp;gt; || Optional. If set, the plugin handles exactly &amp;lt;code&amp;gt;scheme://payload&amp;lt;/code&amp;gt;; if omitted, it handles every URI of its scheme. Several plugins can share one scheme and dispatch on the payload.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_media_create_uri&amp;lt;/code&amp;gt; || The URI used when the user creates this media from the menu / Create button.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_playlist_playbackmode_default&amp;lt;/code&amp;gt; || Optional. The clip playback mode a freshly added clip of this media starts in: &amp;lt;code&amp;gt;stop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loop&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oneshot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bounce&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jitter&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;random&amp;lt;/code&amp;gt;. Omitted or unknown defaults to &amp;lt;code&amp;gt;loop&amp;lt;/code&amp;gt;. Only seeds the initial mode - a project reload restores the clip&#039;s own saved mode.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_media_has_audio&amp;lt;/code&amp;gt; || Optional. &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; to enable audio output: the host pulls &amp;lt;code&amp;gt;onRenderAudio()&amp;lt;/code&amp;gt; and mixes the PCM into the master.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_media_audio_channels&amp;lt;/code&amp;gt; || Optional (default &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;). Channel count of the produced audio. There is &#039;&#039;&#039;no&#039;&#039;&#039; sample-rate key &amp;amp;ndash; the rate always follows the output device (see Audio, below).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Playlist-only keys:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_grid_bg_color&amp;lt;/code&amp;gt; || Item background color as &amp;lt;code&amp;gt;r g b a&amp;lt;/code&amp;gt; floats, e.g. &amp;lt;code&amp;gt;0.05 0.05 0.45 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_accepts_trigger&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;). When &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, dragging a TRIGGER item onto this item&#039;s grid cell connects it (the drag shows a green &amp;quot;connect&amp;quot; outline) instead of moving/swapping cells, and the plugin can read the connection with &amp;lt;code&amp;gt;mxw.pending_trigger_drop(item_id)&amp;lt;/code&amp;gt;. Set it for a timeline; see [[#Connecting to a TRIGGER item]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_cell_scrub&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; (default &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;). When &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, ALT + left-drag across this item&#039;s grid cell scrubs instead of moving the item: the host draws a playhead line and stashes the 0..1 fraction of the cell width each frame, readable with &amp;lt;code&amp;gt;mxw.pending_cell_scrub(item_id)&amp;lt;/code&amp;gt;. Set it for a timeline; see [[#Connecting to a TRIGGER item]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== The plugin environment ==&lt;br /&gt;
&lt;br /&gt;
=== Per-instance state ===&lt;br /&gt;
&lt;br /&gt;
One Python module serves &#039;&#039;&#039;many simultaneous instances&#039;&#039;&#039; (several clips using the same media plugin, several copies of a playlist item). Before every hook call, the host sets module globals identifying the instance:&lt;br /&gt;
&lt;br /&gt;
* Media plugins: &amp;lt;code&amp;gt;media_id&amp;lt;/code&amp;gt; (integer)&lt;br /&gt;
* Playlist plugins: &amp;lt;code&amp;gt;item_id&amp;lt;/code&amp;gt; (integer) and &amp;lt;code&amp;gt;item_position&amp;lt;/code&amp;gt; (tuple &amp;lt;code&amp;gt;(x, y)&amp;lt;/code&amp;gt;, the grid position)&lt;br /&gt;
&lt;br /&gt;
The standard pattern is a module-level dictionary keyed by the id:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
storage = {}&lt;br /&gt;
&lt;br /&gt;
def onCreate():                    # playlist; media plugins use onOpen(uri)&lt;br /&gt;
    storage[item_id] = my_instance_state()&lt;br /&gt;
&lt;br /&gt;
def onDelete():&lt;br /&gt;
    storage.pop(item_id, None)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Host modules ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt; — the MXWendler command interface (playlist control, layers, clips, ...), see the [[Python command reference|Python command reference]].&lt;br /&gt;
* &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt; — Dear ImGui bindings for drawing settings panels inside MXWendler (used by &amp;lt;code&amp;gt;onRenderPanel()&amp;lt;/code&amp;gt;), documented in the [[Python imgui reference|Python ImGui Reference]].&lt;br /&gt;
&lt;br /&gt;
=== Installing own modules with mxw-pip ===&lt;br /&gt;
&lt;br /&gt;
Plugins may use third-party packages (&amp;lt;code&amp;gt;numpy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;moderngl&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;opencv-python&amp;lt;/code&amp;gt;, ...). Packages are not installed into the installation folder — the &#039;&#039;&#039;mxw-pip&#039;&#039;&#039; helper (shipped next to the StageDesigner executable) installs them into the current user&#039;s writable folder, &#039;&#039;&#039;no administrator rights required&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%APPDATA%\Python\Python312\site-packages&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is exactly the directory StageDesigner prepends to &amp;lt;code&amp;gt;sys.path&amp;lt;/code&amp;gt; when the option &#039;&#039;&#039;Prepend user site-path&#039;&#039;&#039; is enabled (Settings → Python tab).&lt;br /&gt;
&lt;br /&gt;
mxw-pip runs &amp;lt;code&amp;gt;pip&amp;lt;/code&amp;gt; with the &#039;&#039;&#039;Python 3.12 shipped with StageDesigner&#039;&#039;&#039; (&amp;lt;code&amp;gt;python.exe&amp;lt;/code&amp;gt; in the installation folder / in its &amp;lt;code&amp;gt;python312/&amp;lt;/code&amp;gt; subfolder) — nothing else needs to be installed. Only when the shipped interpreter is missing does it fall back to a system Python (&amp;lt;code&amp;gt;py -3.12&amp;lt;/code&amp;gt;, then &amp;lt;code&amp;gt;python&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt;), which must be 3.12 so binary wheels match the runtime ABI.&lt;br /&gt;
&lt;br /&gt;
Step by step:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Settings → Python&#039;&#039;&#039; and enable &#039;&#039;&#039;Prepend user site-path&#039;&#039;&#039;. The two installer buttons below are only active while this option is on, because mxw-pip installs into exactly that folder. Enabling applies immediately; disabling takes full effect after a restart.&lt;br /&gt;
# Click &#039;&#039;&#039;Launch CMD window with mxw-pip module installer..&#039;&#039;&#039; — this opens the installer shell (&amp;lt;code&amp;gt;mxw-pip-shell.bat&amp;lt;/code&amp;gt;). In the shell, type:&lt;br /&gt;
#: &amp;lt;pre&amp;gt;mxw-pip install &amp;lt;modulename&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
#: for example:&lt;br /&gt;
#: &amp;lt;pre&amp;gt;mxw-pip install moderngl&amp;lt;/pre&amp;gt;&lt;br /&gt;
# &#039;&#039;&#039;Restart MXWendler StageDesigner&#039;&#039;&#039; so the new module is loaded.&lt;br /&gt;
&lt;br /&gt;
Other &amp;lt;code&amp;gt;pip&amp;lt;/code&amp;gt; subcommands are passed through unchanged, e.g. &amp;lt;code&amp;gt;mxw-pip list&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw-pip show moderngl&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw-pip uninstall moderngl&amp;lt;/code&amp;gt;. The button &#039;&#039;&#039;Open per-user module install folder..&#039;&#039;&#039; next to the installer button shows the target directory in the Explorer. Both &amp;lt;code&amp;gt;mxw-pip.bat&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;mxw-pip-shell.bat&amp;lt;/code&amp;gt; can also be run directly from the installation folder in any command prompt.&lt;br /&gt;
&lt;br /&gt;
Because the target folder lives in the user profile, every user keeps their own module set, and reinstalling / updating StageDesigner never touches the installed modules.&lt;br /&gt;
&lt;br /&gt;
=== Error handling ===&lt;br /&gt;
&lt;br /&gt;
Exceptions raised by a hook are reported to the interpreter console (IO dialog) — throttled, so a per-frame error does not flood the log. A &#039;&#039;&#039;per-frame hook that throws is blacklisted&#039;&#039;&#039;: it is not called again until the plugin is reloaded, so one broken callback cannot stall the render loop. Playlist plugins can be hot-reloaded from disk (state is snapshotted via &amp;lt;code&amp;gt;onSave()&amp;lt;/code&amp;gt;, the module source re-executed, then &amp;lt;code&amp;gt;onCreate()&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;onLoad()&amp;lt;/code&amp;gt; restore each instance), which also clears the blacklist.&lt;br /&gt;
&lt;br /&gt;
== Media plugins ==&lt;br /&gt;
&lt;br /&gt;
A media plugin is addressed by a URI: &amp;lt;code&amp;gt;&amp;amp;lt;scheme&amp;amp;gt;://&amp;amp;lt;payload&amp;amp;gt;&amp;lt;/code&amp;gt;, for example &amp;lt;code&amp;gt;generative://cube_spin_opengl&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;web://https://mxwendler.net&amp;lt;/code&amp;gt;. Every created media instance internally carries a unique instance token so two clips never share state; the plugin always sees the clean URI.&lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
&lt;br /&gt;
All hooks are optional except &amp;lt;code&amp;gt;onOpen&amp;lt;/code&amp;gt; and &#039;&#039;&#039;one of the two render hooks&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Hook !! Direction !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onOpen(uri)&amp;lt;/code&amp;gt; || returns &amp;lt;code&amp;gt;(width, height, length, fps, has_alpha)&amp;lt;/code&amp;gt; || Called when the media is created / loaded. Create the per-instance state here. Do &#039;&#039;&#039;not&#039;&#039;&#039; touch OpenGL yet (see below).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onRenderFrame(frame)&amp;lt;/code&amp;gt; || returns a pixel buffer || Approach 1 and 2: return a &amp;lt;code&amp;gt;H*W*4&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; buffer (bytes / bytearray / numpy), &#039;&#039;&#039;BGRA&#039;&#039;&#039; byte order, top-down. The host uploads it into the media texture.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onRenderFrameGL(frame, texture, width, height)&amp;lt;/code&amp;gt; || returns &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt; || Approach 3: render &#039;&#039;&#039;directly into the media texture&#039;&#039;&#039; — &amp;lt;code&amp;gt;texture&amp;lt;/code&amp;gt; is its raw GL handle. Return &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; when the frame is in the texture; the pixel upload path is then skipped. Tried before &amp;lt;code&amp;gt;onRenderFrame&amp;lt;/code&amp;gt;; a plugin implements one of the two.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onRenderAudio(num_frames)&amp;lt;/code&amp;gt; || returns interleaved float32 || Audio-producing media: return &#039;&#039;num_frames&#039;&#039;&amp;amp;times;channels interleaved &#039;&#039;&#039;float32&#039;&#039;&#039; samples (bytes / bytearray / numpy). The host pulls exactly the frames needed for a gapless cushion. Enabled by &amp;lt;code&amp;gt;plugin_media_has_audio&amp;lt;/code&amp;gt;; generate at the injected &amp;lt;code&amp;gt;audio_samplerate&amp;lt;/code&amp;gt; (see the Audio section).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onClose()&amp;lt;/code&amp;gt; || — || The media is destroyed: release per-instance resources.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onRenderPanel()&amp;lt;/code&amp;gt; || — || Draw ImGui controls (via &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt;) in the clip panel, above the Video Info section.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSizeChange(w, h)&amp;lt;/code&amp;gt; || — || The host changed the render size: recreate size-dependent resources.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSpeedRange()&amp;lt;/code&amp;gt; || returns &amp;lt;code&amp;gt;(min, max)&amp;lt;/code&amp;gt; || Allowed clip playback speed range. Without it the media is locked to speed 1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSetSpeed(speed)&amp;lt;/code&amp;gt; || — || The clip playback speed changed. Not clamped: 0 and negative values are allowed.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSave()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;onLoad(state)&amp;lt;/code&amp;gt; || string round-trip || Persist per-instance state in the project file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onDisplayName()&amp;lt;/code&amp;gt; || returns string || Optional live display name (e.g. the web plugin reports the current page URL).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onGetParams()&amp;lt;/code&amp;gt; || returns a list of dicts || Declare addressable parameters, called once per instance and cached: &amp;lt;code&amp;gt;{&amp;quot;name&amp;quot;: str, &amp;quot;type&amp;quot;: &amp;quot;float&amp;quot;|&amp;quot;string&amp;quot;, &amp;quot;min&amp;quot;: float, &amp;quot;max&amp;quot;: float, &amp;quot;default&amp;quot;: float|str}&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; ignored for &amp;lt;code&amp;gt;&amp;quot;string&amp;quot;&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; defaults to &amp;lt;code&amp;gt;&amp;quot;float&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onParamChanged(index, value)&amp;lt;/code&amp;gt; || — || A parameter was set via OSC, Python or JS at &amp;lt;code&amp;gt;.../clip/media/1/param/&amp;amp;lt;index+1&amp;amp;gt;&amp;lt;/code&amp;gt; (0-based &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;). Store or apply it — the host never caches the value itself.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Parameters are addressed exactly like shader effect parameters, e.g. &amp;lt;code&amp;gt;/mxw/track/2/layer/1/clip/media/1/param/1 0.8&amp;lt;/code&amp;gt; or, for a &amp;lt;code&amp;gt;&amp;quot;string&amp;quot;&amp;lt;/code&amp;gt;-typed param, &amp;lt;code&amp;gt;/mxw/track/2/layer/1/clip/media/1/param/2 &amp;quot;https://www.mxwendler.net&amp;quot;&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;media/1&amp;lt;/code&amp;gt; segment reflects the clip&#039;s single active media slot (any other index is out of range). Because the host does not persist a param&#039;s value, a plugin that wants one to survive a project reload must fold it into its own &amp;lt;code&amp;gt;onSave()&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;onLoad()&amp;lt;/code&amp;gt; and hand the restored value back as &amp;lt;code&amp;gt;onGetParams()&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;&amp;quot;default&amp;quot;&amp;lt;/code&amp;gt; — which runs after &amp;lt;code&amp;gt;onLoad()&amp;lt;/code&amp;gt; already restored the instance state.&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
&lt;br /&gt;
A media plugin can also &#039;&#039;&#039;produce&#039;&#039;&#039; audio: implement &amp;lt;code&amp;gt;onRenderAudio(num_frames)&amp;lt;/code&amp;gt; returning &#039;&#039;num_frames&#039;&#039;&amp;amp;times;channels interleaved &#039;&#039;&#039;float32&#039;&#039;&#039; samples, and set &amp;lt;code&amp;gt;plugin_media_has_audio = 1&amp;lt;/code&amp;gt; in the manifest (channel count via &amp;lt;code&amp;gt;plugin_media_audio_channels&amp;lt;/code&amp;gt;, default 2). The host pulls exactly the frames it needs each render frame into a gapless lookahead cushion, so the sound survives render-loop hitches.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;sample rate always follows the current output device&#039;&#039;&#039; &amp;amp;ndash; there is no sample-rate manifest key. The host injects the live format as the module globals &amp;lt;code&amp;gt;audio_samplerate&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;audio_channels&amp;lt;/code&amp;gt; (like &amp;lt;code&amp;gt;media_id&amp;lt;/code&amp;gt;) before every call; generate at &amp;lt;code&amp;gt;audio_samplerate&amp;lt;/code&amp;gt; and the audio adapts if the device is reopened at another rate. (An optional &amp;lt;code&amp;gt;onAudioFormat()&amp;lt;/code&amp;gt; returning &amp;lt;code&amp;gt;(rate, channels)&amp;lt;/code&amp;gt; may declare the channel count; its rate is ignored.)&lt;br /&gt;
&lt;br /&gt;
To &#039;&#039;&#039;consume&#039;&#039;&#039; audio (audio-reactive media), read it with the &amp;lt;code&amp;gt;mxw.audio&amp;lt;/code&amp;gt; capture API &amp;amp;ndash; see the [[Python command reference]]: &amp;lt;code&amp;gt;mxw.audio.output_capture()&amp;lt;/code&amp;gt; for the master mix or &amp;lt;code&amp;gt;mxw.audio.input_capture()&amp;lt;/code&amp;gt; for the input device.&lt;br /&gt;
&lt;br /&gt;
=== OpenGL rules for media plugins ===&lt;br /&gt;
&lt;br /&gt;
These rules apply to approaches 2 and 3:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Never create a standalone GL context&#039;&#039;&#039; (no windowed/standalone &amp;lt;code&amp;gt;moderngl.create_context()&amp;lt;/code&amp;gt; at import or in &amp;lt;code&amp;gt;onOpen&amp;lt;/code&amp;gt;). MXWendler makes its own context current every frame; GL objects created in a foreign context will be dereferenced against the wrong context and crash the driver.&lt;br /&gt;
* Instead, &#039;&#039;&#039;lazily attach on the first render call&#039;&#039;&#039;: &amp;lt;code&amp;gt;moderngl.create_context()&amp;lt;/code&amp;gt; inside &amp;lt;code&amp;gt;onRenderFrame / onRenderFrameGL&amp;lt;/code&amp;gt; attaches to MXWendler&#039;s context, which the host guarantees to be current there.&lt;br /&gt;
* The host &#039;&#039;&#039;snapshots and restores all relevant GL state&#039;&#039;&#039; around the render hooks (FBO bindings, program, VAO, buffers, viewport, enables, pixel store). The plugin does not need to unbind anything.&lt;br /&gt;
&lt;br /&gt;
=== Approach 1: rendering into pixels (CPU) ===&lt;br /&gt;
&lt;br /&gt;
The simplest approach: compute the frame on the CPU and return it. No OpenGL knowledge required. The host uploads the buffer into the media texture through a PBO (pixel buffer object) double-buffer, so the upload is asynchronous and cheap — the cost of this approach is the CPU rendering itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
W, H = 640, 360&lt;br /&gt;
storage = {}&lt;br /&gt;
&lt;br /&gt;
def onOpen(uri):&lt;br /&gt;
    storage[media_id] = {&amp;quot;phase&amp;quot;: 0.0}&lt;br /&gt;
    return (W, H, 1, 60.0, True)          # width, height, length, fps, has_alpha&lt;br /&gt;
&lt;br /&gt;
def onRenderFrame(frame):&lt;br /&gt;
    inst = storage[media_id]&lt;br /&gt;
    inst[&amp;quot;phase&amp;quot;] += 0.01&lt;br /&gt;
    # a moving horizontal gradient, BGRA byte order, top-down&lt;br /&gt;
    x = (np.linspace(0.0, 1.0, W) + inst[&amp;quot;phase&amp;quot;]) % 1.0&lt;br /&gt;
    row = np.zeros((W, 4), dtype=np.uint8)&lt;br /&gt;
    row[:, 0] = (x * 255).astype(np.uint8)     # B&lt;br /&gt;
    row[:, 2] = ((1 - x) * 255).astype(np.uint8)  # R&lt;br /&gt;
    row[:, 3] = 255                            # A&lt;br /&gt;
    return np.ascontiguousarray(np.tile(row, (H, 1, 1)))&lt;br /&gt;
&lt;br /&gt;
def onClose():&lt;br /&gt;
    storage.pop(media_id, None)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use this for: generated images, PIL/Pillow output, OpenCV results, slow-changing content.&lt;br /&gt;
&lt;br /&gt;
=== Approach 2: rendering into an FBO and streaming ===&lt;br /&gt;
&lt;br /&gt;
Render with OpenGL (e.g. via &#039;&#039;&#039;ModernGL&#039;&#039;&#039;, installed once with &amp;lt;code&amp;gt;mxw-pip install moderngl numpy&amp;lt;/code&amp;gt;) into an offscreen framebuffer, read the pixels back and return them like in approach 1. The scene renders on the GPU, but every frame makes a round trip GPU → CPU (&amp;lt;code&amp;gt;fbo.read()&amp;lt;/code&amp;gt;) → GPU (PBO upload).&lt;br /&gt;
&lt;br /&gt;
Bundled reference: &amp;lt;code&amp;gt;plugins/media/python/plugin_opengl_cube&amp;lt;/code&amp;gt; ([https://github.com/mxwendler/mxw-plugin-opengl-cube github]).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import moderngl&lt;br /&gt;
&lt;br /&gt;
storage = {}&lt;br /&gt;
&lt;br /&gt;
class inst_t:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.ctx = None&lt;br /&gt;
        self.fbo = None&lt;br /&gt;
&lt;br /&gt;
def onOpen(uri):&lt;br /&gt;
    storage[media_id] = inst_t()&lt;br /&gt;
    return (1024, 1024, 1, 60.0, True)&lt;br /&gt;
&lt;br /&gt;
def onRenderFrame(frame):&lt;br /&gt;
    inst = storage[media_id]&lt;br /&gt;
    if inst.ctx is None:&lt;br /&gt;
        # first frame: attach to MXWendler&#039;s context (never earlier!)&lt;br /&gt;
        inst.ctx = moderngl.create_context()&lt;br /&gt;
        color = inst.ctx.texture((1024, 1024), 4)&lt;br /&gt;
        depth = inst.ctx.depth_renderbuffer((1024, 1024))&lt;br /&gt;
        inst.fbo = inst.ctx.framebuffer([color], depth)&lt;br /&gt;
        # ... build program / vao here ...&lt;br /&gt;
&lt;br /&gt;
    inst.fbo.use()&lt;br /&gt;
    inst.ctx.clear(0.0, 0.0, 0.0, 0.0, depth=1.0)&lt;br /&gt;
    # ... draw the scene ...&lt;br /&gt;
&lt;br /&gt;
    # read back: GL is bottom-up RGBA, the host wants top-down BGRA&lt;br /&gt;
    raw = inst.fbo.read(components=4, alignment=1)&lt;br /&gt;
    img = np.frombuffer(raw, dtype=np.uint8).reshape((1024, 1024, 4))&lt;br /&gt;
    img = np.flipud(img)&lt;br /&gt;
    return np.ascontiguousarray(img[:, :, [2, 1, 0, 3]])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use this for: GPU-rendered content when you also need the pixels on the CPU (analysis, recording), or as a stepping stone to approach 3.&lt;br /&gt;
&lt;br /&gt;
=== Approach 3: rendering into a bound texture target (direct) ===&lt;br /&gt;
&lt;br /&gt;
The fastest path: the host passes the &#039;&#039;&#039;raw GL handle of the media texture&#039;&#039;&#039; to &amp;lt;code&amp;gt;onRenderFrameGL&amp;lt;/code&amp;gt;. The plugin attaches it to its own framebuffer and renders straight into it. &#039;&#039;&#039;No readback, no upload, no texture streaming&#039;&#039;&#039; — the frame never leaves the GPU.&lt;br /&gt;
&lt;br /&gt;
Bundled reference: &amp;lt;code&amp;gt;plugins/media/python/plugin_opengl_cube_direct&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import moderngl&lt;br /&gt;
&lt;br /&gt;
storage = {}&lt;br /&gt;
&lt;br /&gt;
class inst_t:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.ctx = None&lt;br /&gt;
        self.fbo = None&lt;br /&gt;
        self.depth = None&lt;br /&gt;
        self.fbo_key = None       # (texture, w, h) the fbo was built for&lt;br /&gt;
&lt;br /&gt;
def onOpen(uri):&lt;br /&gt;
    storage[media_id] = inst_t()&lt;br /&gt;
    return (1024, 1024, 1, 60.0, True)&lt;br /&gt;
&lt;br /&gt;
def onRenderFrameGL(frame, texture, width, height):&lt;br /&gt;
    inst = storage[media_id]&lt;br /&gt;
    if inst.ctx is None:&lt;br /&gt;
        inst.ctx = moderngl.create_context()   # attach to MXWendler&#039;s context&lt;br /&gt;
        # ... build program / vao here ...&lt;br /&gt;
&lt;br /&gt;
    # (re)wrap the host texture when the handle or size changed: the host&lt;br /&gt;
    # recreates the media texture on a render size change&lt;br /&gt;
    if inst.fbo_key != (texture, width, height):&lt;br /&gt;
        if inst.fbo:&lt;br /&gt;
            inst.fbo.release()&lt;br /&gt;
        if inst.depth:&lt;br /&gt;
            inst.depth.release()&lt;br /&gt;
        color = inst.ctx.external_texture(texture, (width, height), 4, 0, &amp;quot;f1&amp;quot;)&lt;br /&gt;
        inst.depth = inst.ctx.depth_renderbuffer((width, height))&lt;br /&gt;
        inst.fbo = inst.ctx.framebuffer([color], inst.depth)&lt;br /&gt;
        inst.fbo_key = (texture, width, height)&lt;br /&gt;
&lt;br /&gt;
    inst.fbo.use()&lt;br /&gt;
    inst.ctx.clear(0.0, 0.0, 0.0, 0.0, depth=1.0)&lt;br /&gt;
    # ... draw the scene; flip Y in the projection, see below ...&lt;br /&gt;
&lt;br /&gt;
    return True    # the frame is in the texture: host skips the upload path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules specific to the direct approach:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Never &amp;lt;code&amp;gt;release()&amp;lt;/code&amp;gt; the external texture wrapper&#039;&#039;&#039; — the GL texture belongs to MXWendler. Only release your own framebuffer and depth renderbuffer.&lt;br /&gt;
* &#039;&#039;&#039;Rebuild the framebuffer when &amp;lt;code&amp;gt;(texture, width, height)&amp;lt;/code&amp;gt; changes.&#039;&#039;&#039; The handle is not stable: a render size change makes the host recreate the media texture.&lt;br /&gt;
* &#039;&#039;&#039;Flip Y.&#039;&#039;&#039; MXWendler media textures are top-down (row 0 = top of the image), a GL render is bottom-up. Negate the Y row of your projection matrix (approaches 1/2 flip on the CPU instead, e.g. with &amp;lt;code&amp;gt;numpy.flipud&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
=== Choosing an approach ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! 1: Pixels (CPU) !! 2: FBO + streaming !! 3: Direct texture&lt;br /&gt;
|-&lt;br /&gt;
| Scene renders on || CPU || GPU || GPU&lt;br /&gt;
|-&lt;br /&gt;
| Per-frame copies || CPU → GPU upload || GPU → CPU readback + CPU → GPU upload || none&lt;br /&gt;
|-&lt;br /&gt;
| OpenGL required || no || yes || yes&lt;br /&gt;
|-&lt;br /&gt;
| CPU access to the pixels || yes (you made them) || yes (after readback) || no&lt;br /&gt;
|-&lt;br /&gt;
| Typical use || generated images, PIL, OpenCV || GPU render that also needs CPU pixels || pure GPU generative content, best performance&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Playlist plugins ==&lt;br /&gt;
&lt;br /&gt;
A playlist plugin is an item placed in the playlist grid. It participates in the cue lifecycle: it can run logic when its cue is played, every frame while its cue is active, or every frame globally. Playlist control functions (&amp;lt;code&amp;gt;mxw.playlist.play()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw.playlist.navigate_index()&amp;lt;/code&amp;gt;, ...) are documented in the [[Python command reference|Python command reference]].&lt;br /&gt;
&lt;br /&gt;
=== Hooks ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Hook !! Required !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onCreate()&amp;lt;/code&amp;gt; || yes || A new instance was placed in the grid (also called after hot-reload): create the per-instance state entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onDelete()&amp;lt;/code&amp;gt; || yes || The instance was deleted: release the state entry.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onAction()&amp;lt;/code&amp;gt; || yes || The item&#039;s cue was played (the item &#039;&#039;fires&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onPostAction()&amp;lt;/code&amp;gt; || no || Called after the action completed.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSave()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;onLoad(state)&amp;lt;/code&amp;gt; || yes || Serialize / restore per-instance state (string). Called on project save/load and around hot-reload.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onRenderPanel()&amp;lt;/code&amp;gt; || yes || Draw the item&#039;s settings panel with &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getText()&amp;lt;/code&amp;gt; || yes || Detail text appended to the item&#039;s grid label.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onNewFrameAlways()&amp;lt;/code&amp;gt; || no || Called every rendered frame, regardless of cue state.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onNewFrameInPlayoutCue()&amp;lt;/code&amp;gt; || no || Called every rendered frame while the item&#039;s cue is the active playout cue.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onPause(is_paused)&amp;lt;/code&amp;gt; || no || Pause was pressed / released.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onPreparePlayback()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;onCleanup()&amp;lt;/code&amp;gt; || no || Prepare / release playout resources.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onActivateInUI()&amp;lt;/code&amp;gt; || no || The item was selected in the user interface.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onActiveCueChange(direction)&amp;lt;/code&amp;gt; || no || The active cue changed past this item (navigation).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;onSettingsChanged()&amp;lt;/code&amp;gt; || no || Item settings were changed from outside.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getDuration()&amp;lt;/code&amp;gt; || no || Report the item&#039;s action duration in milliseconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getTimeSinceOnActionIssued()&amp;lt;/code&amp;gt; || no || Report elapsed action time in milliseconds (drives the progress display).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getColorBG()&amp;lt;/code&amp;gt; || no || Return a &amp;lt;code&amp;gt;mxw_imgui.Vec4&amp;lt;/code&amp;gt; (rgb 0..255) to set the grid cell background color dynamically.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;renderBlinking()&amp;lt;/code&amp;gt; || no || Return &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; to make the grid cell blink.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;getProgress()&amp;lt;/code&amp;gt; || no || Return &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; to fill the cell&#039;s bottom progress bar (the same bar the built-in advance/fade items draw); &amp;lt;code&amp;gt;&amp;amp;lt;= 0&amp;lt;/code&amp;gt; draws nothing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Connecting to a TRIGGER item ===&lt;br /&gt;
&lt;br /&gt;
A playlist plugin (e.g. a keyframe timeline) can bind to a TRIGGER item and animate its layer/clip controls. The user drops a trigger either onto the plugin&#039;s settings panel or onto its grid cell; the plugin resolves the connection to the trigger&#039;s grid &amp;lt;code&amp;gt;(col, row)&amp;lt;/code&amp;gt; and enumerates its controls from there. No need to play the trigger first — the controls are read from the connected preload&#039;s fixture layer, and the very same &amp;lt;code&amp;gt;(col,row)&amp;lt;/code&amp;gt; address resolves the &#039;&#039;live&#039;&#039; layer during playout.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Function !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw_imgui.accept_trigger_drop()&amp;lt;/code&amp;gt; || Makes the current panel window a drop target for a trigger; returns the dropped trigger&#039;s 1-based &amp;lt;code&amp;gt;(col, row)&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;(-1, -1)&amp;lt;/code&amp;gt;. Handles the &amp;quot;drop onto the panel&amp;quot; route.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw.pending_trigger_drop(item_id)&amp;lt;/code&amp;gt; || Returns a &amp;lt;code&amp;gt;(col, row)&amp;lt;/code&amp;gt; stashed by the host when a trigger was dropped onto &#039;&#039;this&#039;&#039; plugin item&#039;s grid cell (pass your own &amp;lt;code&amp;gt;item_id&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;(-1, -1)&amp;lt;/code&amp;gt;. Handles the &amp;quot;drop onto the grid cell&amp;quot; route.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw.trigger_controls(col, row)&amp;lt;/code&amp;gt; || Returns the trigger&#039;s animatable (slider) controls as &amp;lt;code&amp;gt;(label, address)&amp;lt;/code&amp;gt; pairs — layer, clip, effect and media params. Re-read it every frame: controls the user swaps on the clip appear/vanish live. Each &amp;lt;code&amp;gt;address&amp;lt;/code&amp;gt; is usable with &amp;lt;code&amp;gt;mxw.widget(address).setValue()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw.pending_cell_scrub(item_id)&amp;lt;/code&amp;gt; || Returns the 0..1 fraction of an ALT + left-drag across &#039;&#039;this&#039;&#039; plugin item&#039;s grid cell (stashed by the host each frame while dragging, consumed on read), or &amp;lt;code&amp;gt;-1.0&amp;lt;/code&amp;gt;. Needs the &amp;lt;code&amp;gt;plugin_cell_scrub&amp;lt;/code&amp;gt; manifest opt-in. Poll it in &amp;lt;code&amp;gt;onNewFrameAlways()&amp;lt;/code&amp;gt; so scrubbing also works while the panel is closed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Poll both drop routes at the top of &amp;lt;code&amp;gt;onRenderPanel()&amp;lt;/code&amp;gt; and store the resulting &amp;lt;code&amp;gt;(col,row)&amp;lt;/code&amp;gt;; then call &amp;lt;code&amp;gt;mxw.trigger_controls()&amp;lt;/code&amp;gt; to (re)build your control list each frame.&lt;br /&gt;
&lt;br /&gt;
A time connection between the connected clip and the plugin follows from these pieces: the clip&#039;s &amp;lt;code&amp;gt;.../clip/Position&amp;lt;/code&amp;gt; control (normalized 0..1) is the clip&#039;s own time axis. Write it when your playhead moves (scrub → seek) and read it every frame to follow the clip when it is scrubbed — or simply playing. See the timeline plugin&#039;s &amp;lt;code&amp;gt;sync_time_link()&amp;lt;/code&amp;gt; for a worked example including the echo filtering (a written Position reads back frame-quantized).&lt;br /&gt;
&lt;br /&gt;
=== Minimal example ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import pickle, codecs&lt;br /&gt;
import mxw&lt;br /&gt;
import mxw_imgui&lt;br /&gt;
&lt;br /&gt;
class state_t:&lt;br /&gt;
    fire_count = 0&lt;br /&gt;
&lt;br /&gt;
storage = {}&lt;br /&gt;
&lt;br /&gt;
def onCreate():&lt;br /&gt;
    storage[item_id] = state_t()&lt;br /&gt;
&lt;br /&gt;
def onDelete():&lt;br /&gt;
    storage.pop(item_id, None)&lt;br /&gt;
&lt;br /&gt;
def onAction():&lt;br /&gt;
    # the item&#039;s cue was played&lt;br /&gt;
    storage[item_id].fire_count += 1&lt;br /&gt;
&lt;br /&gt;
def getText():&lt;br /&gt;
    return &amp;quot; : fired %d times&amp;quot; % storage[item_id].fire_count&lt;br /&gt;
&lt;br /&gt;
def onRenderPanel():&lt;br /&gt;
    inst = storage[item_id]&lt;br /&gt;
    mxw_imgui.text_unformatted(&amp;quot;Fired %d times&amp;quot; % inst.fire_count)&lt;br /&gt;
    if mxw_imgui.button(&amp;quot;Reset&amp;quot;):&lt;br /&gt;
        inst.fire_count = 0&lt;br /&gt;
&lt;br /&gt;
def onSave():&lt;br /&gt;
    return codecs.encode(pickle.dumps(storage[item_id]), &amp;quot;base64&amp;quot;).decode()&lt;br /&gt;
&lt;br /&gt;
def onLoad(serialized):&lt;br /&gt;
    storage[item_id] = pickle.loads(codecs.decode(serialized.encode(), &amp;quot;base64&amp;quot;))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With a manifest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[mxw_plugin]&lt;br /&gt;
plugin_version = 1&lt;br /&gt;
plugin_script_language = Python&lt;br /&gt;
plugin_menu_parent = IO&lt;br /&gt;
plugin_menu_name = Fire Counter&lt;br /&gt;
plugin_grid_name = Counter&lt;br /&gt;
plugin_tooltip = Counts how often its cue was played&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bundled references, all in the [https://github.com/mxwendler/mxw-plugins-playlist mxw-plugins-playlist] repository: &amp;lt;code&amp;gt;plugins/playlist/python/plugin_advance_datetime&amp;lt;/code&amp;gt; (timed playlist navigation, rich settings panel), &amp;lt;code&amp;gt;plugin_video_writer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;plugin_comment&amp;lt;/code&amp;gt; (a minimal example: a no-op annotation item).&lt;br /&gt;
&lt;br /&gt;
== Example plugins on GitHub ==&lt;br /&gt;
&lt;br /&gt;
The bundled example plugins are maintained as public repositories under [https://github.com/mxwendler github.com/mxwendler], grouped by type — good starting points to fork for an own plugin:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Plugin !! Type !! Approach / purpose !! Repository&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_opengl_cube&amp;lt;/code&amp;gt; || media || Approach 2: ModernGL cube into an offscreen FBO, streamed || [https://github.com/mxwendler/mxw-plugins-media mxw-plugins-media]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_opengl_cube_direct&amp;lt;/code&amp;gt; || media || Approach 3: same cube rendered directly into the media texture || [https://github.com/mxwendler/mxw-plugins-media mxw-plugins-media]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_web_media&amp;lt;/code&amp;gt; || media || A web browser as media source (whole-scheme &amp;lt;code&amp;gt;web://&amp;lt;/code&amp;gt; plugin) || [https://github.com/mxwendler/mxw-plugins-media mxw-plugins-media]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_fragcoord&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;plugin_shadertoy&amp;lt;/code&amp;gt; || media || Shader-as-generative-media (FragCoord.xyz / Shadertoy) || [https://github.com/mxwendler/mxw-plugins-media mxw-plugins-media]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_advance_datetime&amp;lt;/code&amp;gt; || playlist || Timed playlist navigation with a rich settings panel || [https://github.com/mxwendler/mxw-plugins-playlist mxw-plugins-playlist]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_video_writer&amp;lt;/code&amp;gt; || playlist || Write video files from the playlist || [https://github.com/mxwendler/mxw-plugins-playlist mxw-plugins-playlist]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plugin_comment&amp;lt;/code&amp;gt; || playlist || Minimal example: a no-op text annotation item || [https://github.com/mxwendler/mxw-plugins-playlist mxw-plugins-playlist]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Developing a new plugin inside a project ===&lt;br /&gt;
&lt;br /&gt;
The most convenient place to develop a plugin is &#039;&#039;&#039;inside a project folder&#039;&#039;&#039;: the plugin travels with the show, needs no write access to the installation, and overrides a same-named bundled plugin. Conceptually:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Create a project folder&#039;&#039;&#039; — a plain directory that will hold everything belonging to the show, e.g. &amp;lt;code&amp;gt;D:/shows/particles/&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Save the project file there&#039;&#039;&#039; — &#039;&#039;File → Save As..&#039;&#039; into that folder, e.g. &amp;lt;code&amp;gt;D:/shows/particles/particles.mxw&amp;lt;/code&amp;gt;. The folder containing the &amp;lt;code&amp;gt;.mxw&amp;lt;/code&amp;gt; file &#039;&#039;is&#039;&#039; the project folder; loading the project later makes MXWendler pick up its plugins again.&lt;br /&gt;
# &#039;&#039;&#039;Create the plugin directory there&#039;&#039;&#039; — the project mirrors the installation layout: &amp;lt;code&amp;gt;D:/shows/particles/plugins/media/python/&amp;amp;lt;plugin_folder&amp;amp;gt;/&amp;lt;/code&amp;gt; for media plugins (&amp;lt;code&amp;gt;plugins/playlist/python/...&amp;lt;/code&amp;gt; for playlist plugins). Enable &#039;&#039;Settings → Python → Check for plugins inside the project folder&#039;&#039; — project plugins have the highest precedence of all plugin locations.&lt;br /&gt;
&lt;br /&gt;
=== Letting Claude Code write the plugin ===&lt;br /&gt;
&lt;br /&gt;
An AI coding agent like [https://claude.com/claude-code Claude Code] can write a complete plugin from the contract described on this page. Start it &#039;&#039;&#039;in the project folder&#039;&#039;&#039;, so it creates the plugin directly where MXWendler looks for it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd D:/shows/particles&lt;br /&gt;
claude&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Give it the reference material and a precise task — for a generative OpenGL particle system for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Create an MXWendler media plugin under plugins/media/python/plugin_particle_system/&lt;br /&gt;
(folder + mxw_plugin.ini + mxw_main.py).&lt;br /&gt;
&lt;br /&gt;
Reference: the bundled example in &amp;lt;MXWendler install dir&amp;gt;/plugins/media/python/&lt;br /&gt;
plugin_opengl_cube_direct/ - follow its structure and hook usage exactly, and the&lt;br /&gt;
plugin howto at https://wiki.mxwendler.net/index.php?title=Python_plugin_reference.&lt;br /&gt;
&lt;br /&gt;
The plugin is a generative OpenGL particle system, addressed as&lt;br /&gt;
generative://particle_system, rendered with ModernGL directly into the media&lt;br /&gt;
texture via onRenderFrameGL (no readback, no onRenderFrame). Keep per-instance&lt;br /&gt;
state keyed by media_id. Emit particles from the center, integrate velocity and&lt;br /&gt;
gravity per frame scaled by the clip playback speed (onSetSpeed, onSpeedRange&lt;br /&gt;
-5..5). Expose particle count, gravity and start size as sliders in&lt;br /&gt;
onRenderPanel (mxw_imgui) and persist them via onSave/onLoad. Respect the GL&lt;br /&gt;
rules: attach with moderngl.create_context() lazily on the first render call,&lt;br /&gt;
never release the external texture, rebuild the fbo when (texture, w, h)&lt;br /&gt;
changes, flip Y in the projection.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then iterate: create the media in a clip (it appears under its &amp;lt;code&amp;gt;plugin_menu_name&amp;lt;/code&amp;gt;, or address &amp;lt;code&amp;gt;generative://particle_system&amp;lt;/code&amp;gt; directly) and refine with follow-up prompts (&amp;quot;make the particles fade out&amp;quot;, &amp;quot;add a color gradient slider&amp;quot;, ...). Errors show up in the interpreter console. For playlist plugins, &#039;&#039;Settings → Python → Reload Python Plugins&#039;&#039; hot-reloads the edited source; for media plugins, recreate the media (or restart) to re-import the module.&lt;br /&gt;
&lt;br /&gt;
== Persistence ==&lt;br /&gt;
&lt;br /&gt;
Both plugin types persist per-instance state through the &amp;lt;code&amp;gt;onSave() → string&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;onLoad(string)&amp;lt;/code&amp;gt; pair. The string is stored inside the project file; anything goes, a common choice is base64-encoded pickle (see the playlist example above). Media plugins additionally have their render size stored and restored by the host automatically.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nothing appears in the menu&#039;&#039;&#039; — check the manifest: &amp;lt;code&amp;gt;plugin_version = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;plugin_script_language = Python&amp;lt;/code&amp;gt;, a non-empty &amp;lt;code&amp;gt;plugin_menu_name&amp;lt;/code&amp;gt;, and the level key (&amp;lt;code&amp;gt;development&amp;lt;/code&amp;gt; plugins only show in debug builds).&lt;br /&gt;
* &#039;&#039;&#039;Errors&#039;&#039;&#039; — open the interpreter console (IO dialog): hook exceptions are reported there (throttled). Remember that a throwing per-frame hook is blacklisted until reload.&lt;br /&gt;
* &#039;&#039;&#039;Media shows black&#039;&#039;&#039; — &amp;lt;code&amp;gt;onRenderFrame&amp;lt;/code&amp;gt; returned a buffer of the wrong size (must be &amp;lt;code&amp;gt;width*height*4&amp;lt;/code&amp;gt; bytes), or a GL plugin created its own context instead of attaching to MXWendler&#039;s (see the OpenGL rules).&lt;br /&gt;
* &#039;&#039;&#039;Missing packages&#039;&#039;&#039; — install them with mxw-pip (see [[#Installing own modules with mxw-pip|Installing own modules with mxw-pip]]) and make sure &#039;&#039;&#039;Prepend user site-path&#039;&#039;&#039; is enabled: the embedded interpreter does not see a system-wide Python installation&#039;s packages.&lt;br /&gt;
[[Category:Python]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Python_command_reference&amp;diff=6210</id>
		<title>Python command reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Python_command_reference&amp;diff=6210"/>
		<updated>2026-08-09T16:00:34Z</updated>

		<summary type="html">&lt;p&gt;Admin: docs: audio streams — mxw.audio capture + audio-producing media plugins (device-rate adaptive)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MXWendler wiki page: Python command reference (module mxw) --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Intended location: https://wiki.mxwendler.net/index.php?title=Python_command_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_imgui_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_plugin_reference --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page lists the commands of the Python module &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt;, MXWendler&#039;s general Python command interface. It is available from the script console and from Python plugins (see the [[Python plugin reference|Python Plugin Howto]]). For drawing plugin panels see the [[Python imgui reference|Python ImGui Reference]].&lt;br /&gt;
&lt;br /&gt;
The embedded interpreter is &#039;&#039;&#039;Python 3.12&#039;&#039;&#039;. Import is implicit in the script console; in a plugin module use &amp;lt;code&amp;gt;import mxw&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The presented Python commands supported in version 7.2. and up&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Legend ===&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FLOATS&#039;&#039; are written with one decimal: &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; &amp;amp;rarr; every float between 0 and 1 inclusive.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;INTEGERS&#039;&#039; are written as plain numbers or ranges: &amp;lt;code&amp;gt;1 .. 5&amp;lt;/code&amp;gt; &amp;amp;rarr; the integers 1,2,3,4,5.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;STRINGS&#039;&#039; are written between double quotes.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; appears, two alternative call formats produce a similar result; use one at a time.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Addressing:&#039;&#039;&#039; widgets are targeted by their OSC-style address string, e.g. &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip&amp;lt;/code&amp;gt;. The same addresses used over OSC work here.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Access model (7.2):&#039;&#039;&#039; widget values are read/written through &amp;lt;code&amp;gt;mxw.widget(address)&amp;lt;/code&amp;gt;; global functions live in the submodules/factories &amp;lt;code&amp;gt;mxw.playlist&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw.io&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw.preload(n)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw.media(name)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mxw.grabber(name)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Reference ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Software Info&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.millis&amp;lt;/code&amp;gt; || milliseconds passed since the software was opened || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;passed time is &amp;quot; + str(mxw.millis))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.width&amp;lt;/code&amp;gt; || current frame width in px || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;frame width is &amp;quot; + str(mxw.width))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.height&amp;lt;/code&amp;gt; || current frame height in px || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;frame height is &amp;quot; + str(mxw.height))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.outwidth&amp;lt;/code&amp;gt; || current output width in px || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;output width is &amp;quot; + str(mxw.outwidth))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.outheight&amp;lt;/code&amp;gt; || current output height in px || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;output height is &amp;quot; + str(mxw.outheight))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.framecounter&amp;lt;/code&amp;gt; || number of frames rendered since the software was opened || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;frames rendered: &amp;quot; + str(mxw.framecounter))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.print_console(&amp;quot;text&amp;quot;)&amp;lt;/code&amp;gt; || print a line to the script console || &amp;lt;code&amp;gt;mxw.print_console(&amp;quot;hello&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.print_statusline(&amp;quot;text&amp;quot;)&amp;lt;/code&amp;gt; || print text on the application status line || &amp;lt;code&amp;gt;mxw.print_statusline(&amp;quot;running&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.makescreenshot(&amp;quot;path&amp;quot;)&amp;lt;/code&amp;gt; || save a full-frame screenshot as PNG (empty path &amp;amp;rarr; Desktop) || &amp;lt;code&amp;gt;mxw.makescreenshot(&amp;quot;c:/Users/me/Desktop/shot.png&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.makesectionscreenshot(&amp;quot;path&amp;quot;, x, y, w, h)&amp;lt;/code&amp;gt; || save a cropped screenshot of the region (x, y, w, h) || &amp;lt;code&amp;gt;mxw.makesectionscreenshot(&amp;quot;c:/Users/me/Desktop/crop.png&amp;quot;, 0, 0, 400, 200)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.describe()&amp;lt;/code&amp;gt; || return a text listing of every operation known to the unified interface registry (auto-docs / discovery) || &amp;lt;code&amp;gt;mxw.print_console(mxw.describe())&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; | I/O ( &amp;lt;code&amp;gt;mxw.io&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.dmx(channel)&amp;lt;/code&amp;gt; || return the DMX value received on the given channel || &amp;lt;code&amp;gt;v = mxw.io.dmx(4)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.midi(device, channel)&amp;lt;/code&amp;gt; || return the MIDI value received from device/channel || &amp;lt;code&amp;gt;v = mxw.io.midi(1, 6)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.keyboard(state, key)&amp;lt;/code&amp;gt; || return whether the given key (ASCII) is in the given state || &amp;lt;code&amp;gt;if mxw.io.keyboard(0, 65): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.send_dmx(channel, value)&amp;lt;/code&amp;gt; || send a DMX value on a channel || &amp;lt;code&amp;gt;mxw.io.send_dmx(4, 255)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.send_midi(device, channel, value)&amp;lt;/code&amp;gt; || send a MIDI value to device/channel || &amp;lt;code&amp;gt;mxw.io.send_midi(1, 6, 100)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.pjlink(&amp;quot;command&amp;quot;, &amp;quot;ip&amp;quot;, &amp;quot;pw&amp;quot;)&amp;lt;/code&amp;gt; || PJLink projector control. Commands: &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;avmute_on&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;avmute_off&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vmute_on&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vmute_off&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxw.io.pjlink(&amp;quot;on&amp;quot;, &amp;quot;192.168.1.2&amp;quot;, &amp;quot;panasonic&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.io.send_osc(&amp;quot;host&amp;quot;, port, &amp;quot;address&amp;quot;, &amp;quot;tags&amp;quot;, *args)&amp;lt;/code&amp;gt; || send an OSC message. &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt; is one char per argument: &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt; float, &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; int, &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; string, &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; blob (list of 0..255) || &amp;lt;code&amp;gt;mxw.io.send_osc(&amp;quot;127.0.0.1&amp;quot;, 7000, &amp;quot;/cue&amp;quot;, &amp;quot;ci&amp;quot;, &amp;quot;go&amp;quot;, 5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Playlist ( &amp;lt;code&amp;gt;mxw.playlist&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.preload_media()&amp;lt;/code&amp;gt; || preload the media used by the playlist || &amp;lt;code&amp;gt;mxw.playlist.preload_media()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.play()&amp;lt;/code&amp;gt; || play the playlist || &amp;lt;code&amp;gt;mxw.playlist.play()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.pause()&amp;lt;/code&amp;gt; || pause, or restart if already paused || &amp;lt;code&amp;gt;mxw.playlist.pause()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.go_pause(True/False)&amp;lt;/code&amp;gt; || halt (True) or resume (False) playback || &amp;lt;code&amp;gt;mxw.playlist.go_pause(True)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.skiptonext()&amp;lt;/code&amp;gt; || skip to the next cue || &amp;lt;code&amp;gt;mxw.playlist.skiptonext()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.go_next()&amp;lt;/code&amp;gt; || go to the next cue without playing || &amp;lt;code&amp;gt;mxw.playlist.go_next()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.go_prev()&amp;lt;/code&amp;gt; || go to the previous cue || &amp;lt;code&amp;gt;mxw.playlist.go_prev()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.go_first()&amp;lt;/code&amp;gt; || go to the first cue || &amp;lt;code&amp;gt;mxw.playlist.go_first()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.navigate_index(index)&amp;lt;/code&amp;gt; || go to the cue with the given index || &amp;lt;code&amp;gt;mxw.playlist.navigate_index(2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.navigate_string(&amp;quot;name&amp;quot;)&amp;lt;/code&amp;gt; || go to the cue matching the given name || &amp;lt;code&amp;gt;mxw.playlist.navigate_string(&amp;quot;BG_video2&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.get_active_cue()&amp;lt;/code&amp;gt; || return the active cue index (int) || &amp;lt;code&amp;gt;i = mxw.playlist.get_active_cue()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.get_cue_count()&amp;lt;/code&amp;gt; || return the number of cues (int) || &amp;lt;code&amp;gt;n = mxw.playlist.get_cue_count()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.get_cue_names()&amp;lt;/code&amp;gt; || return the list of cue names (index matches &amp;lt;code&amp;gt;navigate_index&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;for name in mxw.playlist.get_cue_names(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.playlist.is_rehearsal()&amp;lt;/code&amp;gt; || return True if the playlist is in rehearsal mode || &amp;lt;code&amp;gt;if mxw.playlist.is_rehearsal(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Preload ( &amp;lt;code&amp;gt;mxw.preload(n)&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).isvalid()&amp;lt;/code&amp;gt; || True if preload &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; exists || &amp;lt;code&amp;gt;if mxw.preload(2).isvalid(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).clear()&amp;lt;/code&amp;gt; || clear the selected preload || &amp;lt;code&amp;gt;mxw.preload(2).clear()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).set_media(&amp;quot;filename&amp;quot;)&amp;lt;/code&amp;gt; || set the preload media by filename || &amp;lt;code&amp;gt;mxw.preload(2).set_media(&amp;quot;try.mp4&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).set_name(&amp;quot;name&amp;quot;)&amp;lt;/code&amp;gt; || rename the preload || &amp;lt;code&amp;gt;mxw.preload(2).set_name(&amp;quot;new_background&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).add_preload()&amp;lt;/code&amp;gt; || load the preload into the layers || &amp;lt;code&amp;gt;mxw.preload(2).add_preload()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).trigger_preload()&amp;lt;/code&amp;gt; || trigger a layer from the preload || &amp;lt;code&amp;gt;mxw.preload(2).trigger_preload()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).get_activated()&amp;lt;/code&amp;gt; || True if the preload is open for edit || &amp;lt;code&amp;gt;mxw.preload(2).get_activated()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).set_activated(True/False)&amp;lt;/code&amp;gt; || open/close the preload for edit || &amp;lt;code&amp;gt;mxw.preload(2).set_activated(False)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).get_layer_position()&amp;lt;/code&amp;gt; || return the preload&#039;s layer index || &amp;lt;code&amp;gt;mxw.preload(2).get_layer_position()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).get_track_position()&amp;lt;/code&amp;gt; || return the preload&#039;s track index || &amp;lt;code&amp;gt;mxw.preload(2).get_track_position()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).set_layer_position(pos)&amp;lt;/code&amp;gt; || set the preload&#039;s layer index || &amp;lt;code&amp;gt;mxw.preload(2).set_layer_position(2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).set_track_position(pos)&amp;lt;/code&amp;gt; || set the preload&#039;s track index || &amp;lt;code&amp;gt;mxw.preload(2).set_track_position(2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).get_preload_names()&amp;lt;/code&amp;gt; || return the list of preload comment/name strings || &amp;lt;code&amp;gt;names = mxw.preload(2).get_preload_names()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.preload(n).get_image_sample_cvmat(w, h)&amp;lt;/code&amp;gt; || return a &amp;lt;code&amp;gt;w&amp;lt;/code&amp;gt;&amp;amp;times;&amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; RGBA image sample of the preload as a buffer (OpenCV Mat) || &amp;lt;code&amp;gt;img = mxw.preload(2).get_image_sample_cvmat(64, 64)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Widgets ( &amp;lt;code&amp;gt;mxw.widget(address)&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).getValue()&amp;lt;/code&amp;gt; || return the widget&#039;s normalized value (float) || &amp;lt;code&amp;gt;o = mxw.widget(&amp;quot;/mxw/track/active/layer/active/opacity&amp;quot;).getValue()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).setValue(v)&amp;lt;/code&amp;gt; || set the widget&#039;s normalized value || &amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/track/active/layer/active/opacity&amp;quot;).setValue(0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).getStringValue()&amp;lt;/code&amp;gt; || return the widget&#039;s string value (e.g. a cue/clip name) || &amp;lt;code&amp;gt;mxw.print_console(mxw.widget(&amp;quot;/mxw/playlist/container/1/column/0/row/1&amp;quot;).getStringValue())&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).setStringValue(&amp;quot;text&amp;quot;)&amp;lt;/code&amp;gt; || set the widget&#039;s string value (e.g. name a cue) || &amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/playlist/container/1/column/0/row/1&amp;quot;).setStringValue(&amp;quot;background videoclip&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).setWidgetRealValue(d)&amp;lt;/code&amp;gt; || set the widget&#039;s real (un-normalized) value || &amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).setWidgetRealValue(120.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).animate(initvalue, incomingvalue, duration, delta, type)&amp;lt;/code&amp;gt; || animate the widget value over &amp;lt;code&amp;gt;duration&amp;lt;/code&amp;gt; ms || &amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).animate(0.0, 1.0, 1000, 0.0, 0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.widget(&amp;quot;/mxw/path&amp;quot;).info()&amp;lt;/code&amp;gt; || return a list describing the widget. For a &#039;&#039;&#039;clip&#039;&#039;&#039;: &amp;lt;code&amp;gt;[length, width, height, millis_per_frame, cache_state, media_path]&amp;lt;/code&amp;gt;. Returns &amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt; if the address does not resolve || &amp;lt;code&amp;gt;length, w, h, mspf, cache, path = mxw.widget(&amp;quot;/mxw/track/active/layer/active/clip&amp;quot;).info()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Media ( &amp;lt;code&amp;gt;mxw.media(name)&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).isvalid()&amp;lt;/code&amp;gt; || True if the named media exists || &amp;lt;code&amp;gt;if mxw.media(&amp;quot;USB Cam&amp;quot;).isvalid(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).reference(True/False)&amp;lt;/code&amp;gt; || add (True) or remove (False) a reference that keeps the media loaded || &amp;lt;code&amp;gt;mxw.media(&amp;quot;clip.mov&amp;quot;).reference(True)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).unload_media_full_if_not_used_by_clips()&amp;lt;/code&amp;gt; || unload the media if no clip uses it (returns bool) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;clip.mov&amp;quot;).unload_media_full_if_not_used_by_clips()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).get_image_sample_cvmat(w, h)&amp;lt;/code&amp;gt; || return a &amp;lt;code&amp;gt;w&amp;lt;/code&amp;gt;&amp;amp;times;&amp;lt;code&amp;gt;h&amp;lt;/code&amp;gt; RGBA image sample of the media (OpenCV Mat) || &amp;lt;code&amp;gt;img = mxw.media(&amp;quot;clip.mov&amp;quot;).get_image_sample_cvmat(64, 64)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).get_image_sample_cvmat_async(w, h)&amp;lt;/code&amp;gt; || non-blocking variant of the image sample || &amp;lt;code&amp;gt;img = mxw.media(&amp;quot;clip.mov&amp;quot;).get_image_sample_cvmat_async(64, 64)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).get_capture_device_names()&amp;lt;/code&amp;gt; || return the list of available capture-device names || &amp;lt;code&amp;gt;devs = mxw.media(&amp;quot;&amp;quot;).get_capture_device_names()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_is_supported&amp;quot;)&amp;lt;/code&amp;gt; || return whether the (NDI) camera supports PTZ || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_is_supported&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_zoom&amp;quot;, value)&amp;lt;/code&amp;gt; || zoom, 0 (in) .. 1 (out) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_zoom&amp;quot;, 0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_zoom_speed&amp;quot;, value)&amp;lt;/code&amp;gt; || zoom speed, -1 (out) .. 1 (in) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_zoom_speed&amp;quot;, 0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_pan_tilt&amp;quot;, pan, tilt)&amp;lt;/code&amp;gt; || absolute pan/tilt, -1 .. 1 || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_pan_tilt&amp;quot;, -0.5, 0.2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_pan_tilt_speed&amp;quot;, pan_speed, tilt_speed)&amp;lt;/code&amp;gt; || pan/tilt speed, -1 (right/down) .. 1 (left/up) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_pan_tilt_speed&amp;quot;, -0.3, 0.8)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_store_preset&amp;quot;, n)&amp;lt;/code&amp;gt; || store position/focus/zoom into preset 0 .. 99 || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_store_preset&amp;quot;, 75)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_recall_preset&amp;quot;, n, speed)&amp;lt;/code&amp;gt; || recall preset 0 .. 99 at speed 0 .. 1 || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_recall_preset&amp;quot;, 4, 0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_auto_focus&amp;quot;)&amp;lt;/code&amp;gt; || toggle auto-focus || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_auto_focus&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_focus&amp;quot;, value)&amp;lt;/code&amp;gt; || absolute focus, 0 (infinity) .. 1 (closest) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_focus&amp;quot;, 0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_focus_speed&amp;quot;, value)&amp;lt;/code&amp;gt; || focus speed, -1 (out) .. 1 (in) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_focus_speed&amp;quot;, -0.2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_white_balance_auto&amp;quot;)&amp;lt;/code&amp;gt; || auto white balance || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_white_balance_auto&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_white_balance_indoor&amp;quot;)&amp;lt;/code&amp;gt; || indoor white balance || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_white_balance_indoor&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_white_balance_outdoor&amp;quot;)&amp;lt;/code&amp;gt; || outdoor white balance || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_white_balance_outdoor&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_white_balance_oneshot&amp;quot;)&amp;lt;/code&amp;gt; || set white balance once from current brightness || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_white_balance_oneshot&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_white_balance_manual&amp;quot;, red, blue)&amp;lt;/code&amp;gt; || manual white balance, 0.0 .. 1.0 each || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_white_balance_manual&amp;quot;, 0.1, 0.7)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_exposure_auto&amp;quot;)&amp;lt;/code&amp;gt; || auto exposure || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_exposure_auto&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_exposure_manual&amp;quot;, level)&amp;lt;/code&amp;gt; || manual exposure iris, 0.0 (dark) .. 1.0 (light) || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_exposure_manual&amp;quot;, 0.4)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.media(&amp;quot;name&amp;quot;).ptz(&amp;quot;ptz_exposure_manual_v2&amp;quot;, iris, gain, shutter)&amp;lt;/code&amp;gt; || manual exposure iris/gain/shutter, 0.0 .. 1.0 each || &amp;lt;code&amp;gt;mxw.media(&amp;quot;USB Cam&amp;quot;).ptz(&amp;quot;ptz_exposure_manual_v2&amp;quot;, 0.4, 0.2, 0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Grabber ( &amp;lt;code&amp;gt;mxw.grabber(name)&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.grabber(&amp;quot;name&amp;quot;).isvalid()&amp;lt;/code&amp;gt; || True if the named keystone grabber exists || &amp;lt;code&amp;gt;if mxw.grabber(&amp;quot;cam&amp;quot;).isvalid(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.grabber(&amp;quot;name&amp;quot;).getGrabSizeX()&amp;lt;/code&amp;gt; || grabber width in px || &amp;lt;code&amp;gt;mxw.grabber(&amp;quot;cam&amp;quot;).getGrabSizeX()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.grabber(&amp;quot;name&amp;quot;).getGrabSizeY()&amp;lt;/code&amp;gt; || grabber height in px || &amp;lt;code&amp;gt;mxw.grabber(&amp;quot;cam&amp;quot;).getGrabSizeY()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.grabber(&amp;quot;name&amp;quot;).getData()&amp;lt;/code&amp;gt; || return the grabber&#039;s pixels as a byte list (RGBA, width&amp;amp;times;height&amp;amp;times;4) || &amp;lt;code&amp;gt;px = mxw.grabber(&amp;quot;cam&amp;quot;).getData()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;3&amp;quot; |Audio capture ( &amp;lt;code&amp;gt;mxw.audio&amp;lt;/code&amp;gt; )&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.audio.output_capture(capacity_seconds=4.0)&amp;lt;/code&amp;gt; || open a gapless capture of the master OUTPUT mix; returns a capture handle backed by a lock-free ring (&#039;&#039;capacity_seconds&#039;&#039; of buffer) || &amp;lt;code&amp;gt;cap = mxw.audio.output_capture()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw.audio.input_capture(capacity_seconds=4.0)&amp;lt;/code&amp;gt; || open a capture of the selected audio INPUT device (same source the analyzer uses) || &amp;lt;code&amp;gt;cap = mxw.audio.input_capture()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.channels&amp;lt;/code&amp;gt; || channel count of the capture || &amp;lt;code&amp;gt;ch = cap.channels&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.sample_rate&amp;lt;/code&amp;gt; || sample rate in Hz (follows the device) || &amp;lt;code&amp;gt;sr = cap.sample_rate&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.available()&amp;lt;/code&amp;gt; || frames currently readable in the ring || &amp;lt;code&amp;gt;n = cap.available()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.read(max_frames)&amp;lt;/code&amp;gt; || read up to &#039;&#039;max_frames&#039;&#039; frames as interleaved &#039;&#039;&#039;float32&#039;&#039;&#039; bytes (length = frames&amp;amp;times;channels&amp;amp;times;4) || &amp;lt;code&amp;gt;import numpy as np; a = np.frombuffer(cap.read(cap.available()), np.float32).reshape(-1, cap.channels)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.is_closed()&amp;lt;/code&amp;gt; || True after a device reopen (rate/channel change) &amp;amp;ndash; drop and re-acquire the handle || &amp;lt;code&amp;gt;if cap.is_closed(): cap = mxw.audio.output_capture()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.close()&amp;lt;/code&amp;gt; || release the capture (idempotent) || &amp;lt;code&amp;gt;cap.close()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.dropped()&amp;lt;/code&amp;gt; || frames dropped because read() fell behind (ring overrun) || &amp;lt;code&amp;gt;cap.dropped()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;cap.starved()&amp;lt;/code&amp;gt; || times the ring was empty on read || &amp;lt;code&amp;gt;cap.starved()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
&lt;br /&gt;
* [[Python imgui reference|Python ImGui Reference]] &amp;amp;ndash; drawing plugin panels with &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[Python plugin reference|Python Plugin Howto]] &amp;amp;ndash; writing media and playlist plugins&lt;br /&gt;
[[Category:Python]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Tutorial_Opening_Different_Media&amp;diff=6209</id>
		<title>Tutorial Opening Different Media</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Tutorial_Opening_Different_Media&amp;diff=6209"/>
		<updated>2026-08-08T19:27:24Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial applies to all different OS and MXWendler versions.&lt;br /&gt;
==Supported Media Sources==&lt;br /&gt;
&lt;br /&gt;
===Video Formats===&lt;br /&gt;
&lt;br /&gt;
All the standard video formats, commonly known as container formats, such as &#039;&#039;&#039;.avi, .mov, .vob or .mpg&#039;&#039;&#039; can be used in the software. Inside these containers are media in the form of so-called codecs for video and audio. MXWendler can read and process all standard codecs, differentiating thereby between ‘internal’ and ‘external’ processing. &amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
In internal processing, media are transferred – aided by system codecs - into an own format specifically developed for real-time compositing with high-resolution video streams: the CPU in the computer is no longer required to unpack the converted media and can concentrate instead on the graphics. This method enables the 5-times forwards/backwards warping controls, excellent latency at keypoints, frame blending slow motion, and the processing of image sequences. However, to do this, the video material must first be imported. For the direct processing of video material, MXWendler uses an FFMpeg-based decoder that can play performance-optimized videos of up to 4K, and supports multi-channel audio (also via ASIO).&lt;br /&gt;
&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
===Live Video===&lt;br /&gt;
&lt;br /&gt;
MXWendler supports nearly all industry-standard grabber- and live input hardware components through Quicktime and DirectShow interfaces. Grabbers for BNC, DVI and SDI video are possible. Latency can be reduced to a minimum, down to under 0,08 seconds, by overclocking the system. Webcams and NDI can be used as live video sources as well. See also: [[Tutorial NDI Tools]].&lt;br /&gt;
&lt;br /&gt;
===Images===&lt;br /&gt;
&lt;br /&gt;
All standard image formats are supported  (&#039;&#039;&#039;.jpg, .png, .psd&#039;&#039;&#039;, etc.).&lt;br /&gt;
&lt;br /&gt;
===PDF===&lt;br /&gt;
&lt;br /&gt;
PDF files are supported in MXWendler version 6 and above and can be used as a media source. A PDF file will be played back as an image sequence. Each page of the PDF will be played as one frame. The playback speed can be changed to acquire the desired tempo of the playback. The playback of each frame can be also triggered through the Playlist function, Frame Step. &lt;br /&gt;
See also: [[Tutorial Playlists with PDF and Frame Step]] &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
==Opening Different Media==&lt;br /&gt;
&lt;br /&gt;
Different media can be opened/imported in MXWendler by:&lt;br /&gt;
:The file browser in Output Pipeline, in Preload box, or Live Editor.&lt;br /&gt;
:Drag&amp;amp;dropping from explorer to a Preload Clip, a Playlist Cell, in Live Editor, or Layer Manager.&lt;br /&gt;
:Import Multiple Clips through Preload&#039;s function Menu.&lt;br /&gt;
&lt;br /&gt;
===Opening Video &amp;amp; Image Files===&lt;br /&gt;
&lt;br /&gt;
1. Click on the first Preload. The Preload Preview opens (red box). &#039;&#039;&#039;(A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Left-click on Open to search for the desired file. &#039;&#039;&#039;(B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Select and open the file. &#039;&#039;&#039;(C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The file is now in preload and is ready for use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Tip: Alternatively, you can also drag&amp;amp;drop the file into the Preload from a file browser, or allocate media to a number of Preloads with Multi Clip Import.&#039;&#039;&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
&lt;br /&gt;
[[File:Opening different Media Trigger 1.png|728px]]&lt;br /&gt;
&lt;br /&gt;
===Opening PDF Files===&lt;br /&gt;
&lt;br /&gt;
1. Click on an empty Preload cell to open it.&lt;br /&gt;
&lt;br /&gt;
2. Left-click on Open to search for the desired PDF file.&lt;br /&gt;
&lt;br /&gt;
3. Select and open the file.&lt;br /&gt;
&lt;br /&gt;
The PDF file will be played as an image sequence frame by frame.&lt;br /&gt;
&lt;br /&gt;
4. You can change the playback speed by choosing Speed amounts from 0.0 to 5.0. &#039;&#039;&#039;(A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
5. You can change the dpi settings (for the resolution of each frame) in settings. &#039;&#039;&#039;(B)&#039;&#039;&#039;&lt;br /&gt;
:&#039;&#039;&#039;Settings &amp;amp;rarr; Media - Clips, Live, Virtual &amp;amp;rarr; PDF &#039;&#039;&#039;&lt;br /&gt;
6. In the Preload Preview, click on Reload Media to make the dpi changes effective. &#039;&#039;&#039;(C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:pdf.png|728px]]&lt;br /&gt;
&lt;br /&gt;
===Opening a Live Video===&lt;br /&gt;
&lt;br /&gt;
1. Connect the camera to the computer; you may need to restart the software.&lt;br /&gt;
&lt;br /&gt;
2. The Live-Camera must first be activated in MXWendler. &#039;&#039;&#039;(A)&#039;&#039;&#039;&lt;br /&gt;
:&#039;&#039;&#039;Settings &amp;amp;rarr; Media &amp;amp;rarr; Live devices &amp;amp;rarr; Double-click ‘unknown’ &amp;amp;rarr; ‘known’&#039;&#039;&#039;&lt;br /&gt;
:The camera can now be loaded into the Preload.&lt;br /&gt;
3. Open the next Preload. Select the camera in the preview menu under Live Media. &#039;&#039;&#039;(B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The live video is now in Preload and is ready for use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Tip: The camera only needs to be activated a single time. For improved performance, cameras can also be temporarily disabled in the same manner. Please refer to the chapter ‘Media Tips’ for more advanced camera settings.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
&lt;br /&gt;
[[File:Opening different Media Trigger 2.png|728px]]&lt;br /&gt;
&lt;br /&gt;
===Opening and Creating Image Sequences===&lt;br /&gt;
&lt;br /&gt;
Two things must be considered before the images can be loaded into the Preload:&lt;br /&gt;
&lt;br /&gt;
The images should be stored in a separate folder, and must contain sequential numbering: e.g. Clip_001.png, Clip_002.png...&lt;br /&gt;
 &lt;br /&gt;
1. Open the next Preload. &#039;&#039;&#039;(A)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Click on Open to open the folder containing the images. &#039;&#039;&#039;(B)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
3. Open the first image in the folder. Confirm with Yes to import as a sequence, and set the desired compression quality. &#039;&#039;&#039;(C)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The sequence is now in Preload and is ready for use.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Tip: Please refer to the chapter ‘Media Tips’ for the proper creation of image sequences.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Opening different Media Trigger 3.png|728px]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Main_Page&amp;diff=6208</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Main_Page&amp;diff=6208"/>
		<updated>2026-08-08T19:20:05Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= MXWendler Stage Designer and FXServer Knowledge Base =&lt;br /&gt;
MXWendler FXServer and Stage Designer serves the best video playout for Theatres, Facade Projections, Video Mapping, Architectural Lighting, Clubs, and LED Lighting. &#039;&#039;This video software places a strong emphasis on the composition and positioning of the output, because the projection is just as important as the content - no space, stage or scene is like another&#039;&#039;. It is a professional real-time video software, which works quickly, securely and robustly. The clearly laid-out interface makes it easy to use and easy to learn. The only limit is the user’s imagination.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
* [[Introduction]]&lt;br /&gt;
* [[User Interface V7|User Interface]]&lt;br /&gt;
* [[Tutorials|Try a Tutorial]]&lt;br /&gt;
* [[Triggering|Triggering Events]]&lt;br /&gt;
* [[Trouble Shooting|Troubleshoot Problems]]&lt;br /&gt;
* [[Usage Tips]]&lt;br /&gt;
* [[Performance|Performance Tips]]&lt;br /&gt;
* [[Translations]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6207</id>
		<title>Trouble Shooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6207"/>
		<updated>2026-08-08T19:17:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: Restore Aero Peek link; remove outdated &amp;#039;Windows 7 + NDI Tools&amp;#039; link (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Sometimes a driver update or a new hardware or a new operating system screws things up badly. We have collected a lot of knowledge from our test farm and our users over the years to help you across the most common pitfalls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;All OS&#039;&#039;&#039;&lt;br /&gt;
*[[Performance Problems]]&lt;br /&gt;
*[[Smooth Playback/ Frame Drops and Audio Drivers]]&lt;br /&gt;
*[[Keystone: not Opening ./skin/keystone/Video.png: file does not exist]]&lt;br /&gt;
*[[Licenser: Wrong Key Format]]&lt;br /&gt;
*[[Playlist: Crossfading Between Bright Media Becomes Temporarily Dark]]&lt;br /&gt;
*[[Capture Cards (e.g. BM Decklink Studio2)]]&lt;br /&gt;
*[[Memory Allocation Error]]&lt;br /&gt;
*[[Time and Event Sync all PCs]]&lt;br /&gt;
*[[MXW does not start any more]]&lt;br /&gt;
*[[Projector Calculator]]&lt;br /&gt;
*[[Artnet connection issues: Firewall]]&lt;br /&gt;
*[[DMX CITP and Image Sequences]]&lt;br /&gt;
*[[MAudio UC-33 to MXWendler controller programming]]&lt;br /&gt;
*[[OSC Messages - Correct Text and Value Example]]&lt;br /&gt;
*[[User Interface - outside of the main display]]&lt;br /&gt;
*[[PJLink commands for DZ21]]&lt;br /&gt;
*[[SDI Inputs - YUV Format and Wrong Color Output]]&lt;br /&gt;
*[[Vision SDI - Internal Loop/Input]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows&#039;&#039;&#039;&lt;br /&gt;
*[[Windows 11 + No Audio Device]]&lt;br /&gt;
*[[Windows 10 + Optimizing Font]]&lt;br /&gt;
*[[Windows 10 + Focusrite 18i20 Audio Issues]]&lt;br /&gt;
*[[Windows 10 + Corrupted Live Video]]&lt;br /&gt;
*[[Windows 10 + VCRUNTTIME140.dll missing]]&lt;br /&gt;
*[[Windows 10 + AJA Kona 5]]&lt;br /&gt;
*[[Windows 10 + Asus Motherboards - Multimonitoring Issues]]&lt;br /&gt;
*[[Windows 10 x64 + Stage Designer/FXServer does not start]]&lt;br /&gt;
*[[Windows 10 + Nvidia and Intel Cards]]&lt;br /&gt;
*[[Windows + Blackmagic Decklink Capture Cards]]&lt;br /&gt;
*[[Windows + Unexpected Output Window Size]]&lt;br /&gt;
*[[Windows + No Output in Output Window]]&lt;br /&gt;
*[[Windows + How to Deactivate Aero Peek to Prevent Unwanted Output Blackouts]]&lt;br /&gt;
*[[Windows 7 + AMD + Stuttering Output]]&lt;br /&gt;
*[[Windows 7 + AMD + Output Window On Wrong Screen]]&lt;br /&gt;
*[[Windows 7 + Artnet]]&lt;br /&gt;
*[[Windows 7 + No Audio]]&lt;br /&gt;
*[[Windows 7 + Configuration (config.xml)]]&lt;br /&gt;
*[[Windows 7 + Richtexteditor Glitches and ClearType]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux&#039;&#039;&#039;&lt;br /&gt;
*[[Linux and No Dongle Detection]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mac OSX&#039;&#039;&#039;&lt;br /&gt;
*[[Mac and No Default Clip]]&lt;br /&gt;
*[[Mac and No Translation]]&lt;br /&gt;
*[[Mac and No Shaders Update]]&lt;br /&gt;
*[[Mac Sierra 10.12 Disable App Translocation]]&lt;br /&gt;
*[[Macbook Pro Core 2 Duo with NVidia 9400M]]&lt;br /&gt;
*[[Mac and Graphic Card Performance]]&lt;br /&gt;
*[[Mac Yosemite 10.10 Multimonitor]]&lt;br /&gt;
*[[Mac and Internal Cached Video]]&lt;br /&gt;
*[[Mac and Audio]]&lt;br /&gt;
*[[Mac and Soundflower 64ch Audio]]&lt;br /&gt;
*[[Mac and DMX]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6206</id>
		<title>Trouble Shooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6206"/>
		<updated>2026-08-08T19:15:28Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove link to deleted page &amp;#039;Windows + How to Deactivate Aero Peek...&amp;#039; (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Sometimes a driver update or a new hardware or a new operating system screws things up badly. We have collected a lot of knowledge from our test farm and our users over the years to help you across the most common pitfalls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;All OS&#039;&#039;&#039;&lt;br /&gt;
*[[Performance Problems]]&lt;br /&gt;
*[[Smooth Playback/ Frame Drops and Audio Drivers]]&lt;br /&gt;
*[[Keystone: not Opening ./skin/keystone/Video.png: file does not exist]]&lt;br /&gt;
*[[Licenser: Wrong Key Format]]&lt;br /&gt;
*[[Playlist: Crossfading Between Bright Media Becomes Temporarily Dark]]&lt;br /&gt;
*[[Capture Cards (e.g. BM Decklink Studio2)]]&lt;br /&gt;
*[[Memory Allocation Error]]&lt;br /&gt;
*[[Time and Event Sync all PCs]]&lt;br /&gt;
*[[MXW does not start any more]]&lt;br /&gt;
*[[Projector Calculator]]&lt;br /&gt;
*[[Artnet connection issues: Firewall]]&lt;br /&gt;
*[[DMX CITP and Image Sequences]]&lt;br /&gt;
*[[MAudio UC-33 to MXWendler controller programming]]&lt;br /&gt;
*[[OSC Messages - Correct Text and Value Example]]&lt;br /&gt;
*[[User Interface - outside of the main display]]&lt;br /&gt;
*[[PJLink commands for DZ21]]&lt;br /&gt;
*[[SDI Inputs - YUV Format and Wrong Color Output]]&lt;br /&gt;
*[[Vision SDI - Internal Loop/Input]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows&#039;&#039;&#039;&lt;br /&gt;
*[[Windows 11 + No Audio Device]]&lt;br /&gt;
*[[Windows 10 + Optimizing Font]]&lt;br /&gt;
*[[Windows 10 + Focusrite 18i20 Audio Issues]]&lt;br /&gt;
*[[Windows 10 + Corrupted Live Video]]&lt;br /&gt;
*[[Windows 10 + VCRUNTTIME140.dll missing]]&lt;br /&gt;
*[[Windows 10 + AJA Kona 5]]&lt;br /&gt;
*[[Windows 10 + Asus Motherboards - Multimonitoring Issues]]&lt;br /&gt;
*[[Windows 10 x64 + Stage Designer/FXServer does not start]]&lt;br /&gt;
*[[Windows 10 + Nvidia and Intel Cards]]&lt;br /&gt;
*[[Windows + Blackmagic Decklink Capture Cards]]&lt;br /&gt;
*[[Windows + Unexpected Output Window Size]]&lt;br /&gt;
*[[Windows + No Output in Output Window]]&lt;br /&gt;
*[[Windows 7 + AMD + Stuttering Output]]&lt;br /&gt;
*[[Windows 7 + AMD + Output Window On Wrong Screen]]&lt;br /&gt;
*[[Windows 7 + Artnet]]&lt;br /&gt;
*[[Windows 7 + No Audio]]&lt;br /&gt;
*[[Windows 7 + Configuration (config.xml)]]&lt;br /&gt;
*[[Windows 7 + Richtexteditor Glitches and ClearType]]&lt;br /&gt;
*[[Windows 7 + NDI Tools]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux&#039;&#039;&#039;&lt;br /&gt;
*[[Linux and No Dongle Detection]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mac OSX&#039;&#039;&#039;&lt;br /&gt;
*[[Mac and No Default Clip]]&lt;br /&gt;
*[[Mac and No Translation]]&lt;br /&gt;
*[[Mac and No Shaders Update]]&lt;br /&gt;
*[[Mac Sierra 10.12 Disable App Translocation]]&lt;br /&gt;
*[[Macbook Pro Core 2 Duo with NVidia 9400M]]&lt;br /&gt;
*[[Mac and Graphic Card Performance]]&lt;br /&gt;
*[[Mac Yosemite 10.10 Multimonitor]]&lt;br /&gt;
*[[Mac and Internal Cached Video]]&lt;br /&gt;
*[[Mac and Audio]]&lt;br /&gt;
*[[Mac and Soundflower 64ch Audio]]&lt;br /&gt;
*[[Mac and DMX]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6205</id>
		<title>Trouble Shooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6205"/>
		<updated>2026-08-08T19:15:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove link to deleted page &amp;#039;Windows XP + No output on second screen&amp;#039; (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Sometimes a driver update or a new hardware or a new operating system screws things up badly. We have collected a lot of knowledge from our test farm and our users over the years to help you across the most common pitfalls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;All OS&#039;&#039;&#039;&lt;br /&gt;
*[[Performance Problems]]&lt;br /&gt;
*[[Smooth Playback/ Frame Drops and Audio Drivers]]&lt;br /&gt;
*[[Keystone: not Opening ./skin/keystone/Video.png: file does not exist]]&lt;br /&gt;
*[[Licenser: Wrong Key Format]]&lt;br /&gt;
*[[Playlist: Crossfading Between Bright Media Becomes Temporarily Dark]]&lt;br /&gt;
*[[Capture Cards (e.g. BM Decklink Studio2)]]&lt;br /&gt;
*[[Memory Allocation Error]]&lt;br /&gt;
*[[Time and Event Sync all PCs]]&lt;br /&gt;
*[[MXW does not start any more]]&lt;br /&gt;
*[[Projector Calculator]]&lt;br /&gt;
*[[Artnet connection issues: Firewall]]&lt;br /&gt;
*[[DMX CITP and Image Sequences]]&lt;br /&gt;
*[[MAudio UC-33 to MXWendler controller programming]]&lt;br /&gt;
*[[OSC Messages - Correct Text and Value Example]]&lt;br /&gt;
*[[User Interface - outside of the main display]]&lt;br /&gt;
*[[PJLink commands for DZ21]]&lt;br /&gt;
*[[SDI Inputs - YUV Format and Wrong Color Output]]&lt;br /&gt;
*[[Vision SDI - Internal Loop/Input]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows&#039;&#039;&#039;&lt;br /&gt;
*[[Windows 11 + No Audio Device]]&lt;br /&gt;
*[[Windows 10 + Optimizing Font]]&lt;br /&gt;
*[[Windows 10 + Focusrite 18i20 Audio Issues]]&lt;br /&gt;
*[[Windows 10 + Corrupted Live Video]]&lt;br /&gt;
*[[Windows 10 + VCRUNTTIME140.dll missing]]&lt;br /&gt;
*[[Windows 10 + AJA Kona 5]]&lt;br /&gt;
*[[Windows 10 + Asus Motherboards - Multimonitoring Issues]]&lt;br /&gt;
*[[Windows 10 x64 + Stage Designer/FXServer does not start]]&lt;br /&gt;
*[[Windows 10 + Nvidia and Intel Cards]]&lt;br /&gt;
*[[Windows + Blackmagic Decklink Capture Cards]]&lt;br /&gt;
*[[Windows + How to Deactivate Aero Peek to Prevent Unwanted Output Blackouts]]&lt;br /&gt;
*[[Windows + Unexpected Output Window Size]]&lt;br /&gt;
*[[Windows + No Output in Output Window]]&lt;br /&gt;
*[[Windows 7 + AMD + Stuttering Output]]&lt;br /&gt;
*[[Windows 7 + AMD + Output Window On Wrong Screen]]&lt;br /&gt;
*[[Windows 7 + Artnet]]&lt;br /&gt;
*[[Windows 7 + No Audio]]&lt;br /&gt;
*[[Windows 7 + Configuration (config.xml)]]&lt;br /&gt;
*[[Windows 7 + Richtexteditor Glitches and ClearType]]&lt;br /&gt;
*[[Windows 7 + NDI Tools]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux&#039;&#039;&#039;&lt;br /&gt;
*[[Linux and No Dongle Detection]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mac OSX&#039;&#039;&#039;&lt;br /&gt;
*[[Mac and No Default Clip]]&lt;br /&gt;
*[[Mac and No Translation]]&lt;br /&gt;
*[[Mac and No Shaders Update]]&lt;br /&gt;
*[[Mac Sierra 10.12 Disable App Translocation]]&lt;br /&gt;
*[[Macbook Pro Core 2 Duo with NVidia 9400M]]&lt;br /&gt;
*[[Mac and Graphic Card Performance]]&lt;br /&gt;
*[[Mac Yosemite 10.10 Multimonitor]]&lt;br /&gt;
*[[Mac and Internal Cached Video]]&lt;br /&gt;
*[[Mac and Audio]]&lt;br /&gt;
*[[Mac and Soundflower 64ch Audio]]&lt;br /&gt;
*[[Mac and DMX]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6204</id>
		<title>Trouble Shooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Trouble_Shooting&amp;diff=6204"/>
		<updated>2026-08-08T19:14:41Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove link to deleted page &amp;#039;Re-Converting Video files using AVANTI GUI&amp;#039; (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Sometimes a driver update or a new hardware or a new operating system screws things up badly. We have collected a lot of knowledge from our test farm and our users over the years to help you across the most common pitfalls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;All OS&#039;&#039;&#039;&lt;br /&gt;
*[[Performance Problems]]&lt;br /&gt;
*[[Smooth Playback/ Frame Drops and Audio Drivers]]&lt;br /&gt;
*[[Keystone: not Opening ./skin/keystone/Video.png: file does not exist]]&lt;br /&gt;
*[[Licenser: Wrong Key Format]]&lt;br /&gt;
*[[Playlist: Crossfading Between Bright Media Becomes Temporarily Dark]]&lt;br /&gt;
*[[Capture Cards (e.g. BM Decklink Studio2)]]&lt;br /&gt;
*[[Memory Allocation Error]]&lt;br /&gt;
*[[Time and Event Sync all PCs]]&lt;br /&gt;
*[[MXW does not start any more]]&lt;br /&gt;
*[[Projector Calculator]]&lt;br /&gt;
*[[Artnet connection issues: Firewall]]&lt;br /&gt;
*[[DMX CITP and Image Sequences]]&lt;br /&gt;
*[[MAudio UC-33 to MXWendler controller programming]]&lt;br /&gt;
*[[OSC Messages - Correct Text and Value Example]]&lt;br /&gt;
*[[User Interface - outside of the main display]]&lt;br /&gt;
*[[PJLink commands for DZ21]]&lt;br /&gt;
*[[SDI Inputs - YUV Format and Wrong Color Output]]&lt;br /&gt;
*[[Vision SDI - Internal Loop/Input]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Windows&#039;&#039;&#039;&lt;br /&gt;
*[[Windows 11 + No Audio Device]]&lt;br /&gt;
*[[Windows 10 + Optimizing Font]]&lt;br /&gt;
*[[Windows 10 + Focusrite 18i20 Audio Issues]]&lt;br /&gt;
*[[Windows 10 + Corrupted Live Video]]&lt;br /&gt;
*[[Windows 10 + VCRUNTTIME140.dll missing]]&lt;br /&gt;
*[[Windows 10 + AJA Kona 5]]&lt;br /&gt;
*[[Windows 10 + Asus Motherboards - Multimonitoring Issues]]&lt;br /&gt;
*[[Windows 10 x64 + Stage Designer/FXServer does not start]]&lt;br /&gt;
*[[Windows 10 + Nvidia and Intel Cards]]&lt;br /&gt;
*[[Windows + Blackmagic Decklink Capture Cards]]&lt;br /&gt;
*[[Windows + How to Deactivate Aero Peek to Prevent Unwanted Output Blackouts]]&lt;br /&gt;
*[[Windows + Unexpected Output Window Size]]&lt;br /&gt;
*[[Windows + No Output in Output Window]]&lt;br /&gt;
*[[Windows 7 + AMD + Stuttering Output]]&lt;br /&gt;
*[[Windows 7 + AMD + Output Window On Wrong Screen]]&lt;br /&gt;
*[[Windows 7 + Artnet]]&lt;br /&gt;
*[[Windows 7 + No Audio]]&lt;br /&gt;
*[[Windows 7 + Configuration (config.xml)]]&lt;br /&gt;
*[[Windows 7 + Richtexteditor Glitches and ClearType]]&lt;br /&gt;
*[[Windows 7 + NDI Tools]]&lt;br /&gt;
*[[Windows XP + No output on second screen|Windows XP + NVidia No output on second screen]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Linux&#039;&#039;&#039;&lt;br /&gt;
*[[Linux and No Dongle Detection]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mac OSX&#039;&#039;&#039;&lt;br /&gt;
*[[Mac and No Default Clip]]&lt;br /&gt;
*[[Mac and No Translation]]&lt;br /&gt;
*[[Mac and No Shaders Update]]&lt;br /&gt;
*[[Mac Sierra 10.12 Disable App Translocation]]&lt;br /&gt;
*[[Macbook Pro Core 2 Duo with NVidia 9400M]]&lt;br /&gt;
*[[Mac and Graphic Card Performance]]&lt;br /&gt;
*[[Mac Yosemite 10.10 Multimonitor]]&lt;br /&gt;
*[[Mac and Internal Cached Video]]&lt;br /&gt;
*[[Mac and Audio]]&lt;br /&gt;
*[[Mac and Soundflower 64ch Audio]]&lt;br /&gt;
*[[Mac and DMX]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6203</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6203"/>
		<updated>2026-08-08T19:13:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS.&lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[OSC Troubleshooting|Troubleshooting]] &lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6202</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6202"/>
		<updated>2026-08-08T19:12:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[OSC Troubleshooting|Troubleshooting]] &lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6201</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6201"/>
		<updated>2026-08-08T19:08:59Z</updated>

		<summary type="html">&lt;p&gt;Admin: Update link after renaming Troubleshooting -&amp;gt; OSC Troubleshooting (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[OSC Troubleshooting|Troubleshooting]] &lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Troubleshooting&amp;diff=6199</id>
		<title>OSC Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Troubleshooting&amp;diff=6199"/>
		<updated>2026-08-08T19:08:57Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page Troubleshooting to OSC Troubleshooting: Clarify: OSC-specific troubleshooting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Common issues that can arise while using OSC and MXW are generally linked to network malfunctions.&lt;br /&gt;
&lt;br /&gt;
===Network diagnostics===&lt;br /&gt;
     &lt;br /&gt;
Make sure that the system you want to control is correctly connected to the same network as the ‘master’  machine.&lt;br /&gt;
&lt;br /&gt;
==== To proof if the two machines are able to communicate in the network try to ping reciprocally the two systems: ====&lt;br /&gt;
:* For Windows users:&lt;br /&gt;
::1. Open the “Command Prompt” in the ‘master’ system as Administrator&lt;br /&gt;
::2. Type &amp;lt;code&amp;gt; ipconfig &amp;lt;/code&amp;gt; take note of the IPv4 Address&lt;br /&gt;
::3. Repeat for the ‘slave’ system&lt;br /&gt;
::4.In the ‘master’ test if the other machine is reachable by typing &amp;lt;code&amp;gt; ping &amp;lt;/code&amp;gt; followed by the IP of the ‘slave’ (e.g. &amp;lt;code&amp;gt; ping 192.168.178.7 &amp;lt;/code&amp;gt;)&lt;br /&gt;
::5. If the machine is reachable a similar message will appear:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
              Pinging 192.168.178.7 with 32 bytes of data:&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              &lt;br /&gt;
              Ping statistics for 192.168.178.7:&lt;br /&gt;
                  Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),&lt;br /&gt;
              Approximate round trip times in milli-seconds:&lt;br /&gt;
                 Minimum = 0ms, Maximum = 0ms, Average = 0ms&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
::* In case it is not reachable the message will show in the statistics&lt;br /&gt;
              Received = 0 , Lost = 4 (100% Loss) &lt;br /&gt;
::* Repeat the steps sending the ping from the ‘slave’ to the ‘master’ IP to proof the connections&lt;br /&gt;
:* For Mac OS X users:&lt;br /&gt;
::1. Press “Apple” + &amp;quot;SPACE BAR&amp;quot; and search for “Terminal”  in the ‘master’ system&lt;br /&gt;
::2. Type &amp;lt;code&amp;gt; ping &amp;lt;/code&amp;gt; followed by the IP Address of the ‘slave’  &lt;br /&gt;
::3. Proof if the ping get through&lt;br /&gt;
::4. Repeat for the ‘slave’ system pinging the IP of the ‘master’&lt;br /&gt;
              &lt;br /&gt;
==== In case of failure to connect: ==== &lt;br /&gt;
:*Verify that the firewall is not blocking the communication:&lt;br /&gt;
::* For Windows users:&lt;br /&gt;
:::1. Search for “Firewall &amp;amp; Network Protection” in the “Start” menu &lt;br /&gt;
:::2. Deactivate all three (Domain, Private and Public) firewalls by entering the respective window and switching the protection to “Off” in all of them&lt;br /&gt;
::* For Mac OS X users:&lt;br /&gt;
:::1. In the Apple menu, select “System Preferences”&lt;br /&gt;
:::2. In the System Preferences window, select “Security and Privacy”&lt;br /&gt;
:::3. In the tab “Firewall” turn off the Firewall by pressing the “Turn Off” Button (10.6 or higher) or by deselecting the checkbox “Block all incoming connections” (10.5 or lower)&lt;br /&gt;
&amp;lt;/div&amp;gt;        &lt;br /&gt;
::* In your Router settings page (see the manufacturers manual for instructions) disable AP (access point) isolation, also known as &#039;Client Isolation&#039; or &#039;Guest Mode&#039;  when active&lt;br /&gt;
&lt;br /&gt;
==== In case of occasional loss of OSC packages: ====&lt;br /&gt;
::* The maximum size of every OSC package is defined by the MTU (minimum transport unit) of the network in use. Big packages tend to get lost more easily depending on the characteristics of the network so reducing the amount of big blobs (e.g. preview requests) can lower the loss rate. See&lt;br /&gt;
::* In case of loss of small packages, verify if the packages are getting sent and their size with a package sniffer (e.g. &amp;quot;Wireshark&amp;quot;) and try different settings on your receiving console/device.&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;     &lt;br /&gt;
If none of the above solutions solves the issue try by restarting the software and reconnecting all the network chain from start.&lt;br /&gt;
&lt;br /&gt;
For further diagnostics activate the Log of received data in MXW and the dispatch of livesigns (See Points 2.2 and 2.2 d. of the Open Sound Control References) to test the receiving and sending functionality on the wished OSC console, Pd patch or the Protokol App for a mobile option (see point 4.).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6198</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6198"/>
		<updated>2026-08-08T19:04:34Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove index numbering from OSC contents (links + sub-items) (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[Troubleshooting]] &lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Troubleshooting&amp;diff=6196</id>
		<title>OSC Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Troubleshooting&amp;diff=6196"/>
		<updated>2026-08-08T19:04:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 5. Troubleshooting to Troubleshooting: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Common issues that can arise while using OSC and MXW are generally linked to network malfunctions.&lt;br /&gt;
&lt;br /&gt;
===Network diagnostics===&lt;br /&gt;
     &lt;br /&gt;
Make sure that the system you want to control is correctly connected to the same network as the ‘master’  machine.&lt;br /&gt;
&lt;br /&gt;
==== To proof if the two machines are able to communicate in the network try to ping reciprocally the two systems: ====&lt;br /&gt;
:* For Windows users:&lt;br /&gt;
::1. Open the “Command Prompt” in the ‘master’ system as Administrator&lt;br /&gt;
::2. Type &amp;lt;code&amp;gt; ipconfig &amp;lt;/code&amp;gt; take note of the IPv4 Address&lt;br /&gt;
::3. Repeat for the ‘slave’ system&lt;br /&gt;
::4.In the ‘master’ test if the other machine is reachable by typing &amp;lt;code&amp;gt; ping &amp;lt;/code&amp;gt; followed by the IP of the ‘slave’ (e.g. &amp;lt;code&amp;gt; ping 192.168.178.7 &amp;lt;/code&amp;gt;)&lt;br /&gt;
::5. If the machine is reachable a similar message will appear:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
              Pinging 192.168.178.7 with 32 bytes of data:&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              Reply from 192.168.178.7: bytes=32 time&amp;lt;1ms TTL=64&lt;br /&gt;
              &lt;br /&gt;
              Ping statistics for 192.168.178.7:&lt;br /&gt;
                  Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),&lt;br /&gt;
              Approximate round trip times in milli-seconds:&lt;br /&gt;
                 Minimum = 0ms, Maximum = 0ms, Average = 0ms&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
::* In case it is not reachable the message will show in the statistics&lt;br /&gt;
              Received = 0 , Lost = 4 (100% Loss) &lt;br /&gt;
::* Repeat the steps sending the ping from the ‘slave’ to the ‘master’ IP to proof the connections&lt;br /&gt;
:* For Mac OS X users:&lt;br /&gt;
::1. Press “Apple” + &amp;quot;SPACE BAR&amp;quot; and search for “Terminal”  in the ‘master’ system&lt;br /&gt;
::2. Type &amp;lt;code&amp;gt; ping &amp;lt;/code&amp;gt; followed by the IP Address of the ‘slave’  &lt;br /&gt;
::3. Proof if the ping get through&lt;br /&gt;
::4. Repeat for the ‘slave’ system pinging the IP of the ‘master’&lt;br /&gt;
              &lt;br /&gt;
==== In case of failure to connect: ==== &lt;br /&gt;
:*Verify that the firewall is not blocking the communication:&lt;br /&gt;
::* For Windows users:&lt;br /&gt;
:::1. Search for “Firewall &amp;amp; Network Protection” in the “Start” menu &lt;br /&gt;
:::2. Deactivate all three (Domain, Private and Public) firewalls by entering the respective window and switching the protection to “Off” in all of them&lt;br /&gt;
::* For Mac OS X users:&lt;br /&gt;
:::1. In the Apple menu, select “System Preferences”&lt;br /&gt;
:::2. In the System Preferences window, select “Security and Privacy”&lt;br /&gt;
:::3. In the tab “Firewall” turn off the Firewall by pressing the “Turn Off” Button (10.6 or higher) or by deselecting the checkbox “Block all incoming connections” (10.5 or lower)&lt;br /&gt;
&amp;lt;/div&amp;gt;        &lt;br /&gt;
::* In your Router settings page (see the manufacturers manual for instructions) disable AP (access point) isolation, also known as &#039;Client Isolation&#039; or &#039;Guest Mode&#039;  when active&lt;br /&gt;
&lt;br /&gt;
==== In case of occasional loss of OSC packages: ====&lt;br /&gt;
::* The maximum size of every OSC package is defined by the MTU (minimum transport unit) of the network in use. Big packages tend to get lost more easily depending on the characteristics of the network so reducing the amount of big blobs (e.g. preview requests) can lower the loss rate. See&lt;br /&gt;
::* In case of loss of small packages, verify if the packages are getting sent and their size with a package sniffer (e.g. &amp;quot;Wireshark&amp;quot;) and try different settings on your receiving console/device.&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;     &lt;br /&gt;
If none of the above solutions solves the issue try by restarting the software and reconnecting all the network chain from start.&lt;br /&gt;
&lt;br /&gt;
For further diagnostics activate the Log of received data in MXW and the dispatch of livesigns (See Points 2.2 and 2.2 d. of the Open Sound Control References) to test the receiving and sending functionality on the wished OSC console, Pd patch or the Protokol App for a mobile option (see point 4.).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=MXW_OSC_command_structure&amp;diff=6194</id>
		<title>MXW OSC command structure</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=MXW_OSC_command_structure&amp;diff=6194"/>
		<updated>2026-08-08T19:04:13Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 2. MXW OSC command structure to MXW OSC command structure: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
View source for 2. MXW OSC command structure&lt;br /&gt;
← 2. MXW OSC command structure&lt;br /&gt;
Jump to navigationJump to search&lt;br /&gt;
You do not have permission to edit this page, for the following reason:&lt;br /&gt;
&lt;br /&gt;
The action you have requested is limited to users in the group: Users.&lt;br /&gt;
&lt;br /&gt;
You can view and copy the source of this page.&lt;br /&gt;
&lt;br /&gt;
Commands to the MXW OSC interface always follow the same syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/&amp;lt;address of widget&amp;gt; [MSGID] &amp;lt;float|integer|string&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
for example: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/1 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
or:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set play patch1&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
or:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/playlist MSGID0001 info&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commands always begin with /mxw/ and it is followed by the address of the receiver and an argument that can be a numeric value, a string, or a combination of both.&lt;br /&gt;
The only optional element is the “Message-ID”.&lt;br /&gt;
&lt;br /&gt;
== 2.1 Sending OSC Values ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The command receivers listen to a value that is either a float or an integer (if they are widgets), or to strings (e.g. to choose patches or clips). &lt;br /&gt;
==== Faders ====&lt;br /&gt;
Receivers in MXW connected to faders in the user interface are responding to Float values. Floats are always in the range of 0.0 to 1.0 and will be scaled to the actual range of the recalled widget. &amp;lt;br&amp;gt;&lt;br /&gt;
For instance, the speed fader has a range in MXW that goes between -5 and 5 and its active range is dependent on the type of played media. &amp;lt;br&amp;gt; If a float value like 0.6 is sent to the OSC address of the clip speed, the fader moves to the value 1.0  (original speed of the clip).&lt;br /&gt;
&lt;br /&gt;
==== Buttons and Checkboxes ====&lt;br /&gt;
Widgets in MXW that have an &#039;&#039;&#039;ON/OFF&#039;&#039;&#039; state accept integers as values. Buttons have the functions Press and Release assigned respectively to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; and checkboxes have assigned ON and OFF respectively to &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;. &amp;lt;/br&amp;gt; This means that if one wants to send a button press, e.g. a &amp;quot;play&amp;quot; button press, a value &amp;quot;0&amp;quot; has to be sent (to send a command, like with a mouse-click, a button must be pressed &amp;lt;u&amp;gt;and released&amp;lt;/u&amp;gt; after)&lt;br /&gt;
&lt;br /&gt;
==== Drop-down Boxes and Combo Boxes ====&lt;br /&gt;
Drop-down lists and Combo Boxes are indexed with integers ranging between &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; and the maximum number of elements. For example to select the third element of a list the integer &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; will be sent to the address of the Combo Box.&lt;br /&gt;
&lt;br /&gt;
=== String Tokens ===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Specific string tokens can also be sent to the command receivers and they can respectively activate specific functions paired with a numeric value or another string. The usable strings are &amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;preview&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt;.&lt;br /&gt;
==== play ====  &lt;br /&gt;
The string play can be sent together with another string containing the name of a saved patch in the address &amp;lt;code&amp;gt;/mxw/set &amp;lt;/code&amp;gt; to start the playback of the recalled patch.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set play patch1&amp;lt;/code&amp;gt;.&lt;br /&gt;
==== info ====&lt;br /&gt;
The string variable info can be sent to a specific address to acquire information about one field or clip through a reply sent by MXW.&lt;br /&gt;
The reply  bundle coming from MXW will also be sent through OSC and will have this format:&lt;br /&gt;
&lt;br /&gt;
* A reply header composed by:&lt;br /&gt;
&lt;br /&gt;
1. Message &amp;lt;code&amp;gt;mxw/reply&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
2. &amp;lt;code&amp;gt;MSGID&amp;lt;/code&amp;gt; (if specified in the info request)&amp;lt;br&amp;gt;&lt;br /&gt;
3. Address pattern of the request&amp;lt;br&amp;gt;&lt;br /&gt;
4. Time as a long variable&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The actual &#039;&#039;&#039;reply content&#039;&#039;&#039; following this table:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! ADDRESS !! REPLY CONTENT&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist info &amp;lt;/code&amp;gt;|| 1. State of the playback (&amp;lt;code&amp;gt;play&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;paused&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stopped&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/container/active info &amp;lt;/code&amp;gt;|| 1. Active container index &amp;lt;br&amp;gt; 2. Number of columns &amp;lt;br&amp;gt; 3. Number of rows &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/playlist/container/active/column/1/row/1 info &amp;lt;/code&amp;gt;|| 1. Label of media in the container in column 1, row 1&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip info &amp;lt;/code&amp;gt;||  1. Length of media &amp;lt;br&amp;gt; 2. Width &amp;lt;br&amp;gt;3. Height&amp;lt;br&amp;gt;4. ms per frame&amp;lt;br&amp;gt; 5. Completition of cache (&amp;lt;code&amp;gt;cachecomplete&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;cachenotcomplete&amp;lt;/code&amp;gt;)&amp;lt;br&amp;gt; 6. Path directory of the active clip&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/preload/1 info &amp;lt;/code&amp;gt;|| 1. Length of media &amp;lt;br&amp;gt; 2. Width &amp;lt;br&amp;gt;3. Height&amp;lt;br&amp;gt;4. ms per frame&amp;lt;br&amp;gt; 5. Completition of cache (&amp;lt;code&amp;gt;cachecomplete&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;cachenotcomplete&amp;lt;/code&amp;gt;)&amp;lt;br&amp;gt; 6. Path directory of the media of the first preload&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/keystone info &amp;lt;/code&amp;gt;||  1. Active keystone element index &amp;lt;br&amp;gt; 2. Name of active keystone element&amp;lt;br&amp;gt; 3. Amount of total keystone elements &amp;lt;br&amp;gt; 4. Names of  keystone elements separated by commas &amp;lt;br&amp;gt; 5. Active softedge index &amp;lt;br&amp;gt; 6. Name of active softedge &amp;lt;br&amp;gt; 7. Amount of total softedges &amp;lt;br&amp;gt; 8. Names of softedges separated by commas &amp;lt;br&amp;gt; 9. Active grabber element index &amp;lt;br&amp;gt; 10. Name of active grabber element&amp;lt;br&amp;gt; 11. Amount of total grabber elements &amp;lt;br&amp;gt; 12. Names of  grabber elements separated by commas &amp;lt;br&amp;gt; 13. Active blacklevel element index &amp;lt;br&amp;gt; 14. Name of active blacklevel element&amp;lt;br&amp;gt; 15. Amount of total blacklevel elements &amp;lt;br&amp;gt; 16. Names of  blacklevel elements separated by commas&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/keystone/element/1 info &amp;lt;/code&amp;gt;|| 1. Element name &amp;lt;br&amp;gt; 2. Element type &amp;lt;br&amp;gt; 3. Video track number &amp;lt;br&amp;gt; 4. Video layer number &amp;lt;br&amp;gt; 5. Precision &amp;lt;br&amp;gt; 6. Number of pivots x &amp;lt;br&amp;gt;  7. Number of pivots y &amp;lt;br&amp;gt; 8. Scale &amp;lt;br&amp;gt; 9. Opacity &amp;lt;br&amp;gt; 10. Rotation of element number 1&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone/element/1/pivot/col/1/row/1 info &amp;lt;/code&amp;gt;|| 1. Pivot translation x &amp;lt;br&amp;gt; 2. Translation y  &amp;lt;br&amp;gt; 3. Translation z &amp;lt;br&amp;gt; 4. UV value x  &amp;lt;br&amp;gt; 5. UV values y &amp;lt;br&amp;gt; 6. UV normalized x  &amp;lt;br&amp;gt; 7. UV normalized y &amp;lt;br&amp;gt; 8. RGB COLOUR&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/layermanager info&amp;lt;/code&amp;gt;|| 1. Active layer index &amp;lt;br&amp;gt; 2. Name of active layer  &amp;lt;br&amp;gt; 3. Amount of total layers &amp;lt;br&amp;gt; 4. Names of layers separated by commas&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/set info&amp;lt;/code&amp;gt; || 1. Active patch index &amp;lt;br&amp;gt; 2. Name of active patch &amp;lt;br&amp;gt; 3. Amount of total patches &amp;lt;br&amp;gt; 4. Names of patches separated by commas&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mxw/trackmanager info&amp;lt;/code&amp;gt;||  1. Active track index &amp;lt;br&amp;gt; 2. Name of active track&amp;lt;br&amp;gt; 3. Amount of total tracks &amp;lt;br&amp;gt; 4. Names of tracks separated by commas&lt;br /&gt;
|-&lt;br /&gt;
| Addresses of Drop-down Boxes and Combo Boxes in MXW &amp;lt;br&amp;gt;(e.g.  &amp;lt;code&amp;gt;mxw/render/effect info&amp;lt;/code&amp;gt;)|| 1. Index and Name of currently selected item &amp;lt;br&amp;gt; 2. Amount of total items &amp;lt;br&amp;gt; 3. Names of items separated by commas&lt;br /&gt;
|-&lt;br /&gt;
| Addresses of Faders in MXW &amp;lt;br&amp;gt;(e.g. &amp;lt;code&amp;gt;mxw/render/opacity info&amp;lt;/code&amp;gt; )|| 1. Value of position of fader (&amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| Addresses of Buttons/Checkboxes in MXW &amp;lt;br&amp;gt;(e.g. &amp;lt;code&amp;gt;mxw/track/1/crossfade info&amp;lt;/code&amp;gt;)|| 1. State of the widget (&amp;lt;code&amp;gt;0 = released/OFF , 1 = pressed/ON&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;2&amp;quot; | NOTE: The token &amp;lt;code&amp;gt;active&amp;lt;/code&amp;gt; can be substituted with an integer corresponding to the index of the wished element&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As an example, if we send:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/playlist/container/active info&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MXWendler will reply:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mxw/reply /mxw/playlist/container/active &amp;amp;emsp;&amp;amp;emsp;&amp;amp;emsp;&amp;amp;emsp;&amp;amp;emsp; 980451 &amp;amp;emsp;&amp;amp;emsp;&amp;amp;emsp;0 &amp;amp;emsp;&amp;amp;emsp;&amp;amp;emsp;&amp;amp;ensp;3 &amp;amp;emsp;&amp;amp;emsp; &amp;amp;emsp; 20&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
 Reply Message    Address of Request           Time    Index  Col.   Row&lt;br /&gt;
&lt;br /&gt;
====select====&lt;br /&gt;
The token select can be added to different addresses to select the single elements on a list of many using a string. This command is can be used in combination with the token &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; as the names of the elements can be recalled with &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; first and then selected with the &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; token. &lt;br /&gt;
The receivers that respond with the token select are:&lt;br /&gt;
* trackmanager&lt;br /&gt;
* layermanager&lt;br /&gt;
* combo-boxes&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/trackmanager select track2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====active====&lt;br /&gt;
The token active is used in the receiver address and can be used in multiple situations to act on the selected element of a list. For example the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/active/fader 0.5&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will move the fader of the selected (active) track to his middle position, setting its opacity to 50%.&lt;br /&gt;
&lt;br /&gt;
====preview====&lt;br /&gt;
The string preview can be used to get in return an OSC blob, containing a 128x128px &#039;&#039;&#039;jpg&#039;&#039;&#039; file that is a preview of the currently played media or a thumbnail of the selected clip. Here are the available addresses for a preview:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME !! ADDRESS&lt;br /&gt;
|-&lt;br /&gt;
| Render || &amp;lt;code&amp;gt;/mxw/render preview&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Track || &amp;lt;code&amp;gt;/mxw/track/active preview&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Layer || &amp;lt;code&amp;gt;/mxw/track/active/layer/active preview&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Clip || &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip preview&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Preload || &amp;lt;code&amp;gt;/mxw/preload/&amp;quot;preload index&amp;quot; preview&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;/mxw/preload/7 preview&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| Patch/Set || &amp;lt;code&amp;gt;/mxw/patch/&amp;quot;patch index&amp;quot; preview&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; E.G.&amp;lt;code&amp;gt;/mxw/patch/3 preview&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;2&amp;quot; | NOTE: The token &amp;lt;code&amp;gt;active&amp;lt;/code&amp;gt; can be substituted with an integer corresponding to the index of the wished element&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====clear====&lt;br /&gt;
&lt;br /&gt;
The function clear can be sent to the preloads to empty one of the preload spaces.&lt;br /&gt;
&lt;br /&gt;
E.G. &amp;lt;code&amp;gt;mxw/preload/1 clear&amp;lt;/code&amp;gt; will clear the first preload slot.&lt;br /&gt;
&lt;br /&gt;
=== Message-ID ===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The “Message-ID”  allows for clear communication and categorization of replies. When a command that generates a reply is sent, it is possible to prepend the command with a  “Message-ID” which will be then in the reply as well. This message must have the format &amp;lt;code&amp;gt; MSGIDXXXX &amp;lt;/code&amp;gt; and it must follow the OSC address like in the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/3 MSGID0123 info&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return a reply similar to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/reply MSGID0123 /mxw/preload/3 112 320 240 40 cachecomplete c:\footage\clip.avi&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2.2 Examples ==&lt;br /&gt;
To address the main fader and fade the opacity of the render from zero to full in ten steps, you would send a command sequence:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.0&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.1&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.2&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.3&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.4&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.6&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.7&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.8&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 0.9&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/render 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finer-grained values can be sent if needed. The commands will be evaluated as soon as they arrive in MXW and the last command before a new frame is drawn will set the widget&#039;s value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/active 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Sets the active track opacity to 0.5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/1 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Sets track 1 opacity to 0.5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/1/trigger 1.0&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Adds a layer with the contents of preload slot 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/1/layer/1/opacity 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Sets the opacity of the first layer of the first track to 0.5 (if there is a layer playing content)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set 5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;The active track will load patch 5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/speed 0.6&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Sets the speed of the clip of the active layer of the active track to 1.0 (0.6 translates to 1.0 in a -5 .. +5 range)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/speed 0.5&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Sets the speed of the clip of the active layer of the active track to 0.5 (clip stops)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/trackmanager 1&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Activate the first track&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/trackmanager 3&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Activate the third track&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/trackmanager select track3&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Activate the third track&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/2/layer/1/clip/effect/2 select ag_AnimWarp&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Instructs the clip of the first layer of the second track to load the effect with the name &amp;quot;ag_AnimWarp&amp;quot; in the effect slot number 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/2/layer/1/clip/effect/1/param/1 0.8&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Set to the value of 0.8, the parameter 1 of the first effect of the clip of the first layer of the second track &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/2 c:/footage/clip.avi&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Preload slot 2 will load c:/footage/clip.avi (and answer with info). Note the direction of the slashes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/2 clear&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Preload slot 2 will unload&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/2 info&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Preload 2 will answer with clip info like  &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/reply /mxw/preload/3 112 320 240 40 cachecomplete &lt;br /&gt;
c:\footage\clip.avi&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/preload/2 MSGID0123 info&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Preload 2 will answer with clip info like &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/reply MSGID0123 /mxw/preload/3 112 320 240 40 cachecomplete c:\footage\clip.avi&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/master/load_showfile c:/footage/showfile.mxw&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Load the stated showfile&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/master/load_keystonefile c:/footage/keystonefile.mxw_keystone2&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;Load the stated keystonefile&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_OSC&amp;diff=6192</id>
		<title>Controlling MXW through OSC</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_OSC&amp;diff=6192"/>
		<updated>2026-08-08T19:04:11Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 1. Controlling MXW through OSC to Controlling MXW through OSC: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
MXW is designed to be a high-performance real-time video software for media servers. It interactively composites high-resolution footage and interactive media.&lt;br /&gt;
OSC commands can be generated, sent, and received by MXWendler and a wide range of applications: signaling frameworks like Pure Data, Max/MSP,  TouchOSC, and TouchDesigner, audio workstations like Ableton Live, Logic, or Protools,  programming environments like Processing, Perl, Java, Unity, and TidalCycles, other Multimedia, Sensoring, Signal Processing software, Microcontrollers and many more, offering a compatible and fast intercommunication method. &lt;br /&gt;
&lt;br /&gt;
Separating the media server from the controlling infrastructure offers various creative and usability options: &lt;br /&gt;
&lt;br /&gt;
*Control multiple machines from one single point&lt;br /&gt;
*Control a single machine from multiple points&lt;br /&gt;
*Replicate a state into a remote system&lt;br /&gt;
*Custom user interfaces&lt;br /&gt;
*Intercommunication with external software and platforms&lt;br /&gt;
*Control via WAN&lt;br /&gt;
*Control via a microcontroller&lt;br /&gt;
*Connect scene-analysis with scene-composition systems&lt;br /&gt;
*Extract control features e.g mapping or triggering&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
== 1.1 Receiving OSC commands in MXW ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To enable OSC receiving open the software MXWendler: &amp;lt;br&amp;gt;&lt;br /&gt;
1. In  &#039;&#039;&#039;Menu: Settings &amp;amp;rarr; Input and Output &#039;&#039;(CTRL+1)&#039;&#039; &amp;amp;rarr;&#039;&#039;&#039; in the tab  &#039;&#039;&#039;OSC&#039;&#039;&#039;,  activate the box &#039;&#039;&#039;Receive OSC&#039;&#039;&#039; ( &#039;&#039;&#039;(A)&#039;&#039;&#039; In the following picture) &amp;lt;br&amp;gt;&lt;br /&gt;
2. Set the port ( 7000 is recommended as an OSC Standard)  &amp;lt;br&amp;gt;&lt;br /&gt;
3. The box &#039;&#039;&#039;Log received data&#039;&#039;&#039; will log commands in the Error and Log Window visible through &#039;&#039;&#039;Menu: Settings &amp;amp;rarr; Error and Log Window &#039;&#039;(CTRL+SHFT+L)&#039;&#039; &#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful for testing and troubleshooting as it will make visible what OSC commands are received by MXW. The logging of data has a performance impact on the system so it is important to turn it off when not in use.&lt;br /&gt;
As this option is marked (r) in the menu, to activate the changes, please restart the software.&lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1.2 Output OSC from MXW: Send vs. Reply ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
MXW can send OSC commands as well. Multiple distinct options are available in &#039;&#039;&#039;Menu: Settings &amp;amp;rarr; Input and Output &#039;&#039;(CTRL+1)&#039;&#039; &amp;amp;rarr;&#039;&#039;&#039; tab &#039;&#039;&#039;OSC&#039;&#039;&#039; : &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:mxwIO.png|728px]]&lt;br /&gt;
&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
&lt;br /&gt;
=== Broadcast and Receive Time over OSC &#039;&#039;&#039;(B)&#039;&#039;&#039; === &lt;br /&gt;
This option will broadcast the MXW time into the selected subnet to synchronize the time among a pool of machines.&lt;br /&gt;
To achieve this a selection mechanism is applied: every machine sends its time until it receives the time from a machine with a lower IP address. In the end, the machine with the lowest IP is selected as the &#039;master&#039; and controls the pool clock.&lt;br /&gt;
IO Events can be forwarded by selecting the relative checkbox. You can for example connect a MIDI device and it will send the MIDI events to the pool.&lt;br /&gt;
&lt;br /&gt;
=== Receive OSC over RS232 &#039;&#039;&#039;(C)&#039;&#039;&#039; ===&lt;br /&gt;
Check this box if the OSC commands are received through a Serial Port instead of a network port. Options for port selection and integer indexing are available.&lt;br /&gt;
&lt;br /&gt;
=== Send OSC &#039;&#039;&#039;(D)&#039;&#039;&#039; ===&lt;br /&gt;
This option will send any action on the running host to another host/network defined in the command options. Moving a track slider will generate the commands that make the track slider in the remote machine move to the same position. The goal is to make another machine (pretended it carries the same media data) produce exactly the same result as the master machine by sending osc commands to replicate the same behaviour.&lt;br /&gt;
Sometimes it is desireable to send only a selction of the generated actions. You can filter the sent commands using the following rules:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
- Adding a + before a *token*, [comment(optional)]&amp;lt;br&amp;gt;&lt;br /&gt;
- Adding a - before a token*, [comment(optional)]&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The *token* is a part of the string like &amp;quot;playlist&amp;quot; or &amp;quot;opacity&amp;quot;, a comment can be added after a comma in case we want to specify the reason of the filter. So adding the line &amp;lt;code&amp;gt;+,*playlist*&amp;lt;/code&amp;gt;  will result into that only commands containing the keyword &amp;quot;playlist&amp;quot; will be sent. In the same way using the filter &amp;lt;code&amp;gt;-,*opacity*, opacity_does_not_change&amp;lt;/code&amp;gt; any command referring to &amp;quot;opacity&amp;quot; will not be sent through and everything else will.&lt;br /&gt;
&lt;br /&gt;
=== OSC reply channel &#039;&#039;&#039;(E)&#039;&#039;&#039; ===&lt;br /&gt;
Many OSC commands are capable of asking for specific information e.g. the name of a clip in the preload or the playback status of the playlist. This option must be active in MXW to allow the software to reply to the received OSC commands.  Options for a specific IP address of the host/subnet and Port are given in the settings.  The last checkbox “Send periodical livesigns” allows to receive a constant periodical flow of data from MXW regarding performance and render information, useful as well for diagnostic reasons.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6191</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6191"/>
		<updated>2026-08-08T19:02:08Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove useless &amp;#039;6. External links&amp;#039; entry from contents (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[1. Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;1.1 Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;1.2 Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[2. MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.1 Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.2 Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[5. Troubleshooting]] &lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6190</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6190"/>
		<updated>2026-08-08T19:00:26Z</updated>

		<summary type="html">&lt;p&gt;Admin: Remove outdated &amp;#039;Practical examples: Pure Data and TouchOSC&amp;#039; entry from contents (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[1. Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;1.1 Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;1.2 Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[2. MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.1 Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.2 Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[5. Troubleshooting]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[6. External links]]&lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Python_Reference&amp;diff=6189</id>
		<title>Python Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Python_Reference&amp;diff=6189"/>
		<updated>2026-08-08T18:58:04Z</updated>

		<summary type="html">&lt;p&gt;Admin: Point TOC to de-numbered &amp;#039;Controlling MXW through Python&amp;#039;; drop index prefixes (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This document describes the MXWendler (MXW) Python command interface through an overview of the programming structure, with practical examples of automation and internal scripting. The presented Python commands are for most part supported in version 7.2.&lt;br /&gt;
&lt;br /&gt;
== What is Python? ==&lt;br /&gt;
Python is a standardized interpreted, high level programming language. It is used in many applications, mainly in AI and generative tasks. The amount of available libraries is outstanding.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Controlling MXW through Python]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Python command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Python imgui reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Python plugin reference]] &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
[[Category:Python]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_Python&amp;diff=6187</id>
		<title>Controlling MXW through Python</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_Python&amp;diff=6187"/>
		<updated>2026-08-08T18:58:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 1. Controlling MXW through Python to Controlling MXW through Python: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MXWendler wiki page: Controlling MXW through Python (overview / hub) --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Intended location: https://wiki.mxwendler.net/index.php?title=1._Controlling_MXW_through_Python --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_command_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_imgui_reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_plugin_reference --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
MXWendler StageDesigner embeds &#039;&#039;&#039;Python 3.12&#039;&#039;&#039;. Python is used in two ways:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Command interface / scripting&#039;&#039;&#039; &amp;amp;ndash; the module &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt; controls the running software (playlist, layers, clips, media, I/O, widgets by their address, ...) from the script console or from within a plugin.&lt;br /&gt;
* &#039;&#039;&#039;Plugins&#039;&#039;&#039; &amp;amp;ndash; self-contained folders that add a media source or a playlist item and are called back by the host through a defined set of functions (&#039;&#039;hooks&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The presented Python interface is supported in version 7.2. and up&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Where to go ==&lt;br /&gt;
&lt;br /&gt;
The detailed documentation lives on three dedicated pages; this page only points to them so nothing is documented twice.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Topic !! Page&lt;br /&gt;
|-&lt;br /&gt;
| The &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt; command interface &amp;amp;ndash; software info, &amp;lt;code&amp;gt;playlist&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;io&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;widget(address)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;media(name)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;preload(n)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;grabber(name)&amp;lt;/code&amp;gt; || [[Python command reference|Python command reference]]&lt;br /&gt;
|-&lt;br /&gt;
| Drawing plugin settings panels with &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt; (MXWendler&#039;s Dear ImGui binding) || [[Python imgui reference|Python ImGui reference]]&lt;br /&gt;
|-&lt;br /&gt;
| Writing &#039;&#039;&#039;plugins&#039;&#039;&#039; &amp;amp;ndash; media and playlist &amp;amp;ndash; the manifest (&amp;lt;code&amp;gt;mxw_plugin.ini&amp;lt;/code&amp;gt;), the hooks, per-instance state, examples || [[Python plugin reference|Python plugin reference]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Quick start ==&lt;br /&gt;
&lt;br /&gt;
A minimal look at each entry point; follow the links above for the full reference.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scripting.&#039;&#039;&#039; From the script console (or any hook), the &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt; module reaches the software:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Python&amp;quot; line&amp;gt;&lt;br /&gt;
import mxw&lt;br /&gt;
mxw.print_console(&amp;quot;frame &amp;quot; + str(mxw.framecounter))&lt;br /&gt;
mxw.playlist.play()&lt;br /&gt;
mxw.widget(&amp;quot;/mxw/track/active/layer/active/opacity&amp;quot;).setValue(0.5)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Plugins.&#039;&#039;&#039; A plugin is a folder holding a manifest and a Python module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
plugins/playlist/python/plugin_my_item/&lt;br /&gt;
    mxw_plugin.ini      the manifest: identity, menu entries&lt;br /&gt;
    mxw_main.py         the Python module with the hook functions&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The host discovers it at startup, shows it in the user interface and calls its hooks at the right moments. See the [[Python plugin reference|Python plugin reference]] for the manifest fields, the full hook list for media and playlist plugins, plugin locations, installing extra packages with &amp;lt;code&amp;gt;mxw-pip&amp;lt;/code&amp;gt;, and complete examples.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Python command reference|Python command reference]] &amp;amp;ndash; the &amp;lt;code&amp;gt;mxw&amp;lt;/code&amp;gt; module&lt;br /&gt;
* [[Python imgui reference|Python ImGui reference]] &amp;amp;ndash; drawing plugin panels with &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[Python plugin reference|Python plugin reference]] &amp;amp;ndash; writing media and playlist plugins&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=JavaScript_Reference&amp;diff=6186</id>
		<title>JavaScript Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=JavaScript_Reference&amp;diff=6186"/>
		<updated>2026-08-08T18:51:36Z</updated>

		<summary type="html">&lt;p&gt;Admin: Point TOC to de-numbered page titles; drop index prefixes (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above.&lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) JavaScript Command Interface through an overview of the programming structure, with practical examples of automation and internal scripting.&lt;br /&gt;
&lt;br /&gt;
== What is JavaScript? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
JavaScript is a standardized interpreted, high level programming language. It is one of the core technologies of the World Wide Web and it is mainly used in web browsers to control web pages and test the user input before sending it.&lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/JavaScript[1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Controlling MXW through JavaScript]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[JavaScript command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Practical examples]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[Troubleshooting scripts]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[External Resources]]&lt;br /&gt;
|}&lt;br /&gt;
[[Category:JavaScript]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=External_Resources&amp;diff=6184</id>
		<title>External Resources</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=External_Resources&amp;diff=6184"/>
		<updated>2026-08-08T18:51:22Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 6. External Resources to External Resources: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
1 https://en.wikipedia.org/wiki/JavaScript&amp;lt;/br&amp;gt;&lt;br /&gt;
2 https://developer.mozilla.org/en-US/docs/Web/JavaScript &amp;lt;/br&amp;gt;&lt;br /&gt;
3 https://curlie.org/Computers/Programming/Languages/JavaScript/ &amp;lt;/br&amp;gt;&lt;br /&gt;
4 https://duktape.org/index.html &amp;lt;/br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Troubleshooting_scripts&amp;diff=6182</id>
		<title>Troubleshooting scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Troubleshooting_scripts&amp;diff=6182"/>
		<updated>2026-08-08T18:51:21Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 5. Troubleshooting scripts to Troubleshooting scripts: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&#039;&#039;&#039;Problem&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
JavaScript is not functioning as intended. No corresponding action happens when the trigger button for the event is pressed. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hints&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Open the JavaScript console by pressing Ctrl+Shift+J (Mac:Command+Shift+J) and look for error messages.&lt;br /&gt;
# Check for syntax errors in your code and ensure that interface functions are written correctly.&lt;br /&gt;
# Check that predefined hooks and functions like e.g. on_trigger() are written correctly. Syntax highlighting and coloring may help you identify these issues.&lt;br /&gt;
# When resolving widgets, verify the used widgets address (e.g. &amp;quot;/mxw/render/opacity&amp;quot;) and make sure that it is valid. To find the correct address, maybe refer to the list of address suggestions available in the &#039;Receiver&#039; menu.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Practical_examples&amp;diff=6180</id>
		<title>Practical examples</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Practical_examples&amp;diff=6180"/>
		<updated>2026-08-08T18:51:19Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 4. Practical examples to Practical examples: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Download the Javascript Reference folder from https://www.mxwendler.net/de/downloads.html&lt;br /&gt;
&lt;br /&gt;
1) 	Double click on the &amp;quot;js-demo.mxw&amp;quot; to load the demo.&amp;lt;div&amp;gt; &lt;br /&gt;
	&lt;br /&gt;
2) 	Open the I/O Settings Window (CTRL+1) or  click on &amp;quot;Settings&amp;quot; → &amp;quot;Inputs and Outputs - Keyboard, Midi, DMX&amp;quot; &amp;lt;div&amp;gt; &lt;br /&gt;
&amp;amp;emsp; and click on SHOW JAVASCRIPT CONSOLE, almost at the bottom of the I/O window.&lt;br /&gt;
&lt;br /&gt;
3)	Follow the instructions on the Javascript Console. &amp;lt;div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Commands:===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remember to click on the interface header before giving commands,&lt;br /&gt;
the operating System needs to know where the keyboard signals are directed.&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;code&amp;gt;backspace&amp;lt;/code&amp;gt;	starts the patch and selects the LiveEditor Tab.	&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;code&amp;gt;spacebar&amp;lt;/code&amp;gt; 	(6 times at least) to set up a tap tempo&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; 	Sets the render opacity to 0&lt;br /&gt;
&amp;lt;div&amp;gt;	&lt;br /&gt;
	&amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; 	Sets the render opacity to 0.5&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;  Sets the render opacity to 1&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;  Writes Output informations on the Javascript console.&lt;br /&gt;
			        Takes a screenshot of the output and saves it in &amp;quot;C:\screen&amp;quot;&lt;br /&gt;
			        (if the directory already exists)&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_JavaScript&amp;diff=6178</id>
		<title>Controlling MXW through JavaScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Controlling_MXW_through_JavaScript&amp;diff=6178"/>
		<updated>2026-08-08T18:51:18Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page 1. Controlling MXW through JavaScript to Controlling MXW through JavaScript: Remove leading index prefix from title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Although there are many ways to control MXWendler with a lot of I/O devices, e.g.  mouse buttons, keyboard, DMX and MIDI devices, and automation commands in MXWendler using events in the playlist, some desired behaviours are too complex to be offered through a GUI element. &lt;br /&gt;
JavaScript allows instead to script any animation and behaviour sequence. Additionally, JavaScript allows you to emit values to I/O devices like DMX, OSC or MIDI and set various internal variables in media and in the software.&lt;br /&gt;
&lt;br /&gt;
The JavaScript engine used by the MXWendler scripting is Duktape, standardized under ECMAScript E5/E5.1. (more info at the Duktape [https://duktape.org/index.html website])&lt;br /&gt;
&lt;br /&gt;
To write JavaScripts open MXWendler &amp;quot;StageDesigner&amp;quot; or &amp;quot;FxServer&amp;quot; and access the editor by clicking &amp;quot;Settings&amp;quot; &amp;amp;rarr; &amp;quot;Inputs and Outputs - Keyboard, Midi, DMX&amp;quot; (or with the hotkey &amp;lt;code&amp;gt;CTRL + 1&amp;lt;/code&amp;gt;) &lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[File:Open settings.jpeg|728px]]&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
On the window, in the first tab (&amp;quot;DMX/Midi/Keyboard Events&amp;quot;) the editor is available in the lower right corner.&lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
[[File:Editor.jpeg|728px]]&lt;br /&gt;
{{#mpdftags: pagebreak}}&lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
To facilitate debugging, a script-wide function &amp;quot;print_console&amp;quot; is available and the Javascript console is available to be opened from either the checkbox under the editor, or from the menu: &amp;quot;Settings&amp;quot; &amp;amp;rarr; &amp;quot;Open Javascript Console&amp;quot; (&amp;lt;code&amp;gt;CTRL + J&amp;lt;/code&amp;gt;)&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Python_imgui_reference&amp;diff=6177</id>
		<title>Python imgui reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Python_imgui_reference&amp;diff=6177"/>
		<updated>2026-08-08T18:00:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: Fix example (mxw.print_console) and repoint broken Python Plugin Howto link (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- MXWendler wiki page: Python mxw_imgui command reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Intended location: https://wiki.mxwendler.net/index.php?title=Python_ImGui_Reference --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_Reference (the mxw module) --&amp;gt;&lt;br /&gt;
&amp;lt;!-- See also: https://wiki.mxwendler.net/index.php?title=Python_plugin_reference --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are listed the commands available in module &amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt;, MXWendler&#039;s Python binding of &#039;&#039;&#039;Dear ImGui&#039;&#039;&#039;. This is how plugins draw their settings panel, in the &amp;lt;code&amp;gt;onRenderPanel()&amp;lt;/code&amp;gt; hook (see the [[Python plugin reference|Python plugin reference]]).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;mxw_imgui&amp;lt;/code&amp;gt; mirrors the Dear ImGui C++ API almost function-for-function: the C++ &amp;lt;code&amp;gt;ImGui::PascalCase&amp;lt;/code&amp;gt; names become Python &amp;lt;code&amp;gt;snake_case&amp;lt;/code&amp;gt;, one argument at a time. If you already know Dear ImGui (or its C++/other-language bindings), the name of a call is usually a mechanical translation away.&lt;br /&gt;
&lt;br /&gt;
=== Legend ===&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Everything from the [[Python_Reference|Python Reference]] Legend applies (floats, integers, strings, &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; for alternative formats). In addition:&lt;br /&gt;
&lt;br /&gt;
Dear ImGui widgets that take a pointer to their value in C++ (so the value can be written back) instead return a &#039;&#039;&#039;tuple&#039;&#039;&#039; &amp;lt;code&amp;gt;(changed, value)&amp;lt;/code&amp;gt; in Python: &amp;lt;code&amp;gt;changed&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; when the user edited the widget this frame, &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; is the (possibly new) value to keep and pass back in next frame. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;changed, value = mxw_imgui.slider_float(&amp;quot;Speed&amp;quot;, value, 0.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Widgets with several packed floats/ints (&amp;lt;code&amp;gt;drag_float2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;slider_int4&amp;lt;/code&amp;gt;, ...) take and return a plain Python list/tuple of that length instead of a C array.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Flags&#039;&#039;&#039; (&amp;lt;code&amp;gt;ImGuiTreeNodeFlags&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ImGuiWindowFlags&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ImGuiCol&amp;lt;/code&amp;gt;, ...) are &#039;&#039;&#039;not&#039;&#039;&#039; exposed as named Python constants — pass the plain integer value of the Dear ImGui enum (default &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; means &amp;quot;no flags&amp;quot; for nearly every call). Consult the Dear ImGui headers/docs for the numeric values if you need non-default flags.&lt;br /&gt;
&lt;br /&gt;
Parameters shown as &amp;lt;code&amp;gt;= value&amp;lt;/code&amp;gt; in the tables below are &#039;&#039;&#039;optional&#039;&#039;&#039; with that default; omit them to use the default.&lt;br /&gt;
&lt;br /&gt;
Plugins draw &#039;&#039;&#039;into an existing panel&#039;&#039;&#039; — there is no &amp;lt;code&amp;gt;begin&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; for top-level windows; start directly with widget calls.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data types ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON TYPE !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.Vec2()&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.Vec2(x, y)&amp;lt;/code&amp;gt; || 2D float vector (&amp;lt;code&amp;gt;.x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.y&amp;lt;/code&amp;gt;), used for sizes and positions || &amp;lt;code&amp;gt;size = mxw_imgui.Vec2(200, 0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.Vec4()&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.Vec4(x, y, z, w)&amp;lt;/code&amp;gt; || 4D float vector (&amp;lt;code&amp;gt;.x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.y&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.z&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.w&amp;lt;/code&amp;gt;), used for colors (RGBA) and rectangles || &amp;lt;code&amp;gt;col = mxw_imgui.Vec4(1.0, 0.0, 0.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.Vector_char&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_float&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_unsignedchar&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_unsignedshort&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_DrawCmd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_DrawVert&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Vector_FontGlyph&amp;lt;/code&amp;gt; || Read-only iterable wrappers around Dear ImGui&#039;s internal &amp;lt;code&amp;gt;ImVector&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; buffers, returned by some getters (e.g. draw list data). Support &amp;lt;code&amp;gt;len()&amp;lt;/code&amp;gt;, iteration and indexing || &amp;lt;code&amp;gt;for glyph in font.Glyphs: pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Style &amp;amp;amp; Fonts ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_font(font)&amp;lt;/code&amp;gt; || push a font onto the font stack for subsequent widgets || &amp;lt;code&amp;gt;mxw_imgui.push_font(mxw_imgui.get_font())&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_font()&amp;lt;/code&amp;gt; || pop the last pushed font || &amp;lt;code&amp;gt;mxw_imgui.pop_font()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_style_color(idx, col)&amp;lt;/code&amp;gt; || push a style color override (&amp;lt;code&amp;gt;col&amp;lt;/code&amp;gt; as packed &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mxw_imgui.push_style_color(0, mxw_imgui.Vec4(1,0,0,1))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_style_color(count = 1)&amp;lt;/code&amp;gt; || pop &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; previously pushed style colors || &amp;lt;code&amp;gt;mxw_imgui.pop_style_color()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_style_var(idx, val)&amp;lt;/code&amp;gt; || push a style var override (&amp;lt;code&amp;gt;val&amp;lt;/code&amp;gt; as float OR &amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mxw_imgui.push_style_var(0, 4.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_style_var(count = 1)&amp;lt;/code&amp;gt; || pop &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; previously pushed style vars || &amp;lt;code&amp;gt;mxw_imgui.pop_style_var()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_allow_keyboard_focus(allow_keyboard_focus)&amp;lt;/code&amp;gt; || allow/disallow tab-focusing the next widgets || &amp;lt;code&amp;gt;mxw_imgui.push_allow_keyboard_focus(false)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_allow_keyboard_focus()&amp;lt;/code&amp;gt; || pop the keyboard-focus override || &amp;lt;code&amp;gt;mxw_imgui.pop_allow_keyboard_focus()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_button_repeat(repeat)&amp;lt;/code&amp;gt; || make subsequent buttons behave as repeating (held = repeated clicks) || &amp;lt;code&amp;gt;mxw_imgui.push_button_repeat(true)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_button_repeat()&amp;lt;/code&amp;gt; || pop the button-repeat override || &amp;lt;code&amp;gt;mxw_imgui.pop_button_repeat()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_font()&amp;lt;/code&amp;gt; || returns the current font object || &amp;lt;code&amp;gt;f = mxw_imgui.get_font()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_font_size()&amp;lt;/code&amp;gt; || returns the current font size in px || &amp;lt;code&amp;gt;sz = mxw_imgui.get_font_size()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_font_tex_uv_white_pixel()&amp;lt;/code&amp;gt; || returns UV coordinate of a white pixel in the font texture, for custom draw-list use || &amp;lt;code&amp;gt;uv = mxw_imgui.get_font_tex_uv_white_pixel()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_color_u32(idx, alpha_mul = 1.0)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_color_u32(col)&amp;lt;/code&amp;gt; || resolve a style color index, a &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt;, or a packed &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt; to a final packed &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt; color || &amp;lt;code&amp;gt;c = mxw_imgui.get_color_u32(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_style_color_vec4(idx)&amp;lt;/code&amp;gt; || returns the raw &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt; for a style color index || &amp;lt;code&amp;gt;c = mxw_imgui.get_style_color_vec4(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_style_color_name(idx)&amp;lt;/code&amp;gt; || returns the readable name of a style color index || &amp;lt;code&amp;gt;mxw.print_console(mxw_imgui.get_style_color_name(0))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_color_edit_options(flags)&amp;lt;/code&amp;gt; || set default flags for every subsequent color_edit/color_picker call || &amp;lt;code&amp;gt;mxw_imgui.set_color_edit_options(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Cursor &amp;amp;amp; Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_item_width(item_width)&amp;lt;/code&amp;gt; || push a fixed width (px, or negative = right-aligned) for subsequent widgets || &amp;lt;code&amp;gt;mxw_imgui.push_item_width(150)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_item_width()&amp;lt;/code&amp;gt; || pop the pushed item width || &amp;lt;code&amp;gt;mxw_imgui.pop_item_width()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_next_item_width(item_width)&amp;lt;/code&amp;gt; || set the width of just the next widget || &amp;lt;code&amp;gt;mxw_imgui.set_next_item_width(300)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.calc_item_width()&amp;lt;/code&amp;gt; || returns the width the next widget would use || &amp;lt;code&amp;gt;w = mxw_imgui.calc_item_width()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_text_wrap_pos(wrap_local_pos_x = 0.0)&amp;lt;/code&amp;gt; || push a word-wrap position (0 = wrap at window edge) for subsequent text || &amp;lt;code&amp;gt;mxw_imgui.push_text_wrap_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_text_wrap_pos()&amp;lt;/code&amp;gt; || pop the pushed wrap position || &amp;lt;code&amp;gt;mxw_imgui.pop_text_wrap_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.separator()&amp;lt;/code&amp;gt; || draw a thin horizontal separator line || &amp;lt;code&amp;gt;mxw_imgui.separator()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.same_line(offset_from_start_x = 0.0, spacing = -1.0)&amp;lt;/code&amp;gt; || keep the next widget on the same line as the previous one || &amp;lt;code&amp;gt;mxw_imgui.same_line()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.new_line()&amp;lt;/code&amp;gt; || force a following widget to start on a new line || &amp;lt;code&amp;gt;mxw_imgui.new_line()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.spacing()&amp;lt;/code&amp;gt; || add vertical spacing || &amp;lt;code&amp;gt;mxw_imgui.spacing()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.dummy(size)&amp;lt;/code&amp;gt; || reserve an empty invisible &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;) area, e.g. as a spacer || &amp;lt;code&amp;gt;mxw_imgui.dummy(mxw_imgui.Vec2(0, 10))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.indent(indent_w = 0.0)&amp;lt;/code&amp;gt; || move the cursor right (indent) || &amp;lt;code&amp;gt;mxw_imgui.indent()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.unindent(indent_w = 0.0)&amp;lt;/code&amp;gt; || move the cursor back left (unindent), matching a prior indent() || &amp;lt;code&amp;gt;mxw_imgui.unindent()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_group()&amp;lt;/code&amp;gt; || start a layout group (following widgets are treated as one unit for layout purposes) || &amp;lt;code&amp;gt;mxw_imgui.begin_group()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.end_group()&amp;lt;/code&amp;gt; || close the current layout group || &amp;lt;code&amp;gt;mxw_imgui.end_group()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_cursor_pos()&amp;lt;/code&amp;gt; || returns the cursor position (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;) relative to the current window || &amp;lt;code&amp;gt;p = mxw_imgui.get_cursor_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_cursor_pos_x()&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_cursor_pos_y()&amp;lt;/code&amp;gt; || returns just the X or Y cursor coordinate || &amp;lt;code&amp;gt;x = mxw_imgui.get_cursor_pos_x()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_cursor_pos(local_pos)&amp;lt;/code&amp;gt; || set the cursor position (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;), window-relative || &amp;lt;code&amp;gt;mxw_imgui.set_cursor_pos(mxw_imgui.Vec2(0, 0))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_cursor_pos_x(local_x)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.set_cursor_pos_y(local_y)&amp;lt;/code&amp;gt; || set just the X or Y cursor coordinate || &amp;lt;code&amp;gt;mxw_imgui.set_cursor_pos_x(20)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_cursor_start_pos()&amp;lt;/code&amp;gt; || returns the initial cursor position of the current window/child || &amp;lt;code&amp;gt;p = mxw_imgui.get_cursor_start_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_cursor_screen_pos()&amp;lt;/code&amp;gt; || returns the cursor position in absolute screen coordinates || &amp;lt;code&amp;gt;p = mxw_imgui.get_cursor_screen_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_cursor_screen_pos(pos)&amp;lt;/code&amp;gt; || set the cursor in absolute screen coordinates || &amp;lt;code&amp;gt;mxw_imgui.set_cursor_screen_pos(p)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.align_text_to_frame_padding()&amp;lt;/code&amp;gt; || vertically align following text with standard framed widgets on the same line || &amp;lt;code&amp;gt;mxw_imgui.align_text_to_frame_padding()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_text_line_height()&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_text_line_height_with_spacing()&amp;lt;/code&amp;gt; || returns one text line&#039;s height, with or without inter-line spacing || &amp;lt;code&amp;gt;h = mxw_imgui.get_text_line_height()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_frame_height()&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_frame_height_with_spacing()&amp;lt;/code&amp;gt; || returns a standard framed widget&#039;s height, with or without spacing || &amp;lt;code&amp;gt;h = mxw_imgui.get_frame_height()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== ID stack ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_id(str_id)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.push_id(str_id_begin, str_id_end)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.push_id(ptr_id)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.push_id(int_id)&amp;lt;/code&amp;gt; || push a scope onto the ID stack, so same-labelled widgets in a loop don&#039;t collide || &amp;lt;code&amp;gt;mxw_imgui.push_id(i)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_id()&amp;lt;/code&amp;gt; || pop the last pushed ID scope || &amp;lt;code&amp;gt;mxw_imgui.pop_id()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_id(str_id)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_id(str_id_begin, str_id_end)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.get_id(ptr_id)&amp;lt;/code&amp;gt; || compute a widget ID without pushing it || &amp;lt;code&amp;gt;uid = mxw_imgui.get_id(&amp;quot;my_widget&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Text ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.text_unformatted(text, text_end = None)&amp;lt;/code&amp;gt; || draw raw text, faster than &amp;lt;code&amp;gt;text()&amp;lt;/code&amp;gt; for long/dynamic strings (no format parsing) || &amp;lt;code&amp;gt;mxw_imgui.text_unformatted(&amp;quot;Ready.&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.text(fmt)&amp;lt;/code&amp;gt; || draw a line of text || &amp;lt;code&amp;gt;mxw_imgui.text(&amp;quot;Frame: &amp;quot; + str(mxw.framecounter))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.text_colored(col, fmt)&amp;lt;/code&amp;gt; || draw text in the given &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt; color || &amp;lt;code&amp;gt;mxw_imgui.text_colored(mxw_imgui.Vec4(1,0,0,1), &amp;quot;Error&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.text_disabled(fmt)&amp;lt;/code&amp;gt; || draw text in the disabled/grey style color || &amp;lt;code&amp;gt;mxw_imgui.text_disabled(&amp;quot;(no signal)&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.text_wrapped(fmt)&amp;lt;/code&amp;gt; || draw text that wraps at the window edge, regardless of the wrap-pos stack || &amp;lt;code&amp;gt;mxw_imgui.text_wrapped(status_message)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.label_text(label, fmt)&amp;lt;/code&amp;gt; || draw a &amp;quot;label: value&amp;quot;-style line (label aligned like other widgets) || &amp;lt;code&amp;gt;mxw_imgui.label_text(&amp;quot;Status&amp;quot;, &amp;quot;OK&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.bullet_text(fmt)&amp;lt;/code&amp;gt; || draw a bulleted line of text || &amp;lt;code&amp;gt;mxw_imgui.bullet_text(&amp;quot;first item&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Main widgets ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.button(label, size = Vec2(0,0))&amp;lt;/code&amp;gt; || a clickable button; returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; the frame it&#039;s clicked || &amp;lt;code&amp;gt;if mxw_imgui.button(&amp;quot;Reload&amp;quot;): reload()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.small_button(label)&amp;lt;/code&amp;gt; || a button with no extra vertical padding, fits inline with text || &amp;lt;code&amp;gt;if mxw_imgui.small_button(&amp;quot;x&amp;quot;): close()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.invisible_button(str_id, size, flags = 0)&amp;lt;/code&amp;gt; || an invisible clickable/draggable area || &amp;lt;code&amp;gt;mxw_imgui.invisible_button(&amp;quot;drag_area&amp;quot;, mxw_imgui.Vec2(50,50))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.arrow_button(str_id, dir)&amp;lt;/code&amp;gt; || a small square button with an arrow glyph (&amp;lt;code&amp;gt;dir&amp;lt;/code&amp;gt;: 0=left,1=right,2=up,3=down) || &amp;lt;code&amp;gt;mxw_imgui.arrow_button(&amp;quot;up&amp;quot;, 2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.image(user_texture_id, size, uv0 = Vec2(0,0), uv1 = Vec2(1,1), tint_col = Vec4(1,1,1,1), border_col = Vec4(0,0,0,0))&amp;lt;/code&amp;gt; || draw a texture (GL texture id) as an image || &amp;lt;code&amp;gt;mxw_imgui.image(tex_id, mxw_imgui.Vec2(128,128))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.image_button(user_texture_id, size, uv0 = Vec2(0,0), uv1 = Vec2(1,1), frame_padding = -1, bg_col = Vec4(0,0,0,0), tint_col = Vec4(1,1,1,1))&amp;lt;/code&amp;gt; || a clickable image button || &amp;lt;code&amp;gt;if mxw_imgui.image_button(tex_id, mxw_imgui.Vec2(32,32)): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.checkbox(label, v)&amp;lt;/code&amp;gt; || a checkbox; &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt;/return is &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;changed, enabled = mxw_imgui.checkbox(&amp;quot;Enabled&amp;quot;, enabled)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.checkbox_flags(label, flags, flags_value)&amp;lt;/code&amp;gt; || a checkbox that toggles one bit(mask) of an int flags value || &amp;lt;code&amp;gt;changed, flags = mxw_imgui.checkbox_flags(&amp;quot;Bit 1&amp;quot;, flags, 1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.radio_button(label, active)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.radio_button(label, v, v_button)&amp;lt;/code&amp;gt; || a radio button; single-bool form for manual state, or bind directly to an int selection variable || &amp;lt;code&amp;gt;changed, mode = mxw_imgui.radio_button(&amp;quot;Mode A&amp;quot;, mode, 0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.progress_bar(fraction, size_arg = Vec2(-FLT_MIN, 0), overlay = None)&amp;lt;/code&amp;gt; || a progress bar, &amp;lt;code&amp;gt;fraction&amp;lt;/code&amp;gt; 0.0..1.0 || &amp;lt;code&amp;gt;mxw_imgui.progress_bar(0.5)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.bullet()&amp;lt;/code&amp;gt; || draw just a bullet glyph, e.g. before inline text/widgets || &amp;lt;code&amp;gt;mxw_imgui.bullet()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Combo box ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.combo(label, current_item, items, popup_max_height_in_items = -1)&amp;lt;/code&amp;gt; || a combo box built from a Python list of strings; simplest way to pick one of several options || &amp;lt;code&amp;gt;changed, sel = mxw_imgui.combo(&amp;quot;Mode&amp;quot;, sel, [&amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;])&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_combo(label, preview_value, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_combo()&amp;lt;/code&amp;gt; || low-level combo box: build the popup content yourself (e.g. with &amp;lt;code&amp;gt;selectable()&amp;lt;/code&amp;gt;) between these two calls || &amp;lt;code&amp;gt;if mxw_imgui.begin_combo(&amp;quot;Mode&amp;quot;, preview): mxw_imgui.end_combo()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Drag sliders ===&lt;br /&gt;
Click-and-drag widgets; typing is also possible (Ctrl+click / double-click).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_float(label, v, v_speed = 1.0, v_min = 0.0, v_max = 0.0, format = None, flags = 0)&amp;lt;/code&amp;gt; || drag a single float; &amp;lt;code&amp;gt;v_min == v_max == 0&amp;lt;/code&amp;gt; means unbounded || &amp;lt;code&amp;gt;changed, value = mxw_imgui.drag_float(&amp;quot;Speed&amp;quot;, value, 0.01, 0.0, 2.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_float2(label, v, ...)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;drag_float3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;drag_float4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 floats (e.g. a color or position) || &amp;lt;code&amp;gt;changed, xyz = mxw_imgui.drag_float3(&amp;quot;Position&amp;quot;, xyz)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_float_range2(label, v_current_min, v_current_max, v_speed = 1.0, v_min = 0.0, v_max = 0.0, format = None, format_max = None, flags = 0)&amp;lt;/code&amp;gt; || drag a min/max float range with two handles || &amp;lt;code&amp;gt;changed, lo, hi = mxw_imgui.drag_float_range2(&amp;quot;Range&amp;quot;, lo, hi)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_int(label, v, v_speed = 1.0, v_min = 0, v_max = 0, format = None, flags = 0)&amp;lt;/code&amp;gt; || drag a single int || &amp;lt;code&amp;gt;changed, value = mxw_imgui.drag_int(&amp;quot;Count&amp;quot;, value, 1, 0, 10)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_int2(label, v, ...)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;drag_int3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;drag_int4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 ints || &amp;lt;code&amp;gt;changed, rgb = mxw_imgui.drag_int3(&amp;quot;RGB&amp;quot;, rgb, 1, 0, 255)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_int_range2(label, v_current_min, v_current_max, ...)&amp;lt;/code&amp;gt; || drag a min/max int range with two handles || &amp;lt;code&amp;gt;changed, lo, hi = mxw_imgui.drag_int_range2(&amp;quot;Range&amp;quot;, lo, hi)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.drag_scalar(label, data_type, p_data, v_speed, p_min = None, p_max = None, format = None, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;drag_scalar_n(..., components, ...)&amp;lt;/code&amp;gt; || generic drag widget for any &amp;lt;code&amp;gt;ImGuiDataType&amp;lt;/code&amp;gt;, rarely needed from Python || &amp;lt;code&amp;gt;mxw_imgui.drag_scalar(&amp;quot;Value&amp;quot;, 0, ptr, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sliders ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_float(label, v, v_min, v_max, format = None, flags = 0)&amp;lt;/code&amp;gt; || slide a single float between &amp;lt;code&amp;gt;v_min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;v_max&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;changed, value = mxw_imgui.slider_float(&amp;quot;Mouse X&amp;quot;, value, 0.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_float2(label, v, v_min, v_max, ...)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;slider_float3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;slider_float4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 floats || &amp;lt;code&amp;gt;changed, rgba = mxw_imgui.slider_float4(&amp;quot;Color&amp;quot;, rgba, 0.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_angle(label, v_rad, v_degrees_min = -360.0, v_degrees_max = 360.0, format = None, flags = 0)&amp;lt;/code&amp;gt; || slide an angle, stored in radians but displayed/typed in degrees || &amp;lt;code&amp;gt;changed, rot = mxw_imgui.slider_angle(&amp;quot;Rotation&amp;quot;, rot)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_int(label, v, v_min, v_max, format = None, flags = 0)&amp;lt;/code&amp;gt; || slide a single int || &amp;lt;code&amp;gt;changed, idx = mxw_imgui.slider_int(&amp;quot;Preset&amp;quot;, idx, 0, 99)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_int2(label, v, v_min, v_max, ...)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;slider_int3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;slider_int4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 ints || &amp;lt;code&amp;gt;changed, xy = mxw_imgui.slider_int2(&amp;quot;Grid pos&amp;quot;, xy, 0, 10)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.slider_scalar(label, data_type, p_data, p_min, p_max, format = None, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;slider_scalar_n(..., components, ...)&amp;lt;/code&amp;gt; || generic slider for any &amp;lt;code&amp;gt;ImGuiDataType&amp;lt;/code&amp;gt;, rarely needed from Python || &amp;lt;code&amp;gt;mxw_imgui.slider_scalar(&amp;quot;Value&amp;quot;, 0, ptr, p_min, p_max)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.v_slider_float(label, size, v, v_min, v_max, format = None, flags = 0)&amp;lt;/code&amp;gt; || vertical slider variant of &amp;lt;code&amp;gt;slider_float&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;changed, value = mxw_imgui.v_slider_float(&amp;quot;##vol&amp;quot;, mxw_imgui.Vec2(20,100), value, 0.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.v_slider_int(label, size, v, v_min, v_max, format = None, flags = 0)&amp;lt;/code&amp;gt; || vertical slider variant of &amp;lt;code&amp;gt;slider_int&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;changed, value = mxw_imgui.v_slider_int(&amp;quot;##lvl&amp;quot;, mxw_imgui.Vec2(20,100), value, 0, 10)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.v_slider_scalar(label, size, data_type, p_data, p_min, p_max, format = None, flags = 0)&amp;lt;/code&amp;gt; || generic vertical slider for any &amp;lt;code&amp;gt;ImGuiDataType&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxw_imgui.v_slider_scalar(&amp;quot;##v&amp;quot;, size, 0, ptr, p_min, p_max)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Input widgets ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_text(label, data, max_size, flags = 0)&amp;lt;/code&amp;gt; || a single-line text field; &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; is the current string, &amp;lt;code&amp;gt;max_size&amp;lt;/code&amp;gt; the max length in bytes || &amp;lt;code&amp;gt;changed, value = mxw_imgui.input_text(&amp;quot;URL&amp;quot;, url_text, 512)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_text_multiline(label, data, max_size, size = Vec2(0,0), flags = 0)&amp;lt;/code&amp;gt; || a multi-line text field || &amp;lt;code&amp;gt;changed, value = mxw_imgui.input_text_multiline(&amp;quot;Notes&amp;quot;, notes, 2048, mxw_imgui.Vec2(300,100))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_float(label, v, step = 0.0, step_fast = 0.0, format = None, flags = 0)&amp;lt;/code&amp;gt; || a typed float field with optional +/- step buttons || &amp;lt;code&amp;gt;changed, value = mxw_imgui.input_float(&amp;quot;Gain&amp;quot;, value, 0.1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_float2(label, v, ...)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;input_float3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;input_float4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 floats || &amp;lt;code&amp;gt;changed, xyz = mxw_imgui.input_float3(&amp;quot;Pos&amp;quot;, xyz)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_int(label, v, step = 1, step_fast = 100, flags = 0)&amp;lt;/code&amp;gt; || a typed int field with +/- step buttons || &amp;lt;code&amp;gt;changed, value = mxw_imgui.input_int(&amp;quot;Count&amp;quot;, value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_int2(label, v, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;input_int3&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;input_int4&amp;lt;/code&amp;gt; || same, for a list of 2/3/4 ints || &amp;lt;code&amp;gt;changed, rgb = mxw_imgui.input_int3(&amp;quot;RGB&amp;quot;, rgb)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_double(label, v, step = 0.0, step_fast = 0.0, format = None, flags = 0)&amp;lt;/code&amp;gt; || a typed double field || &amp;lt;code&amp;gt;changed, value = mxw_imgui.input_double(&amp;quot;Precise&amp;quot;, value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.input_scalar(label, data_type, p_data, p_step = None, p_step_fast = None, format = None, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;input_scalar_n(..., components, ...)&amp;lt;/code&amp;gt; || generic typed field for any &amp;lt;code&amp;gt;ImGuiDataType&amp;lt;/code&amp;gt;, rarely needed from Python || &amp;lt;code&amp;gt;mxw_imgui.input_scalar(&amp;quot;Value&amp;quot;, 0, ptr)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Color editor &amp;amp;amp; picker ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_edit3(label, col, flags = 0)&amp;lt;/code&amp;gt; || a compact RGB color editor (swatch + popup picker); &amp;lt;code&amp;gt;col&amp;lt;/code&amp;gt; is a 3-float list || &amp;lt;code&amp;gt;changed, rgb = mxw_imgui.color_edit3(&amp;quot;Tint&amp;quot;, rgb)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_edit4(label, col, flags = 0)&amp;lt;/code&amp;gt; || same, RGBA (4-float list) || &amp;lt;code&amp;gt;changed, rgba = mxw_imgui.color_edit4(&amp;quot;Tint&amp;quot;, rgba)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_picker3(label, col, flags = 0)&amp;lt;/code&amp;gt; || a full RGB color picker widget, always expanded || &amp;lt;code&amp;gt;changed, rgb = mxw_imgui.color_picker3(&amp;quot;Tint&amp;quot;, rgb)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_picker4(label, col, flags = 0, ref_col = None)&amp;lt;/code&amp;gt; || same, RGBA, optionally showing a reference color for comparison || &amp;lt;code&amp;gt;changed, rgba = mxw_imgui.color_picker4(&amp;quot;Tint&amp;quot;, rgba)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_button(desc_id, col, flags = 0, size = Vec2(0,0))&amp;lt;/code&amp;gt; || a non-editable color swatch button (e.g. as a preview/trigger) || &amp;lt;code&amp;gt;if mxw_imgui.color_button(&amp;quot;preview&amp;quot;, col): open_picker()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Trees ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.tree_node(label)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.tree_node(str_id, fmt)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.tree_node(ptr_id, fmt)&amp;lt;/code&amp;gt; || an expandable/collapsible tree node; returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; while open. Call &amp;lt;code&amp;gt;tree_pop()&amp;lt;/code&amp;gt; if it returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;if mxw_imgui.tree_node(&amp;quot;Advanced&amp;quot;): mxw_imgui.tree_pop()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.tree_node_ex(label, flags = 0)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.tree_node_ex(str_id, flags, fmt)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.tree_node_ex(ptr_id, flags, fmt)&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;tree_node()&amp;lt;/code&amp;gt; with explicit flags (e.g. default-open, leaf, selected) || &amp;lt;code&amp;gt;if mxw_imgui.tree_node_ex(&amp;quot;Node&amp;quot;, 0): mxw_imgui.tree_pop()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.tree_push(str_id)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.tree_push(ptr_id = None)&amp;lt;/code&amp;gt; || push an indent level without drawing a node (paired with &amp;lt;code&amp;gt;tree_pop()&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mxw_imgui.tree_push(&amp;quot;scope&amp;quot;); mxw_imgui.tree_pop()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.tree_pop()&amp;lt;/code&amp;gt; || pop one indent level pushed by &amp;lt;code&amp;gt;tree_node()&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;tree_push()&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxw_imgui.tree_pop()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_tree_node_to_label_spacing()&amp;lt;/code&amp;gt; || returns the horizontal spacing between a tree node arrow and its label || &amp;lt;code&amp;gt;s = mxw_imgui.get_tree_node_to_label_spacing()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.collapsing_header(label, flags = 0)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.collapsing_header(label, p_visible, flags = 0)&amp;lt;/code&amp;gt; || a top-level collapsible section header; optionally with a close (&amp;quot;x&amp;quot;) button when &amp;lt;code&amp;gt;p_visible&amp;lt;/code&amp;gt; is passed || &amp;lt;code&amp;gt;if mxw_imgui.collapsing_header(&amp;quot;Settings&amp;quot;): mxw_imgui.text(&amp;quot;...&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_next_item_open(is_open, cond = 0)&amp;lt;/code&amp;gt; || force the next &amp;lt;code&amp;gt;tree_node()&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;collapsing_header()&amp;lt;/code&amp;gt; open/closed state || &amp;lt;code&amp;gt;mxw_imgui.set_next_item_open(true)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Selectables &amp;amp;amp; list boxes ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.selectable(label, selected = false, flags = 0, size = Vec2(0,0))&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.selectable(label, p_selected, flags = 0, size = Vec2(0,0))&amp;lt;/code&amp;gt; || a clickable, highlightable row (typically inside a list box) || &amp;lt;code&amp;gt;if mxw_imgui.selectable(&amp;quot;Item 1&amp;quot;, is_sel): pick(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_list_box(label, size = Vec2(0,0))&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_list_box()&amp;lt;/code&amp;gt; || low-level list box: build the rows yourself (e.g. with &amp;lt;code&amp;gt;selectable()&amp;lt;/code&amp;gt;) between these two calls || &amp;lt;code&amp;gt;if mxw_imgui.begin_list_box(&amp;quot;Items&amp;quot;): mxw_imgui.end_list_box()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.list_box(label, current_item, items, height_in_items = -1)&amp;lt;/code&amp;gt; || a list box built from a Python list of strings, single-select || &amp;lt;code&amp;gt;changed, sel = mxw_imgui.list_box(&amp;quot;Presets&amp;quot;, sel, [&amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;])&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.list_box_stretch(label, current_item, items)&amp;lt;/code&amp;gt; || MXWendler custom variant of &amp;lt;code&amp;gt;list_box()&amp;lt;/code&amp;gt; that stretches to fill the remaining panel height || &amp;lt;code&amp;gt;changed, sel = mxw_imgui.list_box_stretch(&amp;quot;Presets&amp;quot;, sel, names)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Data plotting ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.plot_lines(label, values, values_offset = 0, overlay_text = None, scale_min = FLT_MAX, scale_max = FLT_MAX, graph_size = Vec2(0,0))&amp;lt;/code&amp;gt; || draw a line graph from a Python list of floats || &amp;lt;code&amp;gt;mxw_imgui.plot_lines(&amp;quot;Levels&amp;quot;, history)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.plot_histogram(label, values, values_offset = 0, overlay_text = None, scale_min = FLT_MAX, scale_max = FLT_MAX, graph_size = Vec2(0,0))&amp;lt;/code&amp;gt; || draw a bar histogram from a Python list of floats || &amp;lt;code&amp;gt;mxw_imgui.plot_histogram(&amp;quot;Levels&amp;quot;, history)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Value() helpers ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.value(prefix, b)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.value(prefix, v)&amp;lt;/code&amp;gt; (int/uint) OR &amp;lt;code&amp;gt;mxw_imgui.value(prefix, v, float_format = None)&amp;lt;/code&amp;gt; || draw a &amp;quot;prefix: value&amp;quot; line for a bool/int/float, without building the string yourself || &amp;lt;code&amp;gt;mxw_imgui.value(&amp;quot;FPS&amp;quot;, mxw.fps)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Menus ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_menu_bar()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_menu_bar()&amp;lt;/code&amp;gt; || start/end a menu bar inside the current window || &amp;lt;code&amp;gt;if mxw_imgui.begin_menu_bar(): mxw_imgui.end_menu_bar()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_main_menu_bar()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_main_menu_bar()&amp;lt;/code&amp;gt; || start/end the application&#039;s main (top-level) menu bar || &amp;lt;code&amp;gt;if mxw_imgui.begin_main_menu_bar(): mxw_imgui.end_main_menu_bar()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_menu(label, enabled = true)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_menu()&amp;lt;/code&amp;gt; || start/end a (sub)menu; call &amp;lt;code&amp;gt;end_menu()&amp;lt;/code&amp;gt; only if &amp;lt;code&amp;gt;begin_menu()&amp;lt;/code&amp;gt; returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;if mxw_imgui.begin_menu(&amp;quot;File&amp;quot;): mxw_imgui.end_menu()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.menu_item(label, shortcut = None, selected = false, enabled = true)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.menu_item(label, shortcut, p_selected, enabled = true)&amp;lt;/code&amp;gt; || a clickable (optionally checkable) menu entry || &amp;lt;code&amp;gt;if mxw_imgui.menu_item(&amp;quot;Save&amp;quot;, &amp;quot;Ctrl+S&amp;quot;): save()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tooltips ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_tooltip()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_tooltip()&amp;lt;/code&amp;gt; || build a custom tooltip (any widgets) between these two calls || &amp;lt;code&amp;gt;mxw_imgui.begin_tooltip(); mxw_imgui.text(&amp;quot;info&amp;quot;); mxw_imgui.end_tooltip()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_tooltip(fmt)&amp;lt;/code&amp;gt; || a quick one-line tooltip for the last hovered item || &amp;lt;code&amp;gt;if mxw_imgui.is_item_hovered(): mxw_imgui.set_tooltip(&amp;quot;Explain this&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Popups &amp;amp;amp; modals ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.open_popup(str_id, flags = 0)&amp;lt;/code&amp;gt; || flag a popup to open (by ID) on the next matching &amp;lt;code&amp;gt;begin_popup()&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mxw_imgui.open_popup(&amp;quot;confirm_delete&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_popup(str_id, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_popup()&amp;lt;/code&amp;gt; || build a plain popup&#039;s content; call &amp;lt;code&amp;gt;end_popup()&amp;lt;/code&amp;gt; only if &amp;lt;code&amp;gt;begin_popup()&amp;lt;/code&amp;gt; returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;if mxw_imgui.begin_popup(&amp;quot;menu&amp;quot;): mxw_imgui.end_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_popup_modal(name, p_open = None, flags = 0)&amp;lt;/code&amp;gt; || build a modal popup&#039;s content (blocks interaction with the rest of the UI) || &amp;lt;code&amp;gt;opened, _ = mxw_imgui.begin_popup_modal(&amp;quot;Confirm&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.open_popup_on_item_click(str_id = None, popup_flags = 1)&amp;lt;/code&amp;gt; || open a popup when the last item is clicked (e.g. right-click context menu) || &amp;lt;code&amp;gt;mxw_imgui.open_popup_on_item_click(&amp;quot;ctx&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.close_current_popup()&amp;lt;/code&amp;gt; || close the popup currently being drawn (e.g. after a button inside it) || &amp;lt;code&amp;gt;if mxw_imgui.button(&amp;quot;OK&amp;quot;): mxw_imgui.close_current_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_popup_context_item(str_id = None, popup_flags = 1)&amp;lt;/code&amp;gt; || combined open+begin for a right-click context popup on the last item || &amp;lt;code&amp;gt;if mxw_imgui.begin_popup_context_item(): mxw_imgui.end_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_popup_context_window(str_id = None, popup_flags = 1)&amp;lt;/code&amp;gt; || same, anchored to the current window instead of the last item || &amp;lt;code&amp;gt;if mxw_imgui.begin_popup_context_window(): mxw_imgui.end_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_popup_context_void(str_id = None, popup_flags = 1)&amp;lt;/code&amp;gt; || same, opens on right-click on empty space (no window/item under cursor) || &amp;lt;code&amp;gt;if mxw_imgui.begin_popup_context_void(): mxw_imgui.end_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_popup_open(str_id, flags = 0)&amp;lt;/code&amp;gt; || returns whether the given popup is currently open || &amp;lt;code&amp;gt;open = mxw_imgui.is_popup_open(&amp;quot;menu&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tables ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_table(str_id, column, flags = 0, outer_size = Vec2(0,0), inner_width = 0.0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_table()&amp;lt;/code&amp;gt; || start/end a table; call &amp;lt;code&amp;gt;end_table()&amp;lt;/code&amp;gt; only if &amp;lt;code&amp;gt;begin_table()&amp;lt;/code&amp;gt; returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;if mxw_imgui.begin_table(&amp;quot;grid&amp;quot;, 3): mxw_imgui.end_table()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_next_row(row_flags = 0, min_row_height = 0.0)&amp;lt;/code&amp;gt; || start the next table row || &amp;lt;code&amp;gt;mxw_imgui.table_next_row()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_next_column()&amp;lt;/code&amp;gt; || advance to the next cell (wraps to the next row automatically) || &amp;lt;code&amp;gt;mxw_imgui.table_next_column()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_set_column_index(column_n)&amp;lt;/code&amp;gt; || jump directly to a given column in the current row || &amp;lt;code&amp;gt;mxw_imgui.table_set_column_index(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_setup_column(label, flags = 0, init_width_or_weight = 0.0, user_id = 0)&amp;lt;/code&amp;gt; || declare a column&#039;s header label / sizing before the first row || &amp;lt;code&amp;gt;mxw_imgui.table_setup_column(&amp;quot;Name&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_setup_scroll_freeze(cols, rows)&amp;lt;/code&amp;gt; || freeze N leading columns/rows while the rest scrolls || &amp;lt;code&amp;gt;mxw_imgui.table_setup_scroll_freeze(0, 1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_headers_row()&amp;lt;/code&amp;gt; || draw the header row from the declared &amp;lt;code&amp;gt;table_setup_column()&amp;lt;/code&amp;gt; labels || &amp;lt;code&amp;gt;mxw_imgui.table_headers_row()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_header(label)&amp;lt;/code&amp;gt; || draw a single header cell manually (instead of &amp;lt;code&amp;gt;table_headers_row()&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mxw_imgui.table_header(&amp;quot;Name&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_sort_specs()&amp;lt;/code&amp;gt; || returns the current column sort specification, if the table is sortable || &amp;lt;code&amp;gt;specs = mxw_imgui.table_get_sort_specs()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_column_count()&amp;lt;/code&amp;gt; || returns the number of columns of the current table || &amp;lt;code&amp;gt;n = mxw_imgui.table_get_column_count()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_column_index()&amp;lt;/code&amp;gt; || returns the current column index || &amp;lt;code&amp;gt;i = mxw_imgui.table_get_column_index()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_row_index()&amp;lt;/code&amp;gt; || returns the current row index || &amp;lt;code&amp;gt;i = mxw_imgui.table_get_row_index()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_column_name(column_n = -1)&amp;lt;/code&amp;gt; || returns a column&#039;s declared label (-1 = current column) || &amp;lt;code&amp;gt;name = mxw_imgui.table_get_column_name(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_get_column_flags(column_n = -1)&amp;lt;/code&amp;gt; || returns a column&#039;s current flags (e.g. is it hidden/sorted) || &amp;lt;code&amp;gt;flags = mxw_imgui.table_get_column_flags()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.table_set_bg_color(target, color, column_n = -1)&amp;lt;/code&amp;gt; || set the background color of a cell/row/column || &amp;lt;code&amp;gt;mxw_imgui.table_set_bg_color(0, mxw_imgui.color_convert_float4_to_u32(mxw_imgui.Vec4(1,0,0,1)))&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy columns ===&lt;br /&gt;
Superseded by [[#Tables|Tables]] above, kept for compatibility.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.columns(count = 1, id = None, border = true)&amp;lt;/code&amp;gt; || switch the rest of the window into a simple N-column layout (&amp;lt;code&amp;gt;count = 1&amp;lt;/code&amp;gt; ends it) || &amp;lt;code&amp;gt;mxw_imgui.columns(2)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.next_column()&amp;lt;/code&amp;gt; || move to the next column (wraps to the next row) || &amp;lt;code&amp;gt;mxw_imgui.next_column()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_column_index()&amp;lt;/code&amp;gt; || returns the current column index || &amp;lt;code&amp;gt;i = mxw_imgui.get_column_index()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_column_width(column_index = -1)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.set_column_width(column_index, width)&amp;lt;/code&amp;gt; || get/set a column&#039;s width || &amp;lt;code&amp;gt;w = mxw_imgui.get_column_width()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_column_offset(column_index = -1)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.set_column_offset(column_index, offset_x)&amp;lt;/code&amp;gt; || get/set a column&#039;s X offset || &amp;lt;code&amp;gt;x = mxw_imgui.get_column_offset()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_columns_count()&amp;lt;/code&amp;gt; || returns the current column count || &amp;lt;code&amp;gt;n = mxw_imgui.get_columns_count()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Tabs ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_tab_bar(str_id, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_tab_bar()&amp;lt;/code&amp;gt; || start/end a tab bar; call &amp;lt;code&amp;gt;end_tab_bar()&amp;lt;/code&amp;gt; only if &amp;lt;code&amp;gt;begin_tab_bar()&amp;lt;/code&amp;gt; returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;if mxw_imgui.begin_tab_bar(&amp;quot;tabs&amp;quot;): mxw_imgui.end_tab_bar()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_tab_item(label, p_open = None, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_tab_item()&amp;lt;/code&amp;gt; || start/end one tab&#039;s content; call &amp;lt;code&amp;gt;end_tab_item()&amp;lt;/code&amp;gt; only if &amp;lt;code&amp;gt;begin_tab_item()&amp;lt;/code&amp;gt; returned &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;opened, _ = mxw_imgui.begin_tab_item(&amp;quot;Settings&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.tab_item_button(label, flags = 0)&amp;lt;/code&amp;gt; || a button drawn as a tab (e.g. a &amp;quot;+&amp;quot; to add a tab) || &amp;lt;code&amp;gt;if mxw_imgui.tab_item_button(&amp;quot;+&amp;quot;): add_tab()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_tab_item_closed(tab_or_docked_window_label)&amp;lt;/code&amp;gt; || programmatically close a tab by label || &amp;lt;code&amp;gt;mxw_imgui.set_tab_item_closed(&amp;quot;Old Tab&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Logging / capture ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_to_tty(auto_open_depth = -1)&amp;lt;/code&amp;gt; || start capturing following widgets&#039; text output to the app&#039;s TTY/console || &amp;lt;code&amp;gt;mxw_imgui.log_to_tty()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_to_file(auto_open_depth = -1, filename = None)&amp;lt;/code&amp;gt; || start capturing to a file || &amp;lt;code&amp;gt;mxw_imgui.log_to_file(-1, &amp;quot;log.txt&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_to_clipboard(auto_open_depth = -1)&amp;lt;/code&amp;gt; || start capturing to the OS clipboard || &amp;lt;code&amp;gt;mxw_imgui.log_to_clipboard()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_finish()&amp;lt;/code&amp;gt; || stop the current capture || &amp;lt;code&amp;gt;mxw_imgui.log_finish()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_buttons()&amp;lt;/code&amp;gt; || draw the standard &amp;quot;Log/Copy to clipboard&amp;quot; buttons || &amp;lt;code&amp;gt;mxw_imgui.log_buttons()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.log_text(fmt)&amp;lt;/code&amp;gt; || add text directly to the active log capture, without drawing a widget || &amp;lt;code&amp;gt;mxw_imgui.log_text(&amp;quot;captured line&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Drag and drop ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_drag_drop_source(flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_drag_drop_source()&amp;lt;/code&amp;gt; || make the last item a drag source; build the payload/preview between these two calls || &amp;lt;code&amp;gt;if mxw_imgui.begin_drag_drop_source(): mxw_imgui.end_drag_drop_source()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_drag_drop_payload(type, data, sz, cond = 0)&amp;lt;/code&amp;gt; || attach a payload to the drag currently being sourced || &amp;lt;code&amp;gt;mxw_imgui.set_drag_drop_payload(&amp;quot;CLIP&amp;quot;, data, len(data))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_drag_drop_target()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_drag_drop_target()&amp;lt;/code&amp;gt; || make the last item/window a drop target; check &amp;lt;code&amp;gt;accept_drag_drop_payload()&amp;lt;/code&amp;gt; between these two calls || &amp;lt;code&amp;gt;if mxw_imgui.begin_drag_drop_target(): mxw_imgui.end_drag_drop_target()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.accept_drag_drop_payload(type, flags = 0)&amp;lt;/code&amp;gt; || accept a payload of the given type while inside a drop target || &amp;lt;code&amp;gt;p = mxw_imgui.accept_drag_drop_payload(&amp;quot;CLIP&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_drag_drop_payload()&amp;lt;/code&amp;gt; || peek the payload of the drag currently in progress, even outside a target || &amp;lt;code&amp;gt;p = mxw_imgui.get_drag_drop_payload()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Clipping ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.push_clip_rect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect)&amp;lt;/code&amp;gt; || push a manual clipping rectangle (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt; corners) for subsequent drawing || &amp;lt;code&amp;gt;mxw_imgui.push_clip_rect(p_min, p_max, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.pop_clip_rect()&amp;lt;/code&amp;gt; || pop the pushed clip rect || &amp;lt;code&amp;gt;mxw_imgui.pop_clip_rect()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Focus &amp;amp;amp; activation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_item_default_focus()&amp;lt;/code&amp;gt; || make the last item the one focused by default when the panel first appears || &amp;lt;code&amp;gt;mxw_imgui.set_item_default_focus()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_keyboard_focus_here(offset = 0)&amp;lt;/code&amp;gt; || focus the next widget for keyboard input (e.g. auto-focus a text field) || &amp;lt;code&amp;gt;mxw_imgui.set_keyboard_focus_here()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Item / widgets utilities ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_hovered(flags = 0)&amp;lt;/code&amp;gt; || returns whether the last item is hovered by the mouse || &amp;lt;code&amp;gt;if mxw_imgui.is_item_hovered(): mxw_imgui.set_tooltip(&amp;quot;info&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_active()&amp;lt;/code&amp;gt; || returns whether the last item is currently active (e.g. being held/edited) || &amp;lt;code&amp;gt;active = mxw_imgui.is_item_active()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_focused()&amp;lt;/code&amp;gt; || returns whether the last item has keyboard focus || &amp;lt;code&amp;gt;focused = mxw_imgui.is_item_focused()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_clicked(mouse_button = 0)&amp;lt;/code&amp;gt; || returns whether the last item was clicked this frame || &amp;lt;code&amp;gt;if mxw_imgui.is_item_clicked(): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_visible()&amp;lt;/code&amp;gt; || returns whether the last item is visible (not clipped) || &amp;lt;code&amp;gt;visible = mxw_imgui.is_item_visible()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_edited()&amp;lt;/code&amp;gt; || returns whether the last item&#039;s value changed this frame || &amp;lt;code&amp;gt;edited = mxw_imgui.is_item_edited()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_activated()&amp;lt;/code&amp;gt; || returns whether the last item just became active this frame || &amp;lt;code&amp;gt;started = mxw_imgui.is_item_activated()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_deactivated()&amp;lt;/code&amp;gt; || returns whether the last item just stopped being active this frame || &amp;lt;code&amp;gt;stopped = mxw_imgui.is_item_deactivated()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_deactivated_after_edit()&amp;lt;/code&amp;gt; || returns whether the last item stopped being active after its value changed (e.g. commit-on-release) || &amp;lt;code&amp;gt;if mxw_imgui.is_item_deactivated_after_edit(): save()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_item_toggled_open()&amp;lt;/code&amp;gt; || returns whether the last tree node/collapsing header was just opened or closed || &amp;lt;code&amp;gt;toggled = mxw_imgui.is_item_toggled_open()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_any_item_hovered()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.is_any_item_active()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.is_any_item_focused()&amp;lt;/code&amp;gt; || returns whether any item at all is hovered/active/focused || &amp;lt;code&amp;gt;busy = mxw_imgui.is_any_item_active()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_item_rect_min()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.get_item_rect_max()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.get_item_rect_size()&amp;lt;/code&amp;gt; || returns the last item&#039;s bounding rectangle (screen-space corners, or size) || &amp;lt;code&amp;gt;size = mxw_imgui.get_item_rect_size()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_item_allow_overlap()&amp;lt;/code&amp;gt; || allow the next widget to visually overlap the last item without stealing its hover/click || &amp;lt;code&amp;gt;mxw_imgui.set_item_allow_overlap()&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Viewport &amp;amp;amp; miscellaneous ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_main_viewport()&amp;lt;/code&amp;gt; || returns the main viewport object (position/size of the whole application) || &amp;lt;code&amp;gt;vp = mxw_imgui.get_main_viewport()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_rect_visible(size)&amp;lt;/code&amp;gt; OR &amp;lt;code&amp;gt;mxw_imgui.is_rect_visible(rect_min, rect_max)&amp;lt;/code&amp;gt; || returns whether a rectangle at the cursor (or explicit corners) is visible/unclipped || &amp;lt;code&amp;gt;visible = mxw_imgui.is_rect_visible(mxw_imgui.Vec2(50,50))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_time()&amp;lt;/code&amp;gt; || returns Dear ImGui&#039;s internal time in seconds (accumulates while the app runs) || &amp;lt;code&amp;gt;t = mxw_imgui.get_time()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_frame_count()&amp;lt;/code&amp;gt; || returns the number of ImGui frames rendered so far || &amp;lt;code&amp;gt;n = mxw_imgui.get_frame_count()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_background_draw_list()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.get_foreground_draw_list()&amp;lt;/code&amp;gt; || returns the draw list rendered behind/in front of all windows, for custom drawing || &amp;lt;code&amp;gt;dl = mxw_imgui.get_foreground_draw_list()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_draw_list_shared_data()&amp;lt;/code&amp;gt; || returns data shared across draw lists (font atlas, clip rect stack, ...), rarely needed from Python || &amp;lt;code&amp;gt;d = mxw_imgui.get_draw_list_shared_data()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_state_storage(storage)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.get_state_storage()&amp;lt;/code&amp;gt; || set/get the key-value storage backing tree/collapsing-header open states || &amp;lt;code&amp;gt;s = mxw_imgui.get_state_storage()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_child_frame(id, size, flags = 0)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_child_frame()&amp;lt;/code&amp;gt; || a framed, scrollable child region (styled like a text/list box) || &amp;lt;code&amp;gt;if mxw_imgui.begin_child_frame(1, mxw_imgui.Vec2(0,100)): mxw_imgui.end_child_frame()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.calc_text_size(text, text_end = None, hide_text_after_double_hash = false, wrap_width = -1.0)&amp;lt;/code&amp;gt; || returns the pixel size a string would occupy with the current font || &amp;lt;code&amp;gt;w = mxw_imgui.calc_text_size(&amp;quot;0&amp;quot;).x&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Color utilities ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_convert_u32_to_float4(in)&amp;lt;/code&amp;gt; || convert a packed &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt; color to a &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;col = mxw_imgui.color_convert_u32_to_float4(0xFFFFFFFF)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_convert_float4_to_u32(in)&amp;lt;/code&amp;gt; || convert a &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt; color to a packed &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;u = mxw_imgui.color_convert_float4_to_u32(mxw_imgui.Vec4(1,1,1,1))&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_convert_rg_bto_hsv(r, g, b)&amp;lt;/code&amp;gt; || returns &amp;lt;code&amp;gt;(h, s, v)&amp;lt;/code&amp;gt; for the given RGB floats (0.0..1.0) || &amp;lt;code&amp;gt;h, s, v = mxw_imgui.color_convert_rg_bto_hsv(1.0, 0.0, 0.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.color_convert_hs_vto_rgb(h, s, v)&amp;lt;/code&amp;gt; || returns &amp;lt;code&amp;gt;(r, g, b)&amp;lt;/code&amp;gt; for the given HSV floats (0.0..1.0) || &amp;lt;code&amp;gt;r, g, b = mxw_imgui.color_convert_hs_vto_rgb(0.0, 1.0, 1.0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Keyboard input ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_key_index(imgui_key)&amp;lt;/code&amp;gt; || map a Dear ImGui &amp;lt;code&amp;gt;ImGuiKey_*&amp;lt;/code&amp;gt; value to the user&#039;s backend key index || &amp;lt;code&amp;gt;idx = mxw_imgui.get_key_index(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_key_down(user_key_index)&amp;lt;/code&amp;gt; || returns whether a key is currently held down || &amp;lt;code&amp;gt;held = mxw_imgui.is_key_down(idx)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_key_pressed(user_key_index, repeat = true)&amp;lt;/code&amp;gt; || returns whether a key was just pressed (optionally auto-repeating while held) || &amp;lt;code&amp;gt;if mxw_imgui.is_key_pressed(idx): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_key_released(user_key_index)&amp;lt;/code&amp;gt; || returns whether a key was just released || &amp;lt;code&amp;gt;if mxw_imgui.is_key_released(idx): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_key_pressed_amount(key_index, repeat_delay, rate)&amp;lt;/code&amp;gt; || returns how many times a key auto-repeated this frame, given a delay/rate || &amp;lt;code&amp;gt;n = mxw_imgui.get_key_pressed_amount(idx, 0.3, 0.1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Mouse input ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_down(button)&amp;lt;/code&amp;gt; || returns whether a mouse button is currently held (0=left,1=right,2=middle) || &amp;lt;code&amp;gt;held = mxw_imgui.is_mouse_down(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_clicked(button, repeat = false)&amp;lt;/code&amp;gt; || returns whether a mouse button was just clicked || &amp;lt;code&amp;gt;if mxw_imgui.is_mouse_clicked(0): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_released(button)&amp;lt;/code&amp;gt; || returns whether a mouse button was just released || &amp;lt;code&amp;gt;if mxw_imgui.is_mouse_released(0): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_double_clicked(button)&amp;lt;/code&amp;gt; || returns whether a mouse button was just double-clicked || &amp;lt;code&amp;gt;if mxw_imgui.is_mouse_double_clicked(0): pass&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_hovering_rect(r_min, r_max, clip = true)&amp;lt;/code&amp;gt; || returns whether the mouse is over the given screen-space rectangle || &amp;lt;code&amp;gt;over = mxw_imgui.is_mouse_hovering_rect(p_min, p_max)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_pos_valid(mouse_pos = None)&amp;lt;/code&amp;gt; || returns whether the (current or given) mouse position is valid (app has focus etc.) || &amp;lt;code&amp;gt;valid = mxw_imgui.is_mouse_pos_valid()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_any_mouse_down()&amp;lt;/code&amp;gt; || returns whether any mouse button is currently held || &amp;lt;code&amp;gt;held = mxw_imgui.is_any_mouse_down()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_mouse_pos()&amp;lt;/code&amp;gt; || returns the current mouse position (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;, screen-space) || &amp;lt;code&amp;gt;p = mxw_imgui.get_mouse_pos()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_mouse_pos_on_opening_current_popup()&amp;lt;/code&amp;gt; || returns the mouse position captured when the current popup was opened || &amp;lt;code&amp;gt;p = mxw_imgui.get_mouse_pos_on_opening_current_popup()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.is_mouse_dragging(button, lock_threshold = -1.0)&amp;lt;/code&amp;gt; || returns whether the mouse is dragging with the given button held || &amp;lt;code&amp;gt;dragging = mxw_imgui.is_mouse_dragging(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_mouse_drag_delta(button = 0, lock_threshold = -1.0)&amp;lt;/code&amp;gt; || returns the drag distance (&amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;) since the drag started || &amp;lt;code&amp;gt;d = mxw_imgui.get_mouse_drag_delta()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.reset_mouse_drag_delta(button = 0)&amp;lt;/code&amp;gt; || reset the tracked drag distance for a button || &amp;lt;code&amp;gt;mxw_imgui.reset_mouse_drag_delta()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_mouse_cursor()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.set_mouse_cursor(cursor_type)&amp;lt;/code&amp;gt; || get/set the desired OS mouse cursor shape || &amp;lt;code&amp;gt;mxw_imgui.set_mouse_cursor(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Clipboard ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.get_clipboard_text()&amp;lt;/code&amp;gt; || returns the current OS clipboard text || &amp;lt;code&amp;gt;txt = mxw_imgui.get_clipboard_text()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.set_clipboard_text(text)&amp;lt;/code&amp;gt; || set the OS clipboard text || &amp;lt;code&amp;gt;mxw_imgui.set_clipboard_text(&amp;quot;copied value&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Disabled blocks &amp;amp;amp; MXWendler extras ===&lt;br /&gt;
The last two functions are MXWendler additions, not part of stock Dear ImGui bindings.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! PYTHON COMMAND/SYMBOL !! DESCRIPTION !! EXAMPLE&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.begin_disabled(disabled = false)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;mxw_imgui.end_disabled()&amp;lt;/code&amp;gt; || grey out and block interaction with all widgets in between || &amp;lt;code&amp;gt;mxw_imgui.begin_disabled(not enabled); mxw_imgui.button(&amp;quot;Go&amp;quot;); mxw_imgui.end_disabled()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;mxw_imgui.render_frame(p_min, p_max, colf, border = true, rounding = 0.0)&amp;lt;/code&amp;gt; || draw a filled/bordered rectangle (screen-space corners as &amp;lt;code&amp;gt;Vec2&amp;lt;/code&amp;gt;, color as &amp;lt;code&amp;gt;Vec4&amp;lt;/code&amp;gt;) directly, e.g. for custom backgrounds || &amp;lt;code&amp;gt;mxw_imgui.render_frame(mxw_imgui.Vec2(0,0), mxw_imgui.Vec2(100,20), mxw_imgui.Vec4(0.2,0.2,0.2,1))&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
[[Category:Python]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Tutorial_Eventmaster_Toolset_Controlling_MXWendler_by_e.g._e2_S3_Image_Processor&amp;diff=6176</id>
		<title>Tutorial Eventmaster Toolset Controlling MXWendler by e.g. e2 S3 Image Processor</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Tutorial_Eventmaster_Toolset_Controlling_MXWendler_by_e.g._e2_S3_Image_Processor&amp;diff=6176"/>
		<updated>2026-08-08T15:41:17Z</updated>

		<summary type="html">&lt;p&gt;Admin: Update link after renaming to &amp;#039;OSC command reference&amp;#039; (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial applies to all different OS and MXWendler versions &amp;gt; 6.0.04&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
This tutorial explains how to set up a Barco Eventmaster to trigger and control media playback on StageDesigner or FXServer.&lt;br /&gt;
&lt;br /&gt;
==Control Setup==&lt;br /&gt;
&lt;br /&gt;
1. Open SD (StageDesigner) and load a clip into preload 1:&lt;br /&gt;
&lt;br /&gt;
[[File:e2_01.png|600px]]&lt;br /&gt;
&lt;br /&gt;
2. Open Settings-&amp;gt;IO-&amp;gt;Barco e2 and activate TCP listening. Also note down the port number.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_02.png|600px]]&lt;br /&gt;
&lt;br /&gt;
3. In the Barco Eventmaster Toolset, create an &#039;External Device&#039;, name it e.g. &#039;StageDesigner&#039;.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_03.png|600px]]&lt;br /&gt;
&lt;br /&gt;
4. In the &#039;Adjust: StageDesigner&#039; tab, set IP address and port number.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_04.png|600px]]&lt;br /&gt;
&lt;br /&gt;
5. In the &#039;Adjust: StageDesigner&#039; tab, add a new command. Store the command content, e.g.&lt;br /&gt;
* /mxw/preload/1 play to start a clip&lt;br /&gt;
* /mxw/preload/1 play to stop a clip&lt;br /&gt;
&lt;br /&gt;
More possible commands are in the OSC control section: [[OSC command reference]]&lt;br /&gt;
&lt;br /&gt;
[[File:e2_05.png|600px]]&lt;br /&gt;
&lt;br /&gt;
6. In the &#039;Cue&#039; section, add a cue.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_06.png|600px]]&lt;br /&gt;
&lt;br /&gt;
7. In this &#039;Cue&#039;, add actions.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_07.png|600px]]&lt;br /&gt;
&lt;br /&gt;
8. From &#039;External Devices&#039; drop an available command onto the &#039;Commands&#039; field of the action.&lt;br /&gt;
&lt;br /&gt;
[[File:e2_08c.png|600px]]&lt;br /&gt;
&lt;br /&gt;
9. Play this cue, a clip should be started in the StageDesigner&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6175</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6175"/>
		<updated>2026-08-08T15:40:47Z</updated>

		<summary type="html">&lt;p&gt;Admin: Update link after renaming to &amp;#039;OSC command reference&amp;#039; (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[1. Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;1.1 Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;1.2 Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[2. MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.1 Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.2 Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[4. Practical examples: Pure Data and TouchOSC]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;4.1 Install Pure Data&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;4.2 MXW Pd Patch&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 0px&amp;quot; | &#039;&#039;4.3 OSC for portable Devices: TouchOSC and Protokol&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[5. Troubleshooting]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[6. External links]]&lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_command_reference&amp;diff=6173</id>
		<title>OSC command reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_command_reference&amp;diff=6173"/>
		<updated>2026-08-08T15:40:46Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin moved page MXW OSC command reference to OSC command reference: Rename: omit &amp;#039;MXW&amp;#039; prefix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are listed all the commands that MXW recognizes.&lt;br /&gt;
&lt;br /&gt;
=== Legend ===&lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
==== Variables ====&lt;br /&gt;
When variables are found in the address of a command ( and not only as the value to be sent), the &amp;lt;code&amp;gt;$+index&amp;lt;/code&amp;gt; notation has been employed :&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/$1 [value]  &amp;lt;/code&amp;gt; indicates that a variable  &amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt; has to be chosen and will specify the correct address where the value will be sent.&amp;lt;br&amp;gt;If the goal is, for example, to reduce of 50% the opacity of the 2nd track, the correct command would be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/2 0.5 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Values ====&lt;br /&gt;
The standard used to represent the available values for each command (column “RANGE or TOKEN”) is:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FLOATS&#039;&#039; are represented with one decimal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; &amp;amp;rarr; all float values between 0 and 1 included&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;INTEGERS&#039;&#039; are represented with numbers or descriptions:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;1 .. 5&amp;lt;/code&amp;gt; &amp;amp;rarr; all integers between 1 and 5 included ( 1 , 2 , 3 , 4 , 5 ) &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;1 .. (MAX n layers)&amp;lt;/code&amp;gt; &amp;amp;rarr; all the integers between 1 and the maximum index of layers in MXW (e.g. if 6 layers are being used the values are integers between 1 and 6 included)&lt;br /&gt;
&lt;br /&gt;
When only one number is indicated it means that only one option is given. This is found in addresses of buttons, checkboxes and in the options where &amp;quot;0&amp;quot; or &amp;quot;1&amp;quot; are the only significant values&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;STRINGS&#039;&#039; are represented between quotation marks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;“info”&amp;lt;/code&amp;gt; means that the string info has to be used at the end of the command&lt;br /&gt;
&lt;br /&gt;
E.G.  to ask for information about the patches the command&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set info &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be sent.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;“name”&amp;lt;/code&amp;gt; is contained in the available string variable, then the content is to be substituted with the actual name.&lt;br /&gt;
 &lt;br /&gt;
E.G. :  to select and play a patch called “patch_one” from its name, the address &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt; with tokens &amp;lt;code&amp;gt;&amp;quot;play&amp;quot; &amp;quot;name_of_patch&amp;quot;&amp;lt;/code&amp;gt; has to be used, resulting in this OSC command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set play patch_one&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; is found it means that two options can deliver a similar result. One of the two formats has to be used at one time.&lt;br /&gt;
&lt;br /&gt;
===Set Reference===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! OSC ADDRESS !! DESCRIPTION !! RANGE  or TOKEN&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt; /mxw/set&amp;lt;/code&amp;gt;||get information on the patches|| &amp;lt;code&amp;gt;“info”&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;||play a specific patch|| &amp;lt;code&amp;gt;“play” “name_of_patch”&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;||choose a patch|| &amp;lt;code&amp;gt;1 .. (MAX n patches)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/editor&amp;lt;/code&amp;gt;||choose UI tab|| &amp;lt;code&amp;gt;0 .. 5&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/trackmanager&amp;lt;/code&amp;gt;||choose active track || &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; &amp;lt;code&amp;gt;1 .. 4&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/trackmanager&amp;lt;/code&amp;gt;||clear all tracks || &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/layermanager&amp;lt;/code&amp;gt; ||choose active layer || &amp;lt;code&amp;gt;1 .. (MAX n layers)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/layermanager&amp;lt;/code&amp;gt;||clear layers in active track|| &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/beatbutton&amp;lt;/code&amp;gt; || Send pulse to beat-button (BPM)|| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist info&amp;lt;/code&amp;gt; || return information on the state of the playback of playlist|| &amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist select&amp;lt;/code&amp;gt; || jump to cue by name || &amp;lt;code&amp;gt;&amp;quot;select&amp;quot; &amp;quot;cuename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotostart&amp;lt;/code&amp;gt; || stop and go to first track on list&amp;lt;ref&amp;gt;The functionality of &#039;&#039;gotostart&#039;&#039; is the same as the &#039;&#039;gotostart&#039;&#039; button in the MXW playlist GUI ( ❙❙◀ ),  so the command has to be sent two times to reset the playlist at the original state.&amp;lt;/ref&amp;gt;|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotoprev&amp;lt;/code&amp;gt; || go to previous cue|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/play&amp;lt;/code&amp;gt; || play active item|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/pause&amp;lt;/code&amp;gt; || pause active playing clip|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotonext&amp;lt;/code&amp;gt; || go to next cue|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotocueandplay&amp;lt;/code&amp;gt; || go to  a specific cue and immediately play|| &amp;lt;code&amp;gt;0..n (MAX n rows)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotocue&amp;lt;/code&amp;gt; || go to a specific cue|| &amp;lt;code&amp;gt;0..n (MAX n rows)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/container/active&amp;lt;/code&amp;gt; || info about the total playlist container|| &amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/container/active/column/$1/row/$2&amp;lt;/code&amp;gt; || info about the selected field in the playlist grid|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. (MAX n columns)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;$2 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n rows)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/first&amp;lt;/code&amp;gt; || go to first patch on the list|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/prev&amp;lt;/code&amp;gt; || select the previous patch || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/play&amp;lt;/code&amp;gt; || play selected patch &amp;lt;ref&amp;gt;The button play in the patch tab works like the play button in the MXW playlist GUI, every click will play the following patch.&amp;lt;/ref&amp;gt;|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/next&amp;lt;/code&amp;gt;|| select to next patch|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;|| clear all patches || &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render&amp;lt;/code&amp;gt;|| change of render opacity|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/opacity&amp;lt;/code&amp;gt;|| change of render opacity|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/scale&amp;lt;/code&amp;gt;|| change of render scale|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/scalexy&amp;lt;/code&amp;gt;|| change of render scale ratio|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/translationx&amp;lt;/code&amp;gt;|| change of render position x|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/translationy&amp;lt;/code&amp;gt;|| change of render position y|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/rotation&amp;lt;/code&amp;gt;|| change of render rotation|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/reset&amp;lt;/code&amp;gt;|| reset render changes|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/effect&amp;lt;/code&amp;gt;|| selects wished render fx|| &amp;lt;code&amp;gt;1 .. (MAX n fx) &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/effect/1/param/$1 &amp;lt;/code&amp;gt;|| modifies value of one parameter($1) of the render fx|| $1&amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n parameters)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/$1&amp;lt;/code&amp;gt;|| set opacity value of a specific track ($1)|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. 4&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active&amp;lt;/code&amp;gt;|| change opacity of active track moving the fader|| &amp;lt;code&amp;gt;0.0 .. 1.0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/fader&amp;lt;/code&amp;gt;|| change opacity of active track moving the fader|| &amp;lt;code&amp;gt;0.0 .. 1.0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/crossfader&amp;lt;/code&amp;gt;|| activates the crossfading between tracks|| &amp;lt;code&amp;gt;0.0 (OFF) &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 1.0 (ON)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/mode&amp;lt;/code&amp;gt;|| changes the mode of fading|| &amp;lt;code&amp;gt;1 .. 8&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/preload/$1/trigger&amp;lt;/code&amp;gt;|| trigger preload $1 content to current track|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n preloads)&amp;lt;/code&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/preload/$1/flipflop&amp;lt;/code&amp;gt;|| flipflop preload $1 content to current track|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n preloads)&amp;lt;/code&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/play&amp;lt;/code&amp;gt; || toggles play-pause button of live editor || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/scale&amp;lt;/code&amp;gt; || change of layer scale || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/scalexy&amp;lt;/code&amp;gt; || change of layer scale ratio || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/translationx&amp;lt;/code&amp;gt; || change of layer position x || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/translationy&amp;lt;/code&amp;gt; || change of layer position y || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/rotation&amp;lt;/code&amp;gt; || change of layer rotation || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/mode&amp;lt;/code&amp;gt; || change of layer blend mode || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/aspectmode&amp;lt;/code&amp;gt; || change of layer aspect mode || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/reset&amp;lt;/code&amp;gt; || reset layer changes || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/keyin&amp;lt;/code&amp;gt; || set keyin of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/keyout&amp;lt;/code&amp;gt; || set keyout of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/speed&amp;lt;/code&amp;gt; || set speed of clip of active layer &amp;lt;ref&amp;gt; The values are sent to the &amp;quot;speed fader&amp;quot;, which values go between 5 and -5, they do not act directly on the &amp;quot;speed value&amp;quot;. This means that depending on the active media the available values in the fader will differ. &amp;lt;/ref&amp;gt; || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/position&amp;lt;/code&amp;gt; || set position of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/mode&amp;lt;/code&amp;gt; ||  set mode of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect&amp;lt;/code&amp;gt; || choose active effect || &amp;lt;code&amp;gt;0 .. (MAX n of fx)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effectbank&amp;lt;/code&amp;gt; || selects active effect || &amp;lt;code&amp;gt;0 .. (MAX n of fx)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/active/param/$1&amp;lt;/code&amp;gt; || set param $1 of effect || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/red&amp;lt;/code&amp;gt; || set red component of color param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/green&amp;lt;/code&amp;gt; || set green component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/blue&amp;lt;/code&amp;gt; || set blue component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/hue&amp;lt;/code&amp;gt; || set huecomponent param.  || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/saturation&amp;lt;/code&amp;gt; || set saturation | &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/value&amp;lt;/code&amp;gt; || set value component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone/element/$1/pivot/col/$2/row/$3/xposition&amp;lt;/code&amp;gt; || move keystone pivot in x || $1 &amp;amp;rarr;  &amp;lt;code&amp;gt;1 .. (MAX n elements)&amp;lt;/code&amp;gt;&lt;br /&gt;
$2 (COLUMN) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
$3 (ROW) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone/element/$1/pivot/col/$2/row/$3/yposition&amp;lt;/code&amp;gt; || move keystone pivot in y|| $1 &amp;amp;rarr;  &amp;lt;code&amp;gt;1 .. (MAX n elements)&amp;lt;/code&amp;gt;&lt;br /&gt;
$2 (COLUMN) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
$3 (ROW) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone_io_animator&amp;lt;/code&amp;gt; || keystone io animator fader|| &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=Category:OSC&amp;diff=6172</id>
		<title>Category:OSC</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=Category:OSC&amp;diff=6172"/>
		<updated>2026-08-08T15:36:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: Create category page (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages documenting how to control MXWendler through the Open Sound Control (OSC) protocol.&lt;br /&gt;
&lt;br /&gt;
The list below is generated automatically from pages tagged &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[Category:OSC]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_command_reference&amp;diff=6171</id>
		<title>OSC command reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_command_reference&amp;diff=6171"/>
		<updated>2026-08-08T15:36:00Z</updated>

		<summary type="html">&lt;p&gt;Admin: Add Category:OSC at page end (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are listed all the commands that MXW recognizes.&lt;br /&gt;
&lt;br /&gt;
=== Legend ===&lt;br /&gt;
&amp;lt;div&amp;gt; &lt;br /&gt;
==== Variables ====&lt;br /&gt;
When variables are found in the address of a command ( and not only as the value to be sent), the &amp;lt;code&amp;gt;$+index&amp;lt;/code&amp;gt; notation has been employed :&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/$1 [value]  &amp;lt;/code&amp;gt; indicates that a variable  &amp;lt;code&amp;gt;$1&amp;lt;/code&amp;gt; has to be chosen and will specify the correct address where the value will be sent.&amp;lt;br&amp;gt;If the goal is, for example, to reduce of 50% the opacity of the 2nd track, the correct command would be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/track/2 0.5 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Values ====&lt;br /&gt;
The standard used to represent the available values for each command (column “RANGE or TOKEN”) is:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;FLOATS&#039;&#039; are represented with one decimal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; &amp;amp;rarr; all float values between 0 and 1 included&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;INTEGERS&#039;&#039; are represented with numbers or descriptions:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;1 .. 5&amp;lt;/code&amp;gt; &amp;amp;rarr; all integers between 1 and 5 included ( 1 , 2 , 3 , 4 , 5 ) &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;1 .. (MAX n layers)&amp;lt;/code&amp;gt; &amp;amp;rarr; all the integers between 1 and the maximum index of layers in MXW (e.g. if 6 layers are being used the values are integers between 1 and 6 included)&lt;br /&gt;
&lt;br /&gt;
When only one number is indicated it means that only one option is given. This is found in addresses of buttons, checkboxes and in the options where &amp;quot;0&amp;quot; or &amp;quot;1&amp;quot; are the only significant values&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;STRINGS&#039;&#039; are represented between quotation marks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;“info”&amp;lt;/code&amp;gt; means that the string info has to be used at the end of the command&lt;br /&gt;
&lt;br /&gt;
E.G.  to ask for information about the patches the command&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set info &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be sent.&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;“name”&amp;lt;/code&amp;gt; is contained in the available string variable, then the content is to be substituted with the actual name.&lt;br /&gt;
 &lt;br /&gt;
E.G. :  to select and play a patch called “patch_one” from its name, the address &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt; with tokens &amp;lt;code&amp;gt;&amp;quot;play&amp;quot; &amp;quot;name_of_patch&amp;quot;&amp;lt;/code&amp;gt; has to be used, resulting in this OSC command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/mxw/set play patch_one&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; is found it means that two options can deliver a similar result. One of the two formats has to be used at one time.&lt;br /&gt;
&lt;br /&gt;
===Set Reference===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! OSC ADDRESS !! DESCRIPTION !! RANGE  or TOKEN&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt; /mxw/set&amp;lt;/code&amp;gt;||get information on the patches|| &amp;lt;code&amp;gt;“info”&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;||play a specific patch|| &amp;lt;code&amp;gt;“play” “name_of_patch”&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;||choose a patch|| &amp;lt;code&amp;gt;1 .. (MAX n patches)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/editor&amp;lt;/code&amp;gt;||choose UI tab|| &amp;lt;code&amp;gt;0 .. 5&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/trackmanager&amp;lt;/code&amp;gt;||choose active track || &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt; &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; &amp;lt;code&amp;gt;1 .. 4&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/trackmanager&amp;lt;/code&amp;gt;||clear all tracks || &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/layermanager&amp;lt;/code&amp;gt; ||choose active layer || &amp;lt;code&amp;gt;1 .. (MAX n layers)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/layermanager&amp;lt;/code&amp;gt;||clear layers in active track|| &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/beatbutton&amp;lt;/code&amp;gt; || Send pulse to beat-button (BPM)|| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist info&amp;lt;/code&amp;gt; || return information on the state of the playback of playlist|| &amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist select&amp;lt;/code&amp;gt; || jump to cue by name || &amp;lt;code&amp;gt;&amp;quot;select&amp;quot; &amp;quot;cuename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotostart&amp;lt;/code&amp;gt; || stop and go to first track on list&amp;lt;ref&amp;gt;The functionality of &#039;&#039;gotostart&#039;&#039; is the same as the &#039;&#039;gotostart&#039;&#039; button in the MXW playlist GUI ( ❙❙◀ ),  so the command has to be sent two times to reset the playlist at the original state.&amp;lt;/ref&amp;gt;|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotoprev&amp;lt;/code&amp;gt; || go to previous cue|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/play&amp;lt;/code&amp;gt; || play active item|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/pause&amp;lt;/code&amp;gt; || pause active playing clip|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotonext&amp;lt;/code&amp;gt; || go to next cue|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotocueandplay&amp;lt;/code&amp;gt; || go to  a specific cue and immediately play|| &amp;lt;code&amp;gt;0..n (MAX n rows)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/gotocue&amp;lt;/code&amp;gt; || go to a specific cue|| &amp;lt;code&amp;gt;0..n (MAX n rows)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/container/active&amp;lt;/code&amp;gt; || info about the total playlist container|| &amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/playlist/container/active/column/$1/row/$2&amp;lt;/code&amp;gt; || info about the selected field in the playlist grid|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. (MAX n columns)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;$2 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n rows)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;quot;info&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/first&amp;lt;/code&amp;gt; || go to first patch on the list|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/prev&amp;lt;/code&amp;gt; || select the previous patch || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/play&amp;lt;/code&amp;gt; || play selected patch &amp;lt;ref&amp;gt;The button play in the patch tab works like the play button in the MXW playlist GUI, every click will play the following patch.&amp;lt;/ref&amp;gt;|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set/next&amp;lt;/code&amp;gt;|| select to next patch|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/set&amp;lt;/code&amp;gt;|| clear all patches || &amp;lt;code&amp;gt;&amp;quot;clear&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render&amp;lt;/code&amp;gt;|| change of render opacity|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/opacity&amp;lt;/code&amp;gt;|| change of render opacity|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/scale&amp;lt;/code&amp;gt;|| change of render scale|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/scalexy&amp;lt;/code&amp;gt;|| change of render scale ratio|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/translationx&amp;lt;/code&amp;gt;|| change of render position x|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/translationy&amp;lt;/code&amp;gt;|| change of render position y|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/rotation&amp;lt;/code&amp;gt;|| change of render rotation|| &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/reset&amp;lt;/code&amp;gt;|| reset render changes|| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/effect&amp;lt;/code&amp;gt;|| selects wished render fx|| &amp;lt;code&amp;gt;1 .. (MAX n fx) &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/render/effect/1/param/$1 &amp;lt;/code&amp;gt;|| modifies value of one parameter($1) of the render fx|| $1&amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n parameters)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/$1&amp;lt;/code&amp;gt;|| set opacity value of a specific track ($1)|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. 4&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0.0 .. 1.0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active&amp;lt;/code&amp;gt;|| change opacity of active track moving the fader|| &amp;lt;code&amp;gt;0.0 .. 1.0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/fader&amp;lt;/code&amp;gt;|| change opacity of active track moving the fader|| &amp;lt;code&amp;gt;0.0 .. 1.0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/crossfader&amp;lt;/code&amp;gt;|| activates the crossfading between tracks|| &amp;lt;code&amp;gt;0.0 (OFF) &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 1.0 (ON)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/mode&amp;lt;/code&amp;gt;|| changes the mode of fading|| &amp;lt;code&amp;gt;1 .. 8&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/preload/$1/trigger&amp;lt;/code&amp;gt;|| trigger preload $1 content to current track|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n preloads)&amp;lt;/code&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/preload/$1/flipflop&amp;lt;/code&amp;gt;|| flipflop preload $1 content to current track|| $1 &amp;amp;rarr; &amp;lt;code&amp;gt;1 .. (MAX n preloads)&amp;lt;/code&amp;gt; &lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/play&amp;lt;/code&amp;gt; || toggles play-pause button of live editor || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/scale&amp;lt;/code&amp;gt; || change of layer scale || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/scalexy&amp;lt;/code&amp;gt; || change of layer scale ratio || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/translationx&amp;lt;/code&amp;gt; || change of layer position x || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/translationy&amp;lt;/code&amp;gt; || change of layer position y || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/rotation&amp;lt;/code&amp;gt; || change of layer rotation || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/mode&amp;lt;/code&amp;gt; || change of layer blend mode || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/aspectmode&amp;lt;/code&amp;gt; || change of layer aspect mode || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/reset&amp;lt;/code&amp;gt; || reset layer changes || &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/keyin&amp;lt;/code&amp;gt; || set keyin of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/keyout&amp;lt;/code&amp;gt; || set keyout of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/speed&amp;lt;/code&amp;gt; || set speed of clip of active layer &amp;lt;ref&amp;gt; The values are sent to the &amp;quot;speed fader&amp;quot;, which values go between 5 and -5, they do not act directly on the &amp;quot;speed value&amp;quot;. This means that depending on the active media the available values in the fader will differ. &amp;lt;/ref&amp;gt; || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/position&amp;lt;/code&amp;gt; || set position of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/mode&amp;lt;/code&amp;gt; ||  set mode of clip of active layer || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect&amp;lt;/code&amp;gt; || choose active effect || &amp;lt;code&amp;gt;0 .. (MAX n of fx)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effectbank&amp;lt;/code&amp;gt; || selects active effect || &amp;lt;code&amp;gt;0 .. (MAX n of fx)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/active/param/$1&amp;lt;/code&amp;gt; || set param $1 of effect || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/red&amp;lt;/code&amp;gt; || set red component of color param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/green&amp;lt;/code&amp;gt; || set green component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/blue&amp;lt;/code&amp;gt; || set blue component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/hue&amp;lt;/code&amp;gt; || set huecomponent param.  || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/saturation&amp;lt;/code&amp;gt; || set saturation | &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/track/active/layer/active/clip/effect/1/color/1/value&amp;lt;/code&amp;gt; || set value component param. || &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone/element/$1/pivot/col/$2/row/$3/xposition&amp;lt;/code&amp;gt; || move keystone pivot in x || $1 &amp;amp;rarr;  &amp;lt;code&amp;gt;1 .. (MAX n elements)&amp;lt;/code&amp;gt;&lt;br /&gt;
$2 (COLUMN) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
$3 (ROW) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone/element/$1/pivot/col/$2/row/$3/yposition&amp;lt;/code&amp;gt; || move keystone pivot in y|| $1 &amp;amp;rarr;  &amp;lt;code&amp;gt;1 .. (MAX n elements)&amp;lt;/code&amp;gt;&lt;br /&gt;
$2 (COLUMN) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
$3 (ROW) &amp;amp;rarr; &amp;lt;code&amp;gt;1 &amp;lt;u&amp;gt;OR&amp;lt;/u&amp;gt; 2&amp;lt;/code&amp;gt;&lt;br /&gt;
VALUE &amp;amp;rarr; &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/mxw/keystone_io_animator&amp;lt;/code&amp;gt; || keystone io animator fader|| &amp;lt;code&amp;gt;0 .. 1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6170</id>
		<title>OSC Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.mxwendler.net/index.php?title=OSC_Reference&amp;diff=6170"/>
		<updated>2026-08-08T15:35:58Z</updated>

		<summary type="html">&lt;p&gt;Admin: Add Category:OSC at page end (bot)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This reference applies to all different OS. The presented OSC commands are for most part supported in version 6.0 but will be fully functional in version 6.0.08 and above. &lt;br /&gt;
&amp;lt;div class=&amp;quot;noprint&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This document describes the MXWendler (MXW) OSC Command Interface through an overview of the command structure and practical examples of integration with external controlling software. &lt;br /&gt;
&lt;br /&gt;
== What is OSC? ==&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
OSC or „Open Sound Control“ is a Network-based protocol that commonly utilizes the UDP transport mechanism. Originally developed as a successor of the MIDI control protocol, it used nowadays as a practical communication method between platforms.&lt;br /&gt;
&lt;br /&gt;
OSC Features:&lt;br /&gt;
* Connectionless communication architecture&lt;br /&gt;
* Broadcast-type messages&lt;br /&gt;
* High resolution time tag&lt;br /&gt;
* Allowed data formats including numeric, symbolic, and “blob” arguments&lt;br /&gt;
* Open-ended, dynamic, URL-style naming scheme for the receivers&#039; address&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
[https://en.wikipedia.org/wiki/Open_Sound_Control [1&amp;lt;nowiki&amp;gt;]&amp;lt;/nowiki&amp;gt; Wikipedia Link]&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px&amp;quot; | [[1. Controlling MXW through OSC]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;1.1 Receiving OSC commands in MXW&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 10px&amp;quot; | &#039;&#039;1.2 Output OSC from MXW: Send vs. Reply&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[2. MXW OSC command structure]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.1 Sending OSC Values&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;2.2 Examples&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[MXW OSC command reference]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 10px 0px&amp;quot; | [[4. Practical examples: Pure Data and TouchOSC]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;4.1 Install Pure Data&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px&amp;quot; | &#039;&#039;4.2 MXW Pd Patch&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 0px 30px 0px&amp;quot; | &#039;&#039;4.3 OSC for portable Devices: TouchOSC and Protokol&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:  10px&amp;quot; | [[5. Troubleshooting]] &lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 10px&amp;quot; | [[6. External links]]&lt;br /&gt;
|}&lt;br /&gt;
[[Category:OSC]]&lt;br /&gt;
[[Category:Reference]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>