Universal Controller MIDI
Blog TouchDesigner 8 min read

TouchDesigner DualSense Controller Mapping with MIDI CHOPs

Map a PS5 DualSense into TouchDesigner via virtual MIDI. CHOP-driven gamepad input, named channels, adaptive trigger feedback — all in one network.

By Aidxn Design

TouchDesigner has Joystick CHOPs. They are fine. They are also flaky on Bluetooth, cap out at the basics, and won't touch the DualSense's touchpad or adaptive triggers. The cleaner route is to bridge the gamepad into TouchDesigner over virtual MIDI, then use a single MIDI In CHOP to fan inputs across your network. This post walks through wiring a TouchDesigner PS5 controller rig with named CHOP channels, Python references, and trigger haptics flowing back the other way.

TL;DR
  • What you do: bridge the DualSense into a virtual MIDI port, drop a MIDI In CHOP, reference named channels in your network.
  • What you need: DualSense, TouchDesigner 2023.+ Commercial or Non-Commercial, macOS 12+ or Windows 10+, Universal Controller MIDI v1.0+.
  • Time: 6 minutes to first stick-driven Noise TOP.
  • Bonus: adaptive triggers as physical feedback when your audio-reactive network kicks.

Why a gamepad for TouchDesigner

TouchDesigner installations live on a single laptop with the lid half-closed, no MIDI controller in sight, and a designer wanting to nudge values during a live show. A DualSense gives you sixteen tactile inputs, two analog sticks, two analog triggers, and a touchpad — without the cable spaghetti of a MIDI Fighter. Bind it once, pack it in the laptop sleeve, you are done. Universal Controller MIDI turns the gamepad into a virtual MIDI port TouchDesigner treats as native hardware.

What you'll need

  • Universal Controller MIDI v1.0+ (download)
  • TouchDesigner 2023.+ — Non-Commercial works fine for testing
  • PS5 DualSense — wired USB-C if you care about latency, Bluetooth if you don't
  • macOS 12+ or Windows 10+

Setup

1. Bridge the gamepad

Launch the bridge, plug the DualSense in. The status pill flips to DualSense connected. In Presets → TouchDesigner the default map drops face buttons on notes 60–63, d-pad on 78–81, shoulders and option/share on 67–71, sticks on CC 1–4, triggers on CC 5–6, and the touchpad XY on CC 16/17. All on channel 1.

2. Drop the MIDI In CHOP

Inside TouchDesigner, right-click the network, add a midiinCHOP. In its parameters: Source = Universal Controller MIDI, Active = On, Format = All Channels, Generate Channels As Needed = On. Channels named ctrl1, ctrl2, … appear as you wiggle inputs. Buttons appear as n60, n62, etc.

3. Rename channels with a Rename CHOP

Stick a renameCHOP after the MIDI In to swap raw names for ones you can read in three weeks. Example pattern: ctrl1 ctrl2 ctrl3 ctrl4 ctrl5 ctrl6 ctrl16 ctrl17 rename to lx ly rx ry l2 r2 tx ty. Now your Python references are human.

4. Reference inputs anywhere

TouchDesigner Python references are read directly off CHOP channels. In any parameter expression you can pull a stick into a uniform, a Math CHOP, a SOP transform, or a feedback TOP.

# Drive a Noise TOP translate from the left stick
op('noise1').par.tx = op('rename1')['lx']
op('noise1').par.ty = op('rename1')['ly']

# Cross-fade two TOPs from the right trigger
amount = op('rename1')['r2']
op('cross1').par.cross = amount

# Touchpad XY → 2D parameter (e.g. Feedback TOP scale)
op('feedback1').par.scalex = 1 + op('rename1')['tx'] * 0.5
op('feedback1').par.scaley = 1 + op('rename1')['ty'] * 0.5

Mapping ideas

  • Face buttons → scene jumps. Bind notes 60–63 to a Replicator's active index for instant scene swaps.
  • Sticks → 2D nav. Drive a 3D camera dolly or a 2D feedback offset; cheap and intuitive.
  • Triggers → effect dry/wet. Cross-fade between two TOP chains with L2 / R2.
  • Touchpad → XY pad. Map CC 16/17 to a Filter TOP's blur amount and a Hue offset for a Kaoss-style sweep surface.
  • D-pad → preset bank nav. Notes 78–81 step a Preset Manager up/down/next/prev.
  • Options / Share → record toggles. Out-of-band buttons live well as "Start render" and "Hold camera" triggers.

Performance tips

  • Filter your CHOP. Drop a filterCHOP at 20–60 ms after the MIDI In to smooth analog sticks — raw MIDI is 7-bit and jumps in steps of 1/128.
  • Use 14-bit where it matters. Enable Settings → 14-bit CC in the bridge for sticks, then set the MIDI In CHOP to 14-bit Range. Smoothness for free.
  • Cook only what you need. Reference CHOP channels with op()[] rather than wiring every channel into every node. Lowers your cook tree.
  • USB-C for shows. Bluetooth is fine for prototyping; in a venue with 200 phones, wire it.

Gotchas

  • MIDI In CHOP shows no source. TouchDesigner enumerates MIDI sources at startup. Launch the bridge first, then TouchDesigner.
  • Sticks centre at 64 instead of 0. That is MIDI doing MIDI. Add a Math CHOP, range from 0–127 → -1 to 1, with a small deadzone via a Limit CHOP.
  • Buttons trigger twice. You probably hooked both a note-on Reset CHOP and a Trigger CHOP. Pick one.
  • Trigger feedback does nothing. Open Bridge → Settings → Adaptive triggers and switch on Feedback enabled. Send the return CC from a midioutCHOP pointed at UCMIDI Out.

Wrap

TouchDesigner plus a DualSense plus a virtual MIDI port is the cheapest, lightest stage rig you will ever pack. The Joystick CHOP is fine for prototyping; for shows, the MIDI route gives you named channels, hot-swap controllers, and trigger haptics that the joystick API simply cannot. Pair it with the adaptive triggers guide and you have a closed-loop performance instrument.

Worth $49? Probably. Try Universal Controller MIDI free first — the free tier covers TouchDesigner fine, Pro unlocks every connector and the mapping editor.

Keep reading

More setup walkthroughs