Skip to main content

External SDK / API

Middle Control exposes a TCP API that lets any external device or software send commands to Middle Control — and read back live camera and gimbal data.

This is useful if you want to:

  • Trigger presets, start/stop recording, or control a gimbal from a custom device or script
  • Integrate Middle Control into a broadcast automation workflow
  • Build a custom control panel (hardware or software) that talks directly to Middle Control
Port change — the API now lives on port 11584

This API used to be documented on port 11581. That port is shared with the Middle Remote (Glue) connection and is refused when Middle Remote is in Direct mode — which is the default on macOS. If your integration was built on 11581, simply change the port to 11584: the commands and the feedback frame are identical. (This External API is a macOS feature. On Windows, use the Companion port 11580 and the Glue / Remote port 11581.)

note

There is no SDK that communicates directly with APC-R units. All commands go through the Middle Control app running on your computer.

🔌 Connection​

Your device or software sends plain-text TCP commands to the computer running Middle Control. Each command is a short string (e.g. CAM3, PRESET1, P500) terminated by a newline character — one command per line.

TCP connection details

Host : IP address of the computer running Middle Control (use 127.0.0.1 if your software runs on the same machine)

Port : 11584

End character : \n (LF or CRLF)

Good to know:

  • Commands are case-sensitive — send them exactly as written on this page.
  • The API is fire-and-forget: a malformed or unknown command is silently ignored (there is no error reply). Use the live feedback to confirm state.
  • When your integration is connected, an External API entry appears in the left sidebar of Middle Control, under Controllers — it stays visible as long as the connection is open.

Quick test from a terminal — select camera 1 and trigger its preset 1:

printf 'CAM1\nPRESET1\n' | nc <MIDDLE_CONTROL_IP> 11584

🎯 Selecting & targeting cameras​

Every command on this page acts on a camera ID (1–99). There are two ways to say which one:

  1. Select a camera with CAMx — the following commands act on it, and the feedback frame reports it. This changes the selected camera in Middle Control, like clicking it in the sidebar.
  2. Target one command by appending @Cx at the end — the command goes to camera x without changing the selection.
CommandDescription
CAM3Select camera/gimbal 3 — the commands that follow act on it
REC_START@C2Start recording on camera 2, selection unchanged
AUTOFOCUS@C5Trigger autofocus on camera 5, selection unchanged
P500@C1Send a pan command to camera 1, selection unchanged
tip

Targeted commands make multi-camera actions easy — send REC_START@C1, REC_START@C2 and REC_START@C3 in rapid succession to start recording on cameras 1, 2 and 3 simultaneously.

🕹️ Gimbal & PTZ control​

Variable speed​

Drive an axis at a given speed — the axis keeps moving until you send 0 on it:

CommandDescription
PxxPan speed, xx between -2048 and +2048 (INT16)
TxxTilt speed, xx between -2048 and +2048 (INT16)
RxxRoll speed, xx between -2048 and +2048 (INT16)
ZxxZoom speed, xx between -2048 and +2048 (INT16)
Send 0 to stop

P500 starts panning and P0 stops it. Safety net: if your TCP connection drops while an axis is still moving, Middle Control stops that axis automatically.

Speed settings used by the button commands and presets:

CommandDescription
PTSxxPan/Tilt speed setting, xx between 1 and 100 (INT8)
ZSxxZoom speed setting, xx between 1 and 100 (INT8)

Absolute position​

Send the gimbal to a precise position in a single command, with this frame format:

aGLOB;aPxx;aTxx;aRxx;aZxx;ss
PartDescription
aGLOBMust be at the start of the frame
aPxxAbsolute Pan position, in 1/10th of a degree (INT16)
aTxxAbsolute Tilt position, in 1/10th of a degree (INT16)
aRxxAbsolute Roll position, in 1/10th of a degree (INT16)
aZxxAbsolute Zoom position, between 0 and 4096 (INT16)
ssTransition duration in seconds

Example: move to Pan 20°, Roll 2°, Tilt 7.5°, Zoom mid-range, over 5 seconds:

aGLOB;aP200;aR20;aT75;aZ2500;5

You can also send a single axis on its own, using the current transition speed:

CommandDescription
aPxx / aTxx / aRxxMove one axis to xx, in 1/10th of a degree
aZxxMove the zoom to xx, between 0 and 4096

Buttons & utilities​

These work like button presses:

CommandDescription
PAN_L / PAN_RPan the gimbal left / right
TILT_U / TILT_DTilt the gimbal up / down
ROLL_L / ROLL_RRoll the gimbal left / right
Stop commands required

After each movement command above, you must send the matching stop command after a delay of at least 70ms:

MovementStop command
PAN_L / PAN_RPAN_IDLE
TILT_U / TILT_DTILT_IDLE
ROLL_L / ROLL_RROLL_IDLE

If the connection drops before the stop command, Middle Control stops the movement automatically.

CommandDescription
ZOOM+ / ZOOM-Zoom in / out by a step
SPEED+ / SPEED-Increase / decrease the pan/tilt speed
ZSPEED+ / ZSPEED-Increase / decrease the zoom speed

Gimbal utilities:

CommandDescription
RECENTERRecenter the gimbal
ACTIVETRACKActive Track Enable / Disable
GIMBALSLEEP / GIMBALWAKESleep / wake the gimbal
GIMBALAUTOCALIBStart Gimbal Autocalibration (Autotune)
MOTORAUTOCALIBStart Focus Motor Autocalibration

🎥 Camera control​

Availability depends on the camera brand and how it is connected (some commands are Sony-only, some need an ATEM link).

Absolute values​

Set a camera value directly:

CommandDescription
aFxxFocus, xx between 0.0 and 1.0 (FLOAT)
aIxxIris, xx = f-number (FLOAT) — snapped to the nearest supported f-stop (roughly f/1.2 to f/22)
aWBxxWhite Balance, xx between 2500 and 10000 Kelvin (INT16 — whole numbers only)
aTINTxxTint, xx between -100 and +100 (INT8)
aISOxxISO / Gain in dB, xx between -12 and +36 (INT8)
aSHUTxxShutter, xx = denominator (INT16 — e.g. aSHUT50 for 1/50s)

For cameras controlled through an ATEM switcher (color corrector values):

CommandDescription
aSATxxSaturation, xx between 0 and 100
aCONTxxContrast, xx between 0 and 100
aBLACKLEVxxBlack level (lift luma), xx between -2.0 and +2.0
aMIDLEVxxMid level (gamma luma), xx between -4.0 and +4.0
aWHITELEVxxWhite level (gain luma), xx between 0 and 16.0

For VISCA cameras that use Red/Blue gain instead of Kelvin/Tint:

CommandDescription
aRGAINxxRed gain, xx between 0 and 255
aBGAINxxBlue gain, xx between 0 and 255

Steps & toggles​

One increment per command:

CommandDescription
FOCUS+ / FOCUS-Focus in / out by a step
IRIS+ / IRIS-Iris increase / decrease
WB+ / WB-White balance increase / decrease
ISO+ / ISO-ISO increase / decrease
TINT+ / TINT-Tint increase / decrease
SHUTTER+ / SHUTTER-Shutter increase / decrease
ND+ / ND-ND Filter increase / decrease
SHARP+ / SHARP-Sharpness increase / decrease
CONT+ / CONT-Contrast increase / decrease (ATEM)
SAT+ / SAT-Saturation increase / decrease (ATEM)
BLEV+ / BLEV-Black level increase / decrease (ATEM)

Auto modes and monitoring toggles:

CommandDescription
AUTOFOCUSTriggers autofocus
AUTOIRISTriggers auto iris
AUTOSHUTTERToggles auto shutter
AUTOGAINToggles auto gain / ISO
AUTOWBToggles auto white balance
COLORBARSShow Color Bars
ZEBRAShow Zebra Guide
FALSECOLORSShow False Color Guide
FOCUSPEAKINGToggle Focus Peaking
STATUSVIEWShow the status view on the HDMI out of the camera
DIGITAL_ZOOMToggle Digital Zoom (Sony)
RESETCCUReset the CCU / color corrector values
CommandDescription
BTN_MENUPress Menu Button
BTN_OKPress OK Button
BTN_LEFT / BTN_RIGHT / BTN_UP / BTN_DOWNPress the arrow buttons
MULTISEL_LEFT / MULTISEL_RIGHT / MULTISEL_UP / MULTISEL_DOWNMove the MultiSelector
MULTISEL_PRESSPress the MultiSelector
CUSTOM_C1 … CUSTOM_C6Trigger Custom function C1 … C6

Recording​

CommandDescription
REC_STARTStart recording (currently selected camera)
REC_STOPStop recording (currently selected camera)
REC_START_ALLStart recording on all cameras
REC_STOP_ALLStop recording on all cameras

The feedback frame lists the cameras currently recording in REC_LIST[…].

📌 Presets​

CommandDescription
PRESET1 … PRESET12Trigger preset 1 … 12 of the currently selected camera
PRESET1@C5 … PRESET12@C5Trigger preset 1 … 12 of camera 5 (presets 5.1 – 5.12 in Middle Control)
SPRESET1@C5 … SPRESET12@C5Save preset 1 … 12 of camera 5 (presets 5.1 – 5.12 in Middle Control)

Control preset playback:

CommandDescription
STOPPRESETStop the preset move in progress (add @Cx to stop a specific camera)
PRES_DxxSet the preset transition duration, xx in seconds
PRES_ExxSet the preset transition easing, xx between 0 (linear) and 100 — one value for all cameras, like PRES_D (APC-R firmware 2.0 or later)

🔁 Automations​

Start, stop and tune the Automations of the Automations page. All commands accept @Cx targeting.

Camera Shake

CommandDescription
SHAKE-START / SHAKE-STOPStart / stop the camera shake
SHAKE-SPEEDxxShake speed, xx between 1 and 100
SHAKE-AMPLxxShake amplitude, xx between 1 and 100

Zoom Loop

CommandDescription
ZLOOP-START / ZLOOP-STOPStart / stop the zoom loop
ZLOOP-SPEEDxxZoom speed, xx between 1 and 100
ZLOOP-DURATIONxxZoom travel time, xx in seconds (0.1 – 60)
ZLOOP-RESTDURATIONxxPause between loops, xx in seconds (0.1 – 15)

Presets Sequence

CommandDescription
PRESETSEQ-START / PRESETSEQ-STOPStart / stop the presets sequence
PRESETSEQ-BANKxSelect the active sequence bank, x between 1 and 7
PRESETSEQ-SPEEDxxTransition speed of the sequence, xx in seconds (0.1 – 15)
PRESETSEQ-RESTDURATIONxxRest time on each preset, xx in seconds (0.1 – 15)

The feedback frame reports the live state of each automation for the selected camera: SHAKE_RUN, ZLOOP_RUN, PRESETSEQ_RUN (1 while running) and PRESETSEQ_BANK (active bank).

🖥️ Live View & Multi View​

Open and close the monitoring windows on the computer running Middle Control:

CommandDescription
LIVEVIEW_OPEN / LIVEVIEW_CLOSEOpen / close the Live View window of the currently selected camera (select it first with CAMx)
MULTIVIEW_OPEN / MULTIVIEW_CLOSEOpen / close the Multi View window (Middle Control Pro — ignored without it)

📡 Live feedback​

Middle Control pushes a live status frame over the same TCP connection, about 4 times per second. The frame reflects the currently selected camera. This lets you read the current state of the gimbal and camera — useful for building feedback displays or reactive workflows.

note

Camera value feedback is available when Middle Control is connected to an ATEM Switcher or to a camera over Wired LAN. Gimbal angles are included when an APC-R is linked to the camera.

TCP Feedback Frame — example
{CAM5;REC1;AF0;DZOOM0;aWB5600;aF0.45;aI6.5;aUI5.4;aTINT10;aISO12;aSHUT1/50;aSAT50;aCONT50;aBLACKLEV0.4;SHAKE_RUN0;ZLOOP_RUN0;PRESETSEQ_RUN1;BRANG_RUN0;PRESETSEQ_BANK1;aPAN523;aTILT124;aROLL890;aZOOM3992;PTS85;ZS24;PRES_D8.0;PRES_ACTIVE0;PRES_E50;REC_LIST[5];CAM_CON_LIST[1,2,5];APCR_CON_LIST[5]}

Each frame is a single line ending in \n: {CAM<id> followed by ;-separated tokens, closed by }. Tokens in order:

TokenMeaning
CAMSelected camera ID
REC / AF / DZOOMRecording / Autofocus / Digital zoom on the selected camera (1 or 0)
aWBWhite balance in Kelvin
aFFocus position, 0.0 – 1.0
aI / aUIIris f-number (locked to stops / unlocked)
aTINTTint (signed)
aISOGain in dB
aSHUTShutter (denominator, e.g. 50 or 1/50)
aSAT / aCONT / aBLACKLEVSaturation, contrast, black level (ATEM-linked cameras)
SHAKE_RUN / ZLOOP_RUN / PRESETSEQ_RUN1 while that automation is running on the selected camera, else 0 (BRANG_RUN is reserved, always 0)
PRESETSEQ_BANKActive presets-sequence bank, 1 – 7
aPAN / aTILT / aROLLGimbal angles in 1/10th of a degree (APC-R linked)
aZOOMZoom motor position, 0 – 4096 (APC-R linked)
PTS / ZSCurrent pan/tilt speed and zoom speed settings
PRES_DPreset transition duration in seconds
PRES_ACTIVE1 while a preset move is running, else 0
PRES_EPreset transition easing, 0 – 100 (- when the camera has no APC-R with firmware 2.0 or later)
REC_LIST[…]Camera IDs currently recording
CAM_CON_LIST[…]Camera IDs currently connected
APCR_CON_LIST[…]Camera IDs with an APC-R gimbal connected
Parse by token name, not by position

Depending on the camera brand and how it is connected, some tokens may be absent from the frame, and a value that is not available is sent as - (a dash) — make sure your parser handles both instead of assuming every token is always present and numeric.