Hardware Controller

A hardware controller in Fusor Studio is any physical MIDI controller bound to Fusor commands: arming transitions, firing pads, toggling modes. You can use the same controller you're already running your DJ app from (any spare knobs, pads, or buttons it has are fair game), or dedicate a separate small controller to Fusor, whichever fits your rig.

This page covers the Input Mapping settings tab (where the Controller bindings live): creating a profile, MIDI-Learning bindings, and the binding model. For the canonical-mapping side of Settings (the DJ-app side), see Teach Mode.

Bindings are per-function, not per-set. You configure once and the profile persists across sessions.


The Input Mapping settings tab

Open Settings and switch to the Input Mapping tab. The layout, top-to-bottom:

SectionWhat it does
ProfilePick a saved profile, or New / Delete.
Profile Name + MIDI Input PortEdit the profile's name and which port it listens on.
Activate (toggle)Turn the profile on or off.
Connection lightReports whether the controller is actually there.
SaveAppears when there are unsaved changes.
Bindings tableOne row per function, plus a Shift 1 and a Shift 2 row. Learn, edit, or Clear each one.

Editing fields marks the profile dirty; the Save button appears. Saving while no profile is activated also activates the saved profile if a port is selected.

Closing Settings, switching tabs, or switching to a different profile while the current one has unsaved changes prompts Save / Discard / Cancel before it lets you leave. The same prompt catches an OS-level close too: Alt+F4, the taskbar close button, or quitting Fusor Studio. A dirty profile can't be lost that way.


Profiles

A profile holds one controller's MIDI bindings. Profiles are saved as .fcontroller files, one per controller.

  • New. Creates a fresh profile and opens it for editing.
  • Delete. Removes the selected profile file from disk.

You can keep several profiles side by side — one per physical controller, or several variants of the same controller for different workflows. Only one profile is active at a time. Switching profiles deactivates the previous binding before activating the new one.

Profile Name and MIDI Input Port

  • Profile Name. The label shown in the profile dropdown. Free-form.
  • MIDI Input Port. The port the profile listens on. The dropdown lists every MIDI input Fusor Studio can see. The port is part of the profile, so swapping profiles also swaps which port is being listened to.

The Activate toggle and the connection light

The toggle is a setting. The light is a status report.

The Activate toggle is your choice: on means "use this profile", off means "don't". Fusor Studio remembers it across restarts. Switching it on opens the chosen MIDI port and starts routing the profile's bindings; switching it off closes the port and stops routing. The toggle is disabled until a port is selected.

The connection light beside it is not a button. It reports what the hardware is doing and can't be clicked:

LightMeaning
Green — ConnectedThe controller is there and its port is open.
Amber — Reconnecting…Activated, but the port isn't there. Fusor Studio is polling for it.
Grey — Not activatedThe toggle is off, so Fusor Studio isn't looking.

An amber light with the toggle still on is a perfectly normal state: your setup is intact and the controller is simply unplugged. The profile stays activated, so plugging the cable back in turns the light green on its own, bindings and all. Nothing needs redoing.

Port errors

If Activate fails, a red panel below the port field explains why:

  • Port in use. The port is held by another application, most commonly your DJ app, which on Windows takes WinMM ports exclusively. Close the holder, or pick a different port. If the controller has multiple endpoints, route a copy to a virtual port you can share.
  • Port not found. The controller isn't plugged in (or the port has gone away). Fusor Studio switches to reconnect polling automatically.

MIDI Learn

The fastest way to fill in a binding is MIDI Learn: click Learn in a row, move the control on your hardware, and accept the result.

Learn listens on the MIDI Input Port selected for the profile you're editing, not on whichever controller happens to be active. You don't need an active controller at all: pick a port for a brand-new profile and Learn works immediately, with no Activate step first.

Workflow

  1. Set the profile's MIDI Input Port to the controller you want to learn from.
  2. Click Learn in the row you want to bind. The Control cell flips to a Listening… badge.
  3. Move the hardware control: press a pad, twist a knob, spin an encoder. Repeat the motion two or three times so Fusor Studio gets a clean read.
  4. Learn accepts on its own about 0.4 seconds after your input settles. The badge updates to show what was detected (Note C3 ch1, say, or CC 23 ch1) and the binding is saved. There's no confirm button; Esc is the only button on screen while learning, and it cancels.
  5. The Type cell shows the auto-detected control type (button, knob, or encoder).

If the profile has a Shift binding, hold it down while you press the control in step 3 and Learn captures the binding as Shift 1 or Shift 2 — whichever you were holding — with no need to touch the Modifier dropdown afterward. Learn a control without holding Shift and it saves as None. Hold both and it captures the one you pressed last; there's no gesture for Either, which is chosen from the dropdown only. Press Shift alone, before you've touched the control, and Fusor Studio shows a hint instead of capturing nothing: "Shift 1 held. Now press the control to bind it with Shift 1."

If the selected port is missing or already held by another application, Fusor Studio shows an error explaining why instead of listening. The causes are the same as at Activate time (see Port errors above).

Learning without disturbing an active controller

If a different profile is already active on its own controller, that controller keeps working normally while you Learn — its bound buttons and pads keep firing Fusor Studio functions. Learn only listens on the port belonging to the profile you're editing, so presses on the active controller are never picked up into the profile you're learning. This lets you set up a second controller's profile while performing with the first.

What gets detected

Fusor Studio uses the most frequent MIDI source in the learn buffer, not just the last message. So stray messages from neighbouring controls (a pad triggered by accident, the modifier wheel jittering) don't poison the learn. The dominant source wins.

The detected control type comes from the value pattern:

  • All Note On/Off messages → button.
  • CC messages with values clustered around relative-mode markers (1–5, 62–66, 123–127), few distinct values, narrow range → encoder (relative).
  • CC messages with a wide range or smooth consecutive changes → knob.
  • Otherwise → button.

The Type cell is a read-only badge. Detection is the only thing that sets it; there's no dropdown to override it. If a control is detected wrongly, re-Learn it, repeating the motion a few more times so the value pattern is unambiguous.

A binding's type affects how the underlying control is interpreted: buttons fire on press, knobs report absolute position, encoders report relative direction.


Functions

Each row in the bindings table is one function Fusor Studio can perform in response to a MIDI message. The current function set:

FunctionWhat it does
Arm / PlaySame as the Arm/Play button on the progress strip — arms the loaded fusor, then starts / pauses it depending on state.
AbortAborts the running transition.
Auto / ManualToggles the transition's progress source.
Start with IncomingToggles the Start-with-Incoming opt-in.
Tempo RampToggles the Tempo Ramp option.
Next Fusor / Prev FusorLoad the next / previous fusor in the active collection. See Browsing fusors from the controller.
Next Transition / Prev TransitionStep through transitions in the active set list. (Requires Fusor Studio Plus — set lists are a Plus feature. These rows are hidden from the picker in the standard app.)
Pad 1Pad 8Fire the action assigned to each pad slot in Pad Mode.

In the standard app, saving a profile drops any binding on a hidden row like Next/Prev Transition. A profile that predates this and hasn't been re-saved can still carry one; the runtime skips it too, so it can't swallow the MIDI key from a binding you can actually see.

Browsing fusors from the controller

Next Fusor and Prev Fusor load as they go. Each press loads the fusor it lands on, so you keep pressing until the one you want is in the player. The list runs in a loop: past the last fusor you come back to the first, and past the first you wrap to the last.

Every press writes where you landed to the status line, like Warmup · 3 of 11 — the collection you're browsing, your position in it, and how many there are. The fusor's own name isn't repeated there because the picker button is already showing it. If you haven't set an active collection, the list is your whole fusor library and the line reads All Fusors instead.

Loading a fusor disarms the player and clears any session tweaks you made to the one you're leaving, so browsing is blocked in the two states where that would cost you something:

  • While a transition is running, the press is refused with "Can't change Fusor during a transition". Nothing loads and the transition is untouched.
  • While armed, the press is refused with "Disarm to browse Fusors", and you stay armed.

Choosing a fusor by name from the Library still works while armed — that's one deliberate pick, and it disarms as it always has. The block is on browsing, not on changing fusor.

Each row carries the same controls:

  • Learn — start MIDI Learn for this row.
  • Clear — remove the binding.
  • Inv — invert switch. Flips the trigger polarity (fires on release / CC < 64 instead of press / CC ≥ 64). Use when your hardware sends release-side messages, or when a binding fires on the wrong half of a foot switch.
  • Type (badge) — shows the detected control type.
  • Modifier — a dropdown: None, Shift 1, Shift 2 or Either. Only the Shift keys you've actually bound are offered. See The Shift rows below.

Trigger semantics

Button-style functions fire on:

  • A Note On with non-zero velocity.
  • A CC value ≥ 64.

With Inv on, both inversions apply: the function fires on Note Off or CC value < 64 instead. Note Off and CC < 64 are otherwise ignored, so a single press fires the function exactly once.


The Shift rows

A controller often has a Shift button that doubles up the rest of the surface — and many have two, one per deck. The DDJ-FLX2 is one of them. Fusor Studio has a Shift 1 and a Shift 2 row at the top of the bindings table, plus a per-row Modifier setting that decides how each function reacts to them.

  • Click Learn in either Shift row and tap the hardware Shift key; it learns the same way any other row does.
  • For a Note Shift key, it's held while the key is down (released on Note Off).
  • For a CC Shift key, it's held while the CC value is ≥ 64.
  • You don't have to bind both. Bind one and Shift 2 simply isn't offered anywhere.

Which key is Shift 1 and which is Shift 2 is entirely your choice — Fusor Studio doesn't know which physical button you pressed, only which MIDI command arrived. Whatever you learn into the Shift 1 row is Shift 1.

The Modifier setting

Each function row's Modifier dropdown decides what that binding does with Shift. Every setting is definitive — it says exactly when the binding fires, and it never fires at any other time:

  • None. Fires only when neither Shift key is held. This is the default.
  • Shift 1. Fires only while Shift 1 is held.
  • Shift 2. Fires only while Shift 2 is held.
  • Either. Fires while either Shift key is held. Offered only when you've bound both.

This lets one physical control do two — or three — jobs: bind the plain press to one function, then bind the same key with Shift 1 to a second and Shift 2 to a third.

None is not a fallback. Hold Shift and press a control that only has a None binding, and nothing happens. That's deliberate: the unshifted press is very likely mapped to something in your DJ app, and the whole point of a Shift layer is that shifted and unshifted are different mappings. If they collapsed back together, the layer would be pointless.

If you hold both Shift keys at once, every binding that matches fires — a Shift 1, a Shift 2 and an Either binding on the same control all go off together. There's no reason to do this, and no rule that picks a winner.

Your controller may already have a Shift layer

Many controllers send a different MIDI command when their own Shift button is held. On the DDJ-FLX2, a performance pad arrives on one channel unshifted and a different channel shifted, and the transport buttons change note number.

When that's true of the control you're binding, you don't need Fusor Studio's Shift rows for it. Hold your controller's Shift while you Learn, and the shifted command is bound directly — as far as Fusor Studio is concerned it's simply a different button.

Bind the Shift rows when:

  • the control doesn't change its command under Shift. Faders and knobs usually don't.
  • you want one control to fire under Either Shift key. No controller can express that on its own.
  • you want to choose which functions the Shift layer reaches, rather than taking whatever second command the hardware happens to send.

To find out which case you're in, Learn the control twice — once plain, once with your controller's Shift held — and compare the two Control cells. Same command both times means you need the Shift rows.

When one press fires two functions

Because every matching binding fires, two functions bound to one control can both run from a single press. The bindings table says so in orange above the list, naming the control, the Shift state, and the functions involved — for example "One press of Note C-1 ch9 with Shift 1 held fires Tempo Ramp and Auto / Manual."

The case this most often catches is Either overlapping a named key: an Either binding fires under Shift 1, so it fires alongside anything scoped Shift 1 on the same control, even though the two rows show different Modifier settings.

A Shift 1 binding and a Shift 2 binding sharing one control is not flagged. That's the ordinary way to get two functions out of one pad, and the two only ever overlap in the both-keys-held case above.

Clearing a Shift key

Click Clear in a Shift row and every binding scoped to that key drops to None, so you can't be left with a binding that has no way to fire. Fusor Studio tells you how many changed. An Either binding survives as long as the other Shift key is still bound.

Shift is hold-only: there's no latching Shift layer you tap on and off, and a profile has two Shift keys rather than several separately-valued modifiers.


Auto-reconnect

If you pick a port that isn't present yet, Fusor Studio doesn't fail outright. The profile stays activated, the light goes amber, and it polls for the named port.

Fusor Studio also watches an activated profile's port for the rest of the session. If the controller's USB cable is pulled, it loses power, or a hub drops it, Fusor Studio notices the port disappearing, closes it, and shows a "HW1-Controller disconnected: <port name>" warning. Detection requires two consecutive confirmations, roughly 6-9 seconds, so a momentary blip in the MIDI port list doesn't tear down a live controller.

Once a disconnect is confirmed:

  • The Activate toggle stays on. The connection light goes amber and reads Reconnecting….
  • The Input Mapping tab updates live, with no need to close and reopen it.
  • When the port reappears, Fusor Studio reopens it, re-applies the profile's bindings, and shows "Controller reconnected: <port name>". You don't need to reactivate the profile by hand.
  • The reconnect runs in the background, so you can keep using Fusor Studio normally.

Switch Activate off to stop polling.

What this doesn't cover. Fusor Studio detects the port disappearing. A controller that stays plugged in but stops responding (a wedged port) isn't caught by this check. If bindings do nothing but the controller is plugged in and Fusor Studio isn't showing HW1, unplug and replug it. If the port comes back under a different name (some devices and hubs do this), Fusor Studio won't find it, so reselect the port in the MIDI Input Port field and Activate again.


.fcontroller files

Each profile is a JSON file with the .fcontroller extension.

Where they live

.fcontroller files are stored in Fusor Studio's per-user data directory, under a controllers/ subfolder, not in your fusor library. Specifically:

PlatformPath
Windows%APPDATA%\fusor-studio\controllers\
macOS~/Library/Application Support/fusor-studio/controllers/
Linux~/.config/fusor-studio/controllers/

There's no button in Settings that opens this folder. Paste the path into Explorer or Finder. (Settings → Logging → Open log folder opens the logs/ folder alongside it, which is one level down from the user-data directory.)

Shape

A .fcontroller file is a JSON object:

{
  "format": "fcontroller",
  "version": 2,
  "meta": {
    "name": "DDJ-FLX2",
    "portName": "DDJ-FLX2",
    "created": "2026-04-12T18:03:11.000Z",
    "modified": "2026-06-08T22:41:47.000Z"
  },
  "modifierBindings": {
    "shift1": { "channel": 1, "type": "note", "number": 63 },
    "shift2": { "channel": 2, "type": "note", "number": 63 }
  },
  "bindings": [
    {
      "function": "armPlay",
      "channel": 1, "type": "note", "number": 62,
      "controlType": "button",
      "interactionMode": null,
      "invert": false,
      "modifier": "none"
    }
  ]
}
  • format must be "fcontroller" for Fusor Studio to load the file.
  • meta.name is the editable profile name; meta.portName is the saved MIDI port.
  • modifierBindings holds the two Shift bindings, shift1 and shift2. Either may be null.
  • bindings holds one entry per function.

Each binding's modifier field can be "none", "shift1", "shift2" or "either", set from the bindings table's Modifier dropdown or by hand-editing the file directly. Any other value matches nothing, so the binding never fires.

Profiles written before Fusor Studio supported two Shift keys say "version": 1 and carry a single modifierBinding with "shiftRequired" bindings. They still load, and their unshifted bindings still work — but the old Shift key is not read and the "shiftRequired" bindings match nothing. Learn both Shift rows again and save; the file is rewritten in the new shape.

Hand-editing

.fcontroller files are plain JSON. Copy a profile to another machine by copying the file; share a profile with another DJ the same way. Hand-edits take effect on next Activate (or after restarting Fusor Studio with auto-activation on).


Tips

  • Move the control a few times. Two or three reads give Fusor Studio enough samples to lock in the control type; one nervous tap can be misread.
  • If a knob keeps registering as a button, the value range Fusor Studio saw was too narrow. Sweep it through its full travel and try again.
  • Don't bind the same physical control to two functions under the same Modifier setting. Both fire, from the one press — which is almost never what you want. Give them different Modifier settings instead, and one control does two jobs.
  • Keep DJ-controller and Fusor-controller separate. Binding the same hardware to both Fusor Studio (via this tab) and your DJ app (via its mapping) makes every press fire twice.