Hey folks — dropping a small but genuinely useful tool: a PS4 DualShock 4 → CHOP tox for TouchDesigner (macos specific) - there are working ps4 TOX's on the TD forum. Plug in your controller, drop the tox into any project, and you get a single clean CHOP output with 20 human-readable channels. No more guessing which button is b7.
What you get
One output CHOP with the following channels:
-
Analog sticks — L_analog_x, L_analog_y, R_analog_x, R_analog_y (range -1 to 1, 0.07 deadzone)
-
Triggers — L2, R2 (analog, 0 to 1)
-
Face buttons — cross, circle, square, triangle
-
Shoulders / stick-clicks — L1, R1, L3, R3
-
Menu buttons — select (share), start (options)
-
D-pad — dpad_up, dpad_down, dpad_left, dpad_right (split into 4 booleans instead of TD's native POV angle)
How it works under the hood
The internal chain is deliberately simple, but each piece is there for a reason:
-
joystickCHOP is the raw input. TD exposes the PS4 pad as LX_axis, LY_axis, RX_axis, RY_axis, L2, R2, b1..b10, plus a dpad POV. Deadzone is set to 0.07 so resting sticks read clean zero. Axis range is -1 to 1.
-
renameCHOP swaps b1..b10 into the readable button names (cross, circle, square, etc.). This is the only reason you don't need a cheat sheet taped to your monitor.
-
D-pad splitting — TD gives you the D-pad as a POV angle, which is annoying to use. A selectCHOP grabs the dpad channels, a mathCHOP negates them, and a logicCHOP fans them out into four independent booleans (dpad_up/down/left/right). Now you can trigger things off D-pad directions like any other button.
-
constantCHOP + replaceCHOP — this is the quiet hero. The constant defines every expected channel at value 0. The replace uses the live joystick output to overwrite whatever's present, but keeps the constant's channels for anything missing. That means if the controller disconnects, your downstream patch doesn't explode with missing channels — you just get zeros until it reconnects. Worth doing in anything you want to ship.
-
mergeCHOP → outCHOP — combines the non-dpad channels with the split dpad booleans and exposes the final output.
The macOS gotcha (what broke it earlier)
When I first dropped this in, the channels were flat zero and the joystickCHOP was throwing a Selected joystick not connected warning — even though the controller was obviously plugged in.
The cause: the source parameter on joystickCHOP was set to player1controller, which is a Windows/XInput-style generic device handle. On macOS, TD doesn't enumerate gamepads that way — it exposes them with a device-specific string. The menu on my machine showed:
tdjoy:m:Sony Interactive Entertainment:p:Wireless Controller:l:0x3100000:
Setting source to that exact string fixed it immediately. If you're on macOS and the tox reads zeros, open the joystickCHOP, click the source dropdown, and pick the Wireless Controller entry (not default, not player1controller). On Windows, default or player1controller usually works — YMMV depending on your driver setup.
That's the whole gotcha. TD's joystick support is solid, but the device-selection layer isn't cross-platform and the default value ships biased toward Windows.
Using it
-
Drop PS4_controller.tox anywhere in your network.
-
Connect its out1 CHOP to whatever you want to drive.
-
If you see zeros on macOS, fix the source param as described above.
That's it. Small tool, but it's the kind of thing that saves you 20 minutes every time you start a new interactive project. Enjoy — and if you build something with it, I'd love to see it.






