TDMap
FOR TOUCHDESIGNER

MIDI mapping,
without the wiring.

TDMap is a TouchDesigner component for mapping any MIDI controller to any parameter — with a real-time web UI for knobs, faders, buttons, push encoders, and 14-bit controls across multiple devices and banks.

TouchDesigner 2023.12120+ (2025.32460+ for optimized 14-bit) · Drop-in .tox · Works with any MIDI controller

What's in TDMap.

Drag a parameter, move a knob, and you're mapped. Then layer behavior on top — across as many devices, banks, and recall scenarios as you need.

Controls

Every type of MIDI control TDMap recognizes out of the box.

Absolute knobs & fadersStandard 7-bit (0–127) controls with full type detection via Smart Learn.
Relative encodersInfinite encoders sending deltas — offset-binary and two's-complement both auto-classified. Per-control invert, adaptive or fixed step.
14-bit faders & knobs16,384-step resolution. TDMap auto-pairs MSB+32/LSB, suppresses raw LSB bytes, and surfaces conflicts in the UI.
ButtonsNote or CC, with gate / latch / trigger hardware behaviors. Mapping intent (toggle, momentary, pulse, set) is independent of hardware.
Push-knobsEncoder + secondary button combos. Separate assignment for the press — or use Alternate Knob as a shift key for a second mapping.
🎹
Keyboard mappingBind TD parameters to specific keys on a MIDI keyboard. Velocity-driven, octave-shiftable, channel-scoped — works alongside grid mappings on the same device.

Mapping

Get a controller talking to TD in seconds, then refine.

No CHOPs or expressionsDrop the .tox, drag & drop params, move controls, go. No CHOP spaghetti, no expressions or binds — pure control.
Smart LearnAuto-detects control type (knob, fader, button, push-encoder) and MIDI protocol on the first few movements.
Drag & drop everythingAnywhere a parameter is shown — card chips, inspector pills, slot pills, function targets — you can drag it out and drop it anywhere else a parameter is accepted (other cards, the param queue, slot/function target zones, piano keys). Same for control references: card layout handles, modify-target rows, slot-target widgets, and function-target control rows all drag onto every matching target zone. Hover-to-activate auto-clicks bank tabs and inline buttons mid-drag.
Hover modeSlot controls whatever par the cursor is over — no assignment needed. Roving value scrubber.
Multi-device & banksMultiple controllers, each with its own grid and channel. Banks swap mapping sets on the same hardware.
Config librarySave and load device layouts, factory presets, global configs. Mappings live outside the component — survive updates.
MIDI Device ManagerEdit TouchDesigner's MIDI I/O table from inside the UI — add / remove devices, swap inputs and outputs, rescan for new hardware. Right-click for a live two-line MIDI log preview without leaving what you're doing.

Behaviors

The reason TDMap exists isn't just to wire CC numbers — it's to layer behavior on top.

Button actionsToggle, momentary, pulse, set-max — independent of hardware type. Toggle reads the live par value. See full function list →
Velocity mappingPads and keys drive parameters continuously — each hit's velocity feeds the absolute pipeline (range, clamp, easing). Pick Hold / Reset Min / Reset Default for what happens on release. Works on push-buttons of push-knobs too.
#
Counter & radio buttonsStep up/down on press with wrap, loop, or zigzag. Or radio-style groups where each button sets a fixed value.
ƒ
Function buttonsButtons run built-in actions — reset, set value, bank switch, par-learn, open editor, push-step, randomize, or custom callbacks. See full function list →
Parameter slotsButtons or pushes hot-swap the active parameter of another control on press. Build instrument-style variations.
Modifier modeKnob, fader, or button mathematically transforms another control's output — scale, add, offset, limit, quantize. Stackable.

Polish

The control-feel layer — smoothing, response curves, range shaping.

Value smoothingExponential filter glues jittery input — global default, per-slot override. Live preview as you tune.
Value pickupAbsolute controls wait to match the current par value before taking over — kills bank-recall jumps.
Easing curves30+ functions per-knob or per-parameter. Linear, exponential, smoothstep, Catmull-Rom — choose your feel.
Input range remapPer-control window for hardware that doesn't reach the full 0–127 (or 0–16383) range.

Workflow

The little quality-of-life stuff that adds up.

Five view modesDetailed, Compact, Mini, List, Values (with live bars). Cycle with one button; right-click to reverse.
Multi-device viewStacks every device's grid in one scrollable layout — collapsible per-device sections, global bank strip.
Undo with groupingCtrl+Z for knob and fader changes. Rapid movements collapse into a single undo entry.
Broken-assignment healingRename or delete an op? Assignment stays as invalid, flagged with a warning. Re-rename and it auto-heals.
Retarget & first-time hintsBatch op-path replace across assignments / banks / devices. Contextual hints surface as you explore.
Update-safe configsConfigs live in a separate TDMap_Config COMP outside the component. Drop in a newer .tox any time — every device, bank, and mapping is untouched.
Middle-click revealMiddle-click any par anywhere in the UI (cards, inspector chips, slot pills, function targets) to jump straight to its owner in the last network editor pane you used — or set a preference to always open in a floating window.
Button actions — what a button (or a push) can do click to expand

A button doesn't have to be a MIDI mapping. Flip its mode to Function in the inspector and it becomes an action button: tap it to reset, snapshot, randomize, switch banks, open an editor, etc. The same applies to a push-knob's push when it's set to Function. Most actions are one-line picks in a dropdown — pick the action, optionally pick what it operates on, done.

Picking what the action operates on

Actions that change a parameter need to know which parameter. Four ways to point at one — visible as tabs above the action:

  • Hovered — whatever your mouse is over in TouchDesigner the moment you press the button. Great for "fix-it" buttons (reset, randomize, snapshot) that you point at things.
  • Adjusted — the last parameter you twisted via MIDI. Lets one button always undo / randomize / re-default whatever you most recently touched.
  • Knob — the push-knob's own assigned parameter. Only on push-knobs.
  • Target — a fixed list of parameters you pin in advance. Two flavors, mixable in the same list:
    • Par target — drag a TD parameter onto the pill. Sticks to that exact parameter.
    • Control target — drag another card onto the pill (or click "+ Add Control Target"). Resolves to whatever that other control is currently driving — so renaming or reassigning the target control transparently changes what this button operates on. Same idea as Slot mode and Modify targets.

Actions iterate the whole list — point one Reset button at six targets to reset all of them with one press.

Things buttons can do

Pick from the dropdown in the inspector. Internal names shown in code for reference.

Set, reset, snapshot, randomize a parameter
Reset resetSend the parameter back to its default value.
Snapshot as default set_as_defaultMake the current value the new default. Useful for setting your "happy place" on the fly (custom pars only).
Snapshot as min / max set_current_as_min / _maxPin the current value as the bottom or top of the parameter's range.
Toggle clamp toggle_clampFlip min/max clamping on or off without changing the values.
Randomize randomizeRoll a random value in range. Int/float pars try to differ from the current value; toggles get a random T/F; pulses fire ~50% of the time; menus pick a different item.
Set a specific value set_valueWrite a fixed value. Type follows the parameter — number, bool, menu name, pulse fire.
Navigate banks & open editors
Next / Previous bank bank_next / bank_prevStep through banks on the active device. Wraps around.
Jump to bank bank_switchPick a specific bank by index.
Open editor for selected / selected↑ / last-adjusted open_editor_*Pop the TouchDesigner Component Editor (custom-parameter setup) for a COMP. Variants: Selected uses the currently selected COMP; Selected↑ uses its parent COMP when the selection is a non-COMP op (so you can target a child op inside a network and still land on the host COMP's editor); Adjusted uses the owner of the last MIDI-adjusted parameter.
Open parameters for selected / selected↑ / last-adjusted open_params_*Pop TouchDesigner's standard Parameters window. Works for any op kind (not just COMPs). Same three variants as Open editor.
Promote to parent (Hovered / Adjusted) promote_to_parent[_adjusted]Promote the targeted parameter to its owner's parent COMP and bind it back, via the bundled CustomParPromoter child COMP. If the par is part of a multi-par group (XYZ, etc.) that's already mapped on a TDMap slot, the whole pargroup is promoted as a unit. Any TDMap mappings that referenced the original par get re-targeted to the new promoted par automatically.
Learn a new mapping
Par Learn learnHold (or toggle) the button, then hover a TD parameter — the slot binds to it. Same as the inspector's PAR button, but as a hardware shortcut.
Fire your own code
Callback callbackCalls a Python function in TDMap's callback DAT by name. Pass up to two string args. Drop in whatever you want.
Encoder-specific (push on a push-knob)
Push-step push_stepHold the push, twist the encoder to change step size on the fly — coarser (×10), finer (÷10), or set to a fixed step while held.
Preferences — what you can dial in click to expand

Open the gear icon in the toolbar to find these. All preferences persist across sessions in a single tdmap-prefs.json file next to your configs.

Defaults for new controls

Default push modeAssignment / Function / Slot / Modify — what a brand-new button or newly enabled push-knob starts in. If you mostly use buttons for actions, set this to Function.
Default function & valueWhen the default push mode is Function, also pick the function name (e.g. Reset, Randomize) and any value it needs. New buttons pre-fill with these.
Multi-assignment by defaultNew slots start in multi-assignment mode (one slot drives many pars). Off by default.
MIDI feedback by defaultNewly created slots have MIDI Out feedback enabled. Useful if all your controllers have motorized faders or LED rings.

Behavior

Auto-toggle on assignmentWhen you assign a pulse / toggle / momentary par to a button, automatically pick the matching button action — so you don't have to think about it.
Smart LearnWhen learning a control, watch the first few movements and auto-classify it as a knob / fader / encoder / button + the right MIDI protocol.
Auto-save layoutPersist every change to the global config the moment it happens — no manual save.
Protect read-only & disabled parsBlock MIDI value writes to parameters TouchDesigner marks as read-only or disabled (mapping stays, value writes don't fire).
Loop menusMenu parameters wrap around at both ends when stepped past the edges (off = clamp).
MIDI-control string menusAllow MIDI to drive string-style menus (StrMenu). Off by default since the values are arbitrary strings, not ordered.
Middle-click "show in pane" — floatingWhen on, middle-click always opens a floating network editor (don't follow the network editor pane you last used in TD).

Feel

Global filterDefault exponential-smoothing amount for new slots. Per-slot override available in the inspector.
Global step / step modeDefault relative-encoder step size and adaptive vs fixed step. Per-slot override available.
Global pickupDefault pickup-on-bank-change for new slots (absolute controls wait to match current value before taking over).

Workflow

Enable undo & group windowToggle Ctrl+Z and set how long rapid changes collapse into one undo step (so a knob sweep is one undo, not 200).
Slot-learn hold timeHow long you have to hold a slot button before "slot learn" mode arms.
Theme & zoomLight / dark theme, and a CEF-safe zoom (CSS transform, not browser zoom) so the panel renders sharply in any TD pane size.
Interactive tourReplay the onboarding walkthrough any time.
Public interface — driving TDMap from your own scripts click to expand

The TDMap component is shipped locked so its extension methods aren't directly accessible from outside callers. Locking serves two purposes: keeping users from accidentally breaking internals on a live show, and making the package less appetizing to AI-training scrapers that crawl public TouchDesigner tox files for code to ingest.

To keep the component scriptable anyway, TDMap exposes a small set of public methods over a public-interface Text DAT. Each non-blank, non-#-prefixed line is parsed as a method call and run against the COMP — one call per line, comments allowed, per-line errors logged to the Textport. Drive that DAT however you like: Python .text = ... assignment, a Replicator emitting rows, an external tox piping commands.

Setup: open the TDMap COMP's custom parameters, go to the Integration page, and pulse Create Public Ext Interface. That creates the Text DAT next to the COMP, ready to edit or drive from another script.

Execution triggers: the lines run automatically whenever the DAT's text changes, and also whenever the COMP's Runpublic custom parameter is pulsed. Use the pulse path when you want to re-fire the same lines without re-writing them — e.g. from a button, a CHOP event, or another script.

Arguments are parsed as Python literals from text — strings, numbers, booleans, lists, dicts, keyword args all work. You cannot pass live TouchDesigner objects (no op('/...') handles, no parameter refs, no module access — eval runs in a restricted scope). Pass a path as a string instead: write '/proj/synthA', not op('/proj/synthA'). If you need a value from elsewhere in TD, resolve it in your driving script first, then write the resulting literal into the DAT.

The intended pattern is to write into the Text DAT from a script rather than typing by hand — that way you compose lines once in real Python, with normal references and helpers, and only ship the final text to the DAT. For example, a DAT Execute attached to your project's state could push fresh navigation calls into TDMap whenever a scene change happens:

# In a script anywhere in your project
tdmap_input = op('/proj/tdmap_input')  # the Text DAT TDMap watches
synth_path = synth_comp.path  # resolve refs HERE, not in the DAT

tdmap_input.text = f'''
# Re-point all mappings at the new synth COMP
RetargetBanks('/proj/synthA', '{synth_path}', device='*', banks='*')
SelectDevice('knobs')
SelectBank(0)
'''.strip()

Example lines (what ends up in the DAT):

# Open a specific device + bank programmatically
SelectDevice('knobs')
SelectBank(2)

# Retarget mappings after renaming a COMP
RetargetBanks('/proj/synthA', '/proj/synthB', device='*', banks='*')

# Auto-load a stored layout on startup
SetDefaultGlobalConfig('live_set.json')

Methods

Mapping
RetargetBanksFind/replace operator-path prefixes across bank tables. find_prefix is a literal substring or, if it contains * ? [, a tdu.match pattern matched segment-by-segment against the leading /-segments of each op_path (e.g. '/noise*''/noise1'). device and banks are tdu.match patterns (None = active, '*' = all).
LearnToggle global MIDI learn mode. None toggles, True/False set explicitly.
Navigation
SelectDeviceSwitch the active device.
SelectBankSwitch the active bank. device=None = active device.
Library
LoadGlobalConfigReplace the entire TDMap state with a saved bundle.
SaveGlobalConfigPersist current state to a bundle.
SetDefaultGlobalConfigMark a bundle as the auto-restore default on TDMap init.
Lifecycle
CreateDeviceAdd a new TDMap device (name, channel, midi_id).
RemoveDeviceDelete a device by name (irreversible).
CreateBankAdd a bank to a device; returns its idx.
RemoveBankRemove a bank by idx.
Feedback
SendAllFeedbackRe-send MIDI feedback (LED / motor / ring) for every slot on the active bank — useful after external state changes the engine didn't observe.
Debug
TestStub that just calls debug('test') — smoke-test the DAT wiring.
Why lines, not direct method access? Locked TouchDesigner components don't expose Python extension members to outside scopes, so the Text DAT is the controlled seam — TDMap parses each line, validates it, runs it under a restricted eval scope. The cost is a tiny indirection; the win is that the component stays one piece you can ship without exposing internals.

Two tiers, two ways to get it.

Base covers everything you need for solid MIDI mapping. Pro unlocks behavioral layers — curves, smoothing, modifier modes, and function buttons.

Patreon — subscribe at the matching tier, get updates while subscribed.
Gumroad — one-time purchase, lifetime updates.

Base
Core mapping

Everything you need to map a controller and ship a show.

  • Multi-device & banks — independent grids, channel IDs, swap mapping sets per bank
  • Smart Learn & Learn All — auto-detect type and protocol; learn an entire controller at once
  • Drag & drop assignments — single & multi-parameter, move or copy across slots
  • Button actions — toggle, momentary, pulse, set-max — for gate, latch, and trigger hardware
  • Velocity mapping — pads and keys drive parameters continuously via velocity; configurable note-off behavior (hold, reset to min, reset to default)
  • Push-knob support — separate parameter assignment for the secondary button
  • Keyboard mapping — bind parameters to specific keys on a MIDI keyboard, with octave shift and channel filtering
  • MIDI Device Manager — edit TD's MIDI I/O table inline, rescan for hardware, live two-line log preview on right-click
  • 14-bit, 2's complement, relative invert — protocol toggles per slot
  • Range, clamp, default — per-assignment overrides
  • Hover mode & copy/paste — paint mappings onto whatever you're hovering
  • Unassigned MIDI panel — capture homeless input and organize later
  • Config library + auto-save — device layouts, factory presets, global configs
  • Undo with grouping — Ctrl+Z, with configurable rapid-move grouping
  • Step overrides — per-slot step mode and size for relative encoders
  • Retarget — batch-replace operator paths across assignments, banks, or all devices
  • Five view modes — Detailed, Compact, Mini, List, and Values (live value bars between min/max)
  • Multi-device view — every device stacked in one scrollable layout, with collapsible per-device sections and a global bank strip that switches all devices at once
  • Input range remap — per-control window for hardware that doesn't reach the full 0–127 / 0–16383 MIDI range
  • Interactive tour — built-in walkthrough of every feature
Pro PRO
Everything in Base, plus behavior.

Layer math, curves, and modes on top of any mapping.

  • Easing curves — 30+ functions, per-knob or per-parameter override (absolute controls)
  • Filter (smoothing) — exponential smoothing, global or per-slot
  • Pickup mode — absolute controls wait to match current value before adjusting
  • Function mode — buttons trigger reset, set value, set default, bank switch, par learn, custom callbacks
  • Slot mode (◈) — buttons & push-knobs hot-swap the active parameter of any other slot
  • Slot learn — hold a slot button and hover a parameter to learn its target
  • Modify mode (⊛) — mathematically modify another control's output: scale, add, divide, offset, limit, quantize
  • Alternate Knob — push-knob's encoder gets a second parameter mapping. Hold or toggle the push button to flip the encoder between its two assignments.
  • Callbacks — trigger custom callbacks from buttons / push with arguments
  • Default push mode — configurable default mode and function for new buttons and push-knobs

On the roadmap.

What's coming next — driven by patron support. Subscribing or buying isn't just access; it funds these.

Gesture recording Capture knob sweeps and button sequences as replayable macros — automate repetitive show cues without writing a single line of TD logic.
OSC mapping Same workflow as MIDI but over OSC — TouchOSC layouts, network-connected hardware, custom apps. Treat any OSC source as just another device in the grid.
Keyboard shortcuts & mouse gestures Bind any TD parameter to a key chord or a mouse gesture. Useful for laptop-only workflows, demos, or any time you don't have a controller in reach.
Game controller mapping Xbox / PlayStation pads and joysticks as first-class controllers — analog sticks as relative encoders, triggers as faders, buttons everywhere.
Modularized action blocks Chainable behavioral blocks you compose like Lego — stack modifiers, sequencers, conditions, and functions on a single control. Today's slot / modify / function modes become reusable building pieces.

Drop it in. Start mapping.

No setup wizard, no config files. Drag the .tox onto your project, tell TD which MIDI inputs to listen to, and you can start mapping immediately.

  1. Drag & drop TDMap.tox onto the root of your project
  2. Open TD's MIDI Device Mapper (Alt+D) and enable your controllers as inputs
  3. Map something: drag a TD parameter onto the TDMap button (or onto a card in the UI) and move a knob — or pick your controller from the supported devices list to load a pre-made layout
  4. Open the UI in a bigger window at http://localhost:16669 any time
# Three ways to map a control

1. Drag a TD parameter onto the
   TDMap button (top-right of TD UI)
   → move a knob → mapped.

2. Drag a TD parameter onto a card
   in the TDMap web UI.

3. Pick your controller from the
   supported devices list →
   load a ready-made layout.

Map something.

The demo runs entirely in your browser — no TouchDesigner required. Try every UI feature with mock data.

Open the Live Demo →