ContentsPython: wildtrax

Python: wildtrax

Scripts that run inside WildTrax. The Python runtime ships with the app; nothing to install. To control WildTrax from another machine, use wildtrax_client instead.

from wildtrax import RecordingEngine, transport, metadata

print(RecordingEngine.isRecording)
metadata.scene("SC07")
transport.record()

Scripts

Folder ~/Library/Application Support/WildTrax 2027/scripts/
Files Every .py file in the folder appears in WildTrax's script list
Output print() goes to the Script Log panel
Thread Scripts run on the UI thread. Use QTimer for anything long-running.
Errors Exceptions are logged; they don't crash WildTrax
Access Scripts can do anything a normal program on your Mac can. Only run ones you trust.

Reads

Properties are read-only and always current. wildtrax.describe() prints everything available.

RecordingEngine

Property Signal
isRecording isRecordingChanged
timeCode doneReadingBuffer
recordingTimeCode doneReadingBuffer
freeRunning doneReadingBuffer
isPostRolling isPostRollingChanged
isFinalizing isFinalizingChanged
finalizingTake isFinalizingChanged
recordingDropped recordingDroppedChanged
statusBarMessage statusBarMessageChanged
postRollEnabled postRollEnabledChanged
postRollSeconds postRollSecondsChanged
autoAdvanceTake autoAdvanceTakeChanged

ProjectSettings

Property Signal
currentProjectPath currentProjectPathChanged
takeNamePattern takeNamePatternChanged
syncPointType syncPointTypeChanged
ltcOffsetMs ltcOffsetChanged
falseStartFolder falseStartFolderChanged
falseStartSuffix falseStartSuffixChanged

Methods: getRecentFiles() getLtcOffsetTimecode() msToTimecode(ms)

AudioTracks

Property Signal
trackCount tracksChanged
globalMonitor globalMonitorChanged
currentLTCChannel currentLTCChannelChanged

Methods: rowCount() getLTCInputChannelNames()

TimeConfig

Property Signal
currentTimeSource currentTimeSourceChanged

Methods: currentTimeSourceName() currentFrameRate() fps() isDropFrame() frameRates() timeSources()

Signals

RecordingEngine.isRecordingChanged.connect(lambda: print(RecordingEngine.isRecording))

.disconnect(fn) to stop. RecordingEngine.signal_for("timeCode") returns a property's signal name.

Commands

Same command path as OSC and HTTP. Indices are 1-based. Raises CommandError if WildTrax refuses the command.

Module Calls
transport record() stop() false_start() false_start_confirmed()
tracks arm(i, value=True) mute(i, value=True) monitor(i, value=True) pan(i, pan) name(i, name) add() remove(i) set_count(n)
metadata project(v) scene(v) slate(v) take(v) roll(v) note(v) add_marker() reset_next_to_default()
soundboard play(pad) stop(pad) set_title(pad, title)
playlist play() stop() set_loop(value=True) set_current_index(i)
raw send(action, **args) — any other action, args named as in the HTTP API bodies, e.g. raw.send("soundboardSetPadColor", padIndex=1, color="#ff0000")

pan: 0 left · 1 right · 2 center.

menu.py in the scripts folder runs at launch.

from wildtrax import menu

menu.add_command("Timecode Window", open_timecode_window)
menu.add_command("Tools/RMS vs Peak", open_rms_tool)   # "/" makes a submenu

Restart WildTrax to pick up changes. WILDTRAX_PATH (colon-separated) adds more folders to search for menu.py.

Windows

PySide6 is included, and scripts share WildTrax's Qt application.

from PySide6.QtWidgets import QDialog, QVBoxLayout, QLabel
from wildtrax import RecordingEngine

class Timecode(QDialog):
    def __init__(self):
        super().__init__()
        self.label = QLabel(RecordingEngine.timeCode)
        QVBoxLayout(self).addWidget(self.label)
        RecordingEngine.doneReadingBuffer.connect(
            lambda: self.label.setText(RecordingEngine.timeCode))

win = Timecode()
win.show()   # keep a reference; .exec() blocks WildTrax

Panels

A script can be a WildTrax panel instead of a window: it docks, tears out and saves with a project like any panel. Add PANEL = True, build a QWidget, and register it with wildtrax.panel. Header buttons are wildtrax.ToolbarButton.

PANEL = True               # lists the script in the Toolkit as a panel
ICON = "radio-tower"       # a bundled icon name, an emoji, or an image file

from PySide6.QtWidgets import QWidget, QVBoxLayout, QPlainTextEdit
import wildtrax

class Notes(QWidget):
    def __init__(self):
        super().__init__()
        self.text = QPlainTextEdit()
        QVBoxLayout(self).addWidget(self.text)
        # Buttons in the panel's header, drawn like every other panel's.
        self.toolbar = [
            wildtrax.ToolbarButton("eraser", "Clear", on_click=self.text.clear),
        ]

wildtrax.panel(Notes)      # a class, not an instance
Showing it Running the script opens its panel beside the frame you're in, or rebuilds it where it's already open
One per showing Each place the panel shows gets its own widget from the class
ToolbarButton ToolbarButton(icon, tooltip="", on_click=None, checkable=False, checked=False, enabled=True). Set enabled, checked, icon or tooltip any time and the header follows

Examples

WildTrax comes with a few Python tools in the Toolkit. Here is one of them in full: a big live timecode display that turns red while recording. Save it to your scripts folder as timecode_slate.py, and it appears in the Toolkit.

"""A big live timecode display that turns red while recording.

Doc's Mini Timecode Slate. Open it as a panel, tear it out onto a second
screen, or point a camera at it.

What this example shows:
  - reading live engine state (RecordingEngine.timeCode, .isRecording)
  - reacting to engine signals instead of polling
  - a script panel: a plain PySide widget that WildTrax shows as a panel
"""

# This line makes the script a panel; WildTrax reads it without running it.
PANEL = True
# The Toolkit tile icon: a bundled icon name, an emoji or an image file.
ICON = "clapperboard"

from PySide6.QtCore import Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget

from wildtrax import RecordingEngine, TimeConfig
import wildtrax

REC_COLOR = "#e5484d"


class TimecodeSlate(QWidget):
    def __init__(self):
        super().__init__()

        self.timecode = QLabel(alignment=Qt.AlignCenter)
        font = QFont("Menlo")
        font.setStyleHint(QFont.Monospace)
        font.setBold(True)
        self.timecode.setFont(font)

        self.status = QLabel(alignment=Qt.AlignCenter)

        layout = QVBoxLayout(self)
        layout.addWidget(self.timecode, 1)
        layout.addWidget(self.status)

    # Connect while visible, disconnect when hidden: a closed slate costs
    # nothing. Methods on a QObject (rather than lambdas) are always called on
    # the GUI thread, even when the engine emits from its audio thread.
    def showEvent(self, event):
        # timeCode has no signal of its own; it updates on doneReadingBuffer.
        RecordingEngine.doneReadingBuffer.connect(self.refresh_timecode)
        RecordingEngine.isRecordingChanged.connect(self.refresh_status)
        self.refresh_timecode()
        self.refresh_status()
        super().showEvent(event)

    def hideEvent(self, event):
        RecordingEngine.doneReadingBuffer.disconnect(self.refresh_timecode)
        RecordingEngine.isRecordingChanged.disconnect(self.refresh_status)
        super().hideEvent(event)

    def refresh_timecode(self):
        text = RecordingEngine.timeCode
        if text != self.timecode.text():   # the buffer signal fires far more often than frames change
            self.timecode.setText(text)

    def refresh_status(self):
        source = TimeConfig.currentTimeSourceName()
        if RecordingEngine.isRecording:
            self.status.setText(f"● REC    {source}")
            self.timecode.setStyleSheet(f"color: {REC_COLOR};")
            self.status.setStyleSheet(f"color: {REC_COLOR};")
        else:
            self.status.setText(source)
            self.timecode.setStyleSheet("")
            self.status.setStyleSheet("")

    # Keep the digits as large as the panel allows.
    def resizeEvent(self, event):
        font = self.timecode.font()
        font.setPixelSize(max(16, min(self.width() // 7, int(self.height() * 0.55))))
        self.timecode.setFont(font)
        super().resizeEvent(event)


# One widget per showing of the panel (the Toolkit workspace, a docked
# panel); WildTrax builds them from this class.
wildtrax.panel(TimecodeSlate)