The Open Stage Control gamepad hybrid is the most underrated rig in live electronic music. Open Stage Control 1.27 is a free, cross-platform OSC + MIDI surface designer that runs in any browser, talks to anything, and beats most $1,000 commercial options after a few hours of tinkering. Pair it with a DualSense OSC controller setup and you get precise screen widgets where you want them, plus 16 buttons, two analog triggers, and twin sticks on a wireless pad. This is the full hybrid — routing, widgets, a working session file, latency tuning.
- What you do: run Open Stage Control as an OSC server, route the gamepad MIDI through a translator to OSC, build a hybrid surface combining touch widgets and gamepad inputs.
- What you need: Open Stage Control 1.27+, Universal Controller MIDI, Bome MIDI Translator or a Node script for MIDI→OSC, target software (Reaper, Ableton, Bitwig, hardware).
- Time: 45 minutes for the first hybrid session, 10 minutes for subsequent ones from the template.
- Cost: Open Stage Control is free, the bridge is
$89Pro, Bome MTP is$59if you go that route — or use the free Node script.
What you'll learn
- The parallel-routing pattern — send MIDI direct to the DAW for speed, OSC to the surface for visuals.
- How to write a 30-line Node MIDI→OSC bridge that normalises everything to
0..1floats. - Three Open Stage Control widget patterns I reuse: gamepad HUD, encoder-driven macros, modal d-pad tabs.
- Why the built-in
gamepadmodule is 4× slower than the dedicated bridge — and when that's still fine. - How to project the OSC surface as audience-facing visualisation while it drives the audio.
Touchscreens lose to muscle memory every time
Open Stage Control gives you faders, XY pads, scope displays, matrix mixers, infinitely tweakable layouts. What it can't give you is the muscle memory of a physical button or the analog feel of a thumbstick. The DualSense fills that gap. Touchscreen handles the things you only adjust occasionally (EQ, sends, reverb size). Controller handles the things you adjust continuously while looking at the stage — drum hits, filter sweeps, scene launches.
The split that works for me
- Tablet / screen surface: master fader, 8 channel faders, master FX wets, transport, scene grid, EQ macros.
- DualSense: pad triggers (face buttons), filter cutoff + resonance (triggers), pan + send (sticks), session navigation (d-pad), XY freeze (touchpad).
Three routing options — and only one I actually use
Open Stage Control is an OSC client/server. The DualSense bridge speaks MIDI natively. Three ways to bolt them together:
- MIDI → OSC bridge: bridge sends MIDI, a small translator (Bome MIDI Translator, or a 30-line Node script) converts it to OSC, Open Stage Control reads OSC.
- Direct gamepad in OSC: Open Stage Control has a built-in
gamepadmodule that reads HTML5 Gamepad API events. Less flexible than the bridge but no extra software needed. - Parallel routing: bridge sends MIDI to the DAW directly for time-critical things (drum hits), and a copy goes to Open Stage Control for visualisation only.
Parallel routing is what I run in real sessions. Drum hits go straight to the DAW at ~3 ms. A copy of every CC also goes to Open Stage Control so the on-screen widgets reflect the controller state and act as a visual feedback layer. Best of both, no compromise.
Step-by-step — full hybrid session
1. Install Open Stage Control
Download the 1.27 or later build from the official site (widget reference lives on the GitHub wiki). It's a standalone Electron app plus a CLI. Launch it once to confirm the control surface opens at http://127.0.0.1:8080.
2. Install Universal Controller MIDI
Grab Universal Controller MIDI, plug in your DualSense, confirm connection. Set the output port to IAC OSC-Bridge (create it in Audio MIDI Setup → MIDI Studio → IAC Driver) or loopMIDI Port 1 on Windows.
3. Wire the MIDI → OSC translator
Behold: 30 lines of Node that does the job.
// Tiny Node script — midi-to-osc.js
// npm install easymidi node-osc
const easymidi = require('easymidi');
const { Client } = require('node-osc');
const input = new easymidi.Input('IAC OSC-Bridge');
const osc = new Client('127.0.0.1', 8080);
input.on('cc', ({ channel, controller, value }) => {
osc.send(`/cc/${channel}/${controller}`, value / 127);
});
input.on('noteon', ({ channel, note, velocity }) => {
osc.send(`/note/${channel}/${note}`, velocity / 127);
});
console.log('MIDI → OSC bridge running.');
Run it: node midi-to-osc.js. Every MIDI message becomes a normalised OSC message at /cc/<ch>/<num> or /note/<ch>/<num>. Don't want to write code? Bome MIDI Translator Pro has a built-in MIDI-to-OSC preset that does the same thing.
4. Build the Open Stage Control session
Launch Open Stage Control with a session file pointing at the same OSC port (default 8080). The simplest hybrid layout:
// session.json (excerpt)
{
"type": "tab",
"label": "Live Set",
"widgets": [
{
"type": "fader",
"label": "Master",
"address": "/master",
"range": { "min": 0, "max": 1 }
},
{
"type": "matrix",
"widget": {
"type": "button",
"address": "/note/1/{x*16+y+60}",
"label": "Pad {x}-{y}"
},
"rows": 4, "cols": 4
},
{
"type": "xy",
"label": "Touchpad mirror",
"address": "/touch/xy",
"listenTo": ["/cc/1/16", "/cc/1/17"]
}
]
}
The matrix widget builds a 4x4 button grid mirroring the face-button presses. The xy widget visualises the touchpad in real time — its listenTo array catches the CCs coming from the bridge, so the screen XY pad moves when you swipe the controller.
5. Connect Open Stage Control to your DAW
Open Stage Control speaks OSC out as well as in. Add a target in Settings → Send pointing at your DAW — Reaper's OSC port (full walk-through in the Reaper OSC + MIDI guide), Bitwig's OSC controller script, or an Ableton Max for Live OSC patch. Widget changes propagate downstream, and the gamepad inputs both drive the DAW via MIDI and animate the on-screen surface.
Widget patterns I reuse constantly
Gamepad heads-up display
A non-interactive widget panel showing live state for every gamepad input. Two columns of 16 LEDs for the buttons, four mini faders for the stick axes, two for triggers, an XY pad for the touchpad. Pure visual feedback. Hugely useful for debugging — and for the audience-facing visualisation you might project behind a live set.
Macro encoders driven by sticks
Each stick axis drives an Open Stage Control encoder widget with infinite rotation and on-screen value. The encoder address points at the DAW's macro CC. Stick movements increment / decrement instead of replacing absolute values — way nicer for fine adjustments than raw absolute mapping.
Modal mode switcher — triple your surface with one trick
Open Stage Control supports tabs and modal pages. Bind the d-pad to switch tabs: up = mixer, down = effects, left = scene, right = instrument. Same buttons do different things depending on the active tab. This single trick triples your effective control surface without adding a single button.
Latency benchmarks — the built-in module loses by 4x
Measured with a Reaper session, Mac M1. End-to-end is button press → bridge → Node translator → Open Stage Control → OSC out → Reaper. Direct MIDI included for reference.
| Path | Mean | P95 |
|---|---|---|
| Direct MIDI bridge → DAW | 3.2 ms | 4.7 ms |
| Bridge → Node MIDI→OSC → OSC server → DAW | 5.8 ms | 9.1 ms |
| Bridge → Bome MTP → OSC → DAW | 4.9 ms | 7.8 ms |
| Built-in Open Stage Control gamepad module | 11.2 ms | 18.6 ms |
OSC vs MIDI byte-rate — the heavier-protocol myth, busted
OSC's "feels heavier" reputation is half right and half wrong. A single OSC message is bigger than a single MIDI message, but OSC carries floats directly — no 14-bit MSB/LSB pairs for high-res values. Same gamepad gesture (a full stick sweep, 1 second of motion) measured on both wires:
| Gesture | MIDI bytes/s | OSC bytes/s | Resolution | Notes |
|---|---|---|---|---|
| Stick X sweep (7-bit CC) | ~600 | ~3,200 | 128 steps | OSC heavier, no benefit |
| Stick X sweep (14-bit CC pair) | ~1,200 | ~3,200 | 16,384 steps | OSC wins on framing overhead |
| Touchpad XY (bundled) | ~2,400 | ~3,600 | 14-bit X+Y | OSC bundles 2 axes per packet |
| Single button press | ~6 | ~52 | 1 bit | MIDI obviously wins |
| 32-pad scene snapshot | ~480 | ~340 | Mixed | OSC wins on bundles |
| Per-frame state mirror | ~1,800 | ~720 | Floats 0..1 | OSC reads cleaner downstream |
The built-in gamepad module is by far the slowest — it polls the HTML5 Gamepad API on a browser timer. Time-critical inputs (drum hits, scene launches) always go through the dedicated bridge. Reserve the built-in module for visual mirroring only.
The full session I run for live techno sets
Six channels in Ableton, six effect returns, two synth racks driven from the DualSense, Open Stage Control tablet handling everything else.
- Cross / Circle / Square / Triangle: drum rack pads 1–4 (Note 60, 62, 64, 65 on channel 10).
- L1 / R1: scene previous / next (Note 67, 69 on channel 16, picked up by a Max for Live device).
- L2 trigger: lead synth filter cutoff (CC 1 on channel 2). Trigger also drives an Open Stage Control fader for visualisation.
- R2 trigger: master reverb wet (CC 11 on channel 16). Also drives an OSC widget.
- Left stick: pad synth attack/release morph (CC 3/4).
- Right stick: send A wet / send B wet (CC 5/6).
- Touchpad: macro X/Y on a Macro 1+2 device. Touchpad press toggles tape stop emulation.
- D-pad: switch Open Stage Control tabs between Mixer / FX / Scene / Macro pages.
Tablet runs the 8-channel mixer, a 16-pad clip-launch grid, four send wets, the gamepad HUD, and a scope display of the master output. The split feels effortless after a couple of sessions — eyes on tablet for big-picture, hands on controller for tactile.
OSC-only setup — when to skip MIDI entirely
If everything in your rig speaks OSC (TouchDesigner, Resolume, Ossia Score, Reaper with the OSC plugin, Bitwig with the OSC controller script), skip MIDI entirely. Configure the bridge to emit OSC directly via Settings → Output → Protocol → OSC. You lose ~0.5 ms to UDP framing and gain readable addresses like /gamepad/buttons/cross instead of note numbers. The OSC vs MIDI deep dive covers the trade-offs.
Tips that took me too long to figure out
- Bind the bridge to
127.0.0.1, not0.0.0.0. Open Stage Control will helpfully accept OSC from anywhere if you don't, and your DAW will fight your translator for the port. - Normalise values in the translator, not in the widgets. Send
0..1floats from MIDI→OSC. Open Stage Control's widget ranges stay clean. - Use Open Stage Control's session autosave. Sessions live as JSON, and
--save-sessionon the command line writes every change. I lost an evening's mapping work to a crash before I learned this. - Bind a "panic" button. Touchpad click sends
/panicwhich firesAll Notes Offon every MIDI port. Stuck-notes recovery in one button. - The browser tab in the background slows down. Chrome throttles backgrounded tabs to 1 Hz timer. Use the standalone Open Stage Control app, not a browser, for live sessions.
Project the surface behind the stage — visualisation tied to performance
Open Stage Control surfaces are HTML, which means they project nicely onto a second screen. Build a session that mirrors the gamepad state — pad LEDs lighting up as you trigger them, fader bars sliding with stick movements, real-time scope of the master output — and send the browser to a TV behind your kit. The audience sees visualisation genuinely tied to the performance instead of generic VJ loops. Combined with a small TouchDesigner patch on the same OSC port (covered in the TouchDesigner DualSense post), one controller drives reactive video and audio.
The "control room" overview tab
I keep a separate tab in every session purely for status: port state, MIDI message rate, OSC packet rate, current preset name, controller battery (the bridge exposes this on /gamepad/battery). Nothing in this tab is interactive — it's read-out, like a synth's status display. The minute shows start mattering, this overview saves panic during soundcheck when something has gone weirdly quiet.
Two controllers, one surface
Open Stage Control's listenTo arrays let widgets respond to multiple input addresses. Connect two DualSense pads via the bridge and both can drive the same widgets, surface showing combined state. Useful for band setups — keys player and synth player both adjust the same reverb wet without stepping on each other.
FAQ
Does Open Stage Control 1.27 read a gamepad natively?
Yes, via the built-in gamepad module that polls the HTML5 Gamepad API. It works for visual mirroring but lags around 11 ms mean / 18 ms P95 because it runs on a browser timer. For drum hits and scene launches, route through Universal Controller MIDI plus a MIDI-to-OSC translator instead.
What's the lowest-latency Open Stage Control gamepad path?
Send time-critical MIDI directly from the bridge to the DAW (≈3 ms), and forward a copy through a MIDI-to-OSC translator into Open Stage Control purely for visualisation. You get instant playback plus a live HUD without compromising one for the other.
Can Open Stage Control replace a Push or APC?
For OSC-fluent rigs (Reaper, Bitwig, Ableton with Max for Live, TouchDesigner, Resolume), yes — and beyond what a Push can do because you build the layout. A DualSense adds the physical buttons and analog sticks that touchscreens can't match.
Does the Open Stage Control gamepad rig work on Windows and Linux?
Yes. Open Stage Control runs on macOS, Windows, and Linux. Universal Controller MIDI ships Mac and Windows builds; on Linux, swap the bridge for a small Python or Node HID-to-MIDI script and the rest of the chain is identical.
The verdict: that's the hybrid OSC + gamepad rig in one post, with the extras that take it past "it works" into "I want to play this every night." Grab the bridge, install Open Stage Control, run the translator, and you have a control surface that beats most commercial options and folds into a backpack.