Hardware Controller

A hardware controller in Fusor Studio is any physical MIDI controller bound to Fusor commands: arming transitions, firing pads, toggling modes. Fusor Studio splits controller duty into two jobs: the DJ controller, watched for your hand on a knob or fader while you mix, and the Fusor controller, whose buttons fire Fusor Studio's own commands. By default one physical controller does both jobs. You can dedicate a separate, smaller controller to the Fusor job instead, whichever fits your rig.

This page covers the DJ controller and Fusor controller tabs of the Settings window's Mapping entry, where controller bindings live: choosing or creating a profile, MIDI-Learning bindings, and the binding model. For the canonical-mapping side of Settings (the DJ-app side), see Teach Mode.

Each binding belongs to a function, and you set it up once: the profile then persists across sessions.


The controller profile bar

Both controller tabs share the same bar at the top: a Controller profile dropdown and a gear icon beside it.

DJ controller's picker lists every profile you've created, plus None. Choosing a profile makes it your DJ controller; choosing None disconnects it.

Fusor controller's picker is a live choice. With a DJ controller chosen it lists Same as my DJ controller, the default, so one device does both jobs; then None; then every profile whose MIDI input differs from the DJ controller's. With no DJ controller it has one entry, None. None with a DJ controller means no Fusor controller: this tab shows "No Fusor controller is chosen. Choose one above, or make a new profile." with New profile. A profile that shares the DJ controller's MIDI input is never offered here, because the two controllers can't share an input. Choosing that same profile as your DJ controller later returns the Fusor controller to Same. On Same, this tab edits the DJ controller's profile and says so, above the grid: "You are editing <name>, your DJ controller's profile."

Choosing a profile on either tab makes it the active controller for that job and connects it, using the MIDI input stored in that profile; the same choices are offered on Settings ▸ Connection, and the two pages always agree. The connection state itself, green Connected, orange Not plugged in, or grey None chosen, is reported on Connection, not here.

The gear opens a popover with everything else profile management needs:

FieldWhat it does
Profile nameEdit the profile's name. Written when you stop typing, leave the field, or press Enter.
MIDI inputWhich port the profile listens on. Lists every MIDI input Fusor Studio can see.
Clear DJ controls (DJ controller tab) / Clear Fusor controls (Fusor controller tab)Clears that tab's job from the selected profile, leaving the other job alone. Shown while the profile has something on that tab to clear.
New profile / Delete profileCreate a fresh profile, or remove the selected one from disk.

Clear DJ controls removes the profile's learned knobs and faders and resets that tab's tested and hidden marks. Clear Fusor controls removes its button bindings and its Shift keys and resets that tab's marks. On Same as my DJ controller, one profile holds both jobs, and each Clear leaves the other job's controls in place.

Delete profile always asks first. The prompt names what goes with the profile: its DJ controller knobs, its Fusor controls, or both. Cancel and Delete are the buttons. Each Clear asks first too, with Cancel and Clear. Nothing is removed until you confirm.

Every field is saved as you change it. There is no Save button anywhere in Mapping.

You can keep several profiles side by side: one per physical controller, or several variants of the same controller. Each tab has one active profile at a time, and the DJ controller and Fusor controller can have different profiles active together, once the Fusor controller is set to something other than Same. Choosing a different profile on a tab deactivates the previous one for that job before activating the new one. Deleting a profile disconnects only the job that was using it, leaving the other job, if any, untouched.

Two controllers, one job each

Choosing a separate profile on Fusor controller splits the two jobs strictly. Only the Fusor controller's buttons fire Fusor Studio: a Fusor function bound on the DJ controller's profile stops firing while the Fusor controller is separate. That binding isn't deleted; it comes back the moment you switch the Fusor controller back to Same as my DJ controller.

Choosing None for the Fusor controller while a DJ controller is chosen has the same effect on the DJ controller's Fusor controls (its bindings and Shift keys do nothing) but opens no second device. The DJ controller's learned controls are still watched. Nothing is deleted from the profile, and choosing Same again brings the Fusor controls back.

The Fusor controller is never watched for pickup, whichever profile it's set to. Pickup applies only to the DJ controller tab's learned knobs and faders. A Shift key you've learned changes only the controller it was learned on: a Shift key learned on the DJ controller has no effect on Fusor controller bindings, and one learned on the Fusor controller has no effect on DJ controller bindings.

DJ controller can be set to None while Fusor controller is separate. Fusor Studio's buttons still work; nothing is watched for pickup, because there's no DJ controller to watch.

Port errors

If the port can't be opened, a red panel in the gear popover 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, and it works a little differently on the two tabs: DJ controller listens for a knob or fader you move and settle on; Fusor controller listens for a button you press.

Learn listens on the MIDI input selected for the profile you're editing, regardless of which controller happens to be active. You don't need to make a profile active first: pick a port for a brand-new profile and Learn works immediately.

DJ controller

Click Learn in a cell, then move that control on your controller. Fusor Studio saves it when you let go, after the same ~400 ms settle Send/Test use elsewhere. Move it again afterward and the cell lights briefly to show the message arrived, which is how you confirm the binding. Tick the Tested check once you're satisfied.

Learning a control on a profile that wasn't already your DJ controller makes it your DJ controller, and a notice above the grid says so: "<name> is now your DJ controller."

Three outcomes can interrupt a listen:

  • Two controls moved at once. Fusor Studio received MIDI from two different controls while you moved one. Nothing is saved; Try Again.
  • That control is already learned, for another cell. Nothing is saved; Try Again, or Use It for <this control> Instead, which moves the learned message onto the new cell.
  • No MIDI for 10 seconds. Keep Listening, or stop (Cancel in Settings, Skip in Guided Setup).

Esc cancels a listen in progress, on either tab.

Learning a control makes it one the Fusor player watches: during a run, the player releases that control to you at pickup, when the control reaches the player's current value, rather than on first touch. See Manual takeover. Every control on this tab is optional. An unlearned or hidden one is released to you on first touch instead, as soon as the DJ app reports a value that is not an echo of the player's own.

DJ controller only offers knobs and faders: buttons have no position to pick up, and selectors are rare on a controller. The essentials Guided Setup asks for start with the Crossfader, once, then EQ High, Mid, Low, Filter, Volume, and Tempo per deck. The rows on this tab follow the same order: the Crossfader group first, with the Crossfader row ahead of the per-deck crossfader-assign buttons, and the EQ rows reading High, Mid, Low.

Fusor controller

Click Learn in a row, then press the button on your controller that should fire it. Fusor Studio uses the most frequent MIDI source in the learn buffer, not just the last message, so a stray message from a neighboring control does not get bound instead. Press the intended control a couple of times. There's no 10-second no-MIDI prompt on this tab.

If the profile has a Shift binding, hold it down while you press the control 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 is no gesture for Either, which is chosen from the dropdown. Press Shift alone, before you have touched the control, and Fusor Studio shows a hint rather than capturing nothing: "Shift 1 held. Now press the control to bind it with Shift 1."

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. If a control is detected wrongly, re-Learn it and repeat the motion a few more times so the pattern is unambiguous.

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 when connecting the profile (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, and 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. That lets you set up a second controller's profile while the first one is in use.

When the profile you're editing is the active one, its controller also keeps working while you Learn. Pressing a button or pad that is already bound fires its function, even while you're re-learning it: re-learn the Arm/Play pad and the transition arms.


Functions (Fusor controller)

Each row is one function Fusor Studio can perform in response to a MIDI message. The functions are grouped as Shift, Transition, Browse and Pads.

A function works like a click on its on-screen control: where that control is greyed out or hidden, the press does nothing, and the on-screen button, where one is shown, flashes red. Three exceptions keep working when their control is not on screen: Arm / Play and Abort / Restore in Pad Mode, Pad 1 – Pad 8 outside Pad Mode, and Next / Prev Fusor and Transition in Pad Mode.

FunctionWhat it does
Arm / PlaySame as the Arm/Play button on the progress strip: arms the loaded fusor, then starts or pauses it depending on state.
Abort / RestoreSame as holding the Abort button on the progress strip: aborts the running transition, and after an abort, when the button reads RESTORE, puts the controls back. See Arming and running. Does nothing while the fusor is armed but not yet running, where the on-screen Abort is greyed out.
Run ModeSteps the Run Mode switch through Auto, Mixed and Manual, then back to Auto, skipping Mixed unless the loaded fusor's mix point is Middle, or End with an effect tail. Does nothing with no fusor loaded. During a run on the clock, pressing it is the same hold as holding Manual on the switch, so one held press is the takeover.
Run Mode: Auto / Run Mode: Mixed / Run Mode: ManualOptional, for controllers with spare pads. Each does what clicking that position on the Run Mode switch does, including the 0.4-second holds during a run on the clock: Manual takes the run over, Mixed during an Auto run adds the stop at the mix point, Auto during a Mixed run before its stop cancels it. See The Run Mode switch.
Start with IncomingToggles the Start-with-Incoming opt-in. Does nothing in Pad Mode or with no fusor loaded, where the on-screen toggle is unavailable too.
Tempo RampToggles the Tempo Ramp option. Turning it on does nothing with no fusor loaded.
Swap RolesSame as the Swap Roles button in the toolbar: swaps which deck is incoming and which is outgoing. Does nothing where the button can't be clicked: during a transition, in Pad Mode, or when the button is hidden (Online, with Show Manual Role Swap while Online off in Settings). See Manual Role Swap.
Pad ModeSame as the Pad Mode button in the toolbar: turns Pad Mode on or off.
Next Fusor / Prev FusorLoad the next / previous fusor in the active collection. See Browsing fusors from the controller.
Pad 1 – Pad 8Fire the action assigned to each pad slot in Pad Mode.

Without Fusor Studio Plus, the Next Transition and Prev Transition rows are hidden. Saving a profile removes any binding on them, and a binding left in the file is ignored, so it cannot block the same MIDI message bound to a row you can see.

Each row has a Tested check, the same kind Teach Mode uses: your own record, set only by you.

Each row has the same controls:

  • Learn starts MIDI Learn for this row.
  • Clear removes the binding.
  • Inv is the invert switch. It reverses the trigger polarity, firing on release or CC < 64 instead of press or CC ≥ 64. Use it when your hardware sends release-side messages, or when a binding fires on the wrong half of a foot switch. It's off and unavailable for the press-and-hold functions.
  • Type (badge) shows the detected control type.
  • Modifier is a dropdown: None, plus the Shift keys this profile has learned, plus Either once both are learned. See The Shift rows below.

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 Fusor 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 are browsing, your position in it, and how many there are. The fusor's own name is not repeated there because the picker button is already showing it. With no active collection set, the list is your whole fusor library and the line reads All Fusors instead.

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

  • 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, and disarms.

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 gives its other controls a second function, and many have two, one per deck. The DDJ-FLX2 is one of them. Fusor controller has a Shift 1 and a Shift 2 row at the top of its list, 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.
  • A Shift key works only while held; it cannot be latched on.
  • 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 your choice. Fusor Studio reads which MIDI command arrived, so 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 once you've learned both.

That 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.

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. No rule 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 is true of the control you are binding, Fusor Studio's Shift rows are unnecessary for it. Hold your controller's Shift while you Learn, and the shifted command is bound directly, because as far as Fusor Studio is concerned it is 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 are in, Learn the control twice, once plain and 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 list says so in orange above it, naming the control, the Shift state, and the functions involved, for example "One press of Note C-1 · ch 9 with Shift 1 held fires Tempo Ramp and Run Mode. Give them different Modifier settings if that isn't what you want." The Control cells of those rows are orange too, so you can spot them while scrolled down the list.

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.


Hiding a row

Both controller tabs work the same way Teach Mode does: the … menu on a row holds Hide and Clear row, and Show hidden, at the top of the screen, brings hidden rows back greyed. Hidden rows are remembered per controller on both controller tabs; Teach Mode remembers its own hidden rows per DJ app instead. Hiding a row changes nothing about how the underlying control or function works.


Auto-reconnect

If you pick a port that isn't present yet, Fusor Studio doesn't fail outright. The profile stays chosen, and Fusor Studio polls for the named port. Settings ▸ Connection reports the state while it does, orange Not plugged in.

Fusor Studio also watches each active profile's port for the rest of the session, DJ controller and Fusor controller alike. If a 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 "<job> unplugged: <port name>" warning, naming the job it lost, for example "DJ controller unplugged: LPD8 mk2" or "Fusor controller unplugged: LPD8 mk2". Detection requires two consecutive confirmations, roughly 6-9 seconds, so a port missing from a single check does not disconnect a working controller.

Once a disconnect is confirmed:

  • The profile stays chosen. Connection's light for that card turns orange, reading Not plugged in.
  • Both controller tabs update live, with no need to close and reopen them.
  • When the port reappears, Fusor Studio reopens it, re-applies the profile's bindings, and shows "<job> reconnected: <port name>". You don't need to choose the profile again.
  • The reconnect runs in the background, so you can keep using Fusor Studio normally.

Choose None for the DJ controller, or switch the Fusor controller back to Same as my DJ controller, to stop polling for that job.

What this doesn't cover. Fusor Studio detects the port disappearing. A controller that stays plugged in but stops sending MIDI 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 gear popover's MIDI input field.


No MIDI from the controller

If Fusor Studio receives no MIDI from the controller on the selected port, both controller tabs show "No MIDI from <controller>" in place of the grid:

Fusor Studio isn't receiving MIDI from this controller. It may be in a mode that sends only to your DJ app, or it isn't connected to this computer, and Fusor Studio can't tell which.

Transitions still run. Knobs you move are handed to you as before, and to take over a whole transition, hold the Run Mode button.

with Listen Again and Continue Without It.

While no MIDI arrives from the controller, Allow crossfader takeover during a run is unavailable, and its greyed-out reason links back to DJ controller.


.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. Go up one level and controllers/ is beside it.)

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"
    }
  ],
  "learnedControls": {},
  "mappingMarks": {
    "learn": { "tested": [], "hidden": [] },
    "drives": { "tested": [], "hidden": [] }
  }
}
  • 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, written by Fusor controller.
  • learnedControls holds what DJ controller has learned, one entry per address.
  • mappingMarks holds the Tested checks and hidden rows for the two controller tabs, split by tab.

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

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 the next time Fusor Studio reads the file: when you next choose that profile, or after restarting Fusor Studio.


Four things to know

  • Move the control a few times. Two or three reads give Fusor Studio enough samples to detect the control type; a single press 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.
  • Do not bind the same physical control to two functions under the same Modifier setting. Both fire from the one press. Give them different Modifier settings instead, and one control does two jobs.
  • Do not bind a Fusor function to a button your DJ app's mapping also uses. Both respond to the same press.