Building a MIDI Footswitch for Mobius Looper

Circular Labs Mobius is a free AU/VST looper plugin. Eight parallel loops. Quantized switching. Half speed, reverse, multiply. Everything the Echoplex promised but in software. Ethan Tufts at Strymon performs as State Shirt with Mobius running inside Ableton. Full arrangements, built live.

The problem is controlling it. Hands on the guitar. You need your feet. Nobody sells a MIDI foot controller for Mobius.

So here’s one.

The finished MIDI footswitch controller, blue diecast aluminum enclosure with six chrome switches

The idea

Six footswitches. Each does three things: tap, double tap, hold. Up to 18 MIDI messages from a box the size of a paperback.

Expression pedal for loop feedback. RGB LEDs for state: recording, playing, overdubbing, reversed. Glance down and you know.

Footswitch layout: two rows of three switches, USB-B top left, expression jack top right

Bottom row: record, overdub, mute. The core workflow. Top row: undo, multiply, reverse. Double tap any top row switch to jump between four loops.

Parts

EU suppliers. Most of the cost is the Teensy and the switches.

PartSpecQtySourcePrice
MicrocontrollerTeensy 4.0 (without headers)1BerryBase / Exp-Tech~€30
FootswitchesMomentary Soft-Touch SPST-NO (Banzai SKU 41888)6Banzai Music€30
EnclosureDC-DD Diecast Aluminum 188x120x37mm1Banzai Music€12
LEDsWS2812B strip, cut to 6 individual LEDs (SEZO 1m 60LED)1Amazon DE€9
USB panel mountMEIRIYFA USB-B D-type female to USB-A female1Amazon DE~€7
Internal USB cablePAXO 30cm USB-A to Micro-B1Amazon DE~€6
Expression jack6.35mm TRS stereo panel mount1Banzai Music€2
Resistors470 ohm x1, 10K ohm x12on hand
Wire22-24 AWG stranded, multiple colorson hand
StandoffsM3 nylon for Teensy mounting4on hand

~€95 total.

Alternative suppliers

Reichelt, Mouser EU, Thomann carry most of these. The footswitches are hardest to source. Soft touch momentary, not clicky. The Banzai ones are quiet under bare feet or shoes.

Tools

Soldering iron, solder, wire strippers, multimeter. Drill bits: 12mm (switches), 5–8mm (LED holes), 10mm (TRS jack), 24mm (USB-B panel mount). Deburring tool. Hot glue gun for LED mounting.

Wiring

Circuit diagram showing Teensy 4.0 connections to six footswitches, WS2812B LED chain, expression pedal, and USB-B panel mount

Pin assignments

Teensy PinConnected ToNotes
Pin 1WS2812B data inThrough 470 ohm resistor
Pin 2SW1 (Record)INPUT_PULLUP, other leg to GND
Pin 3SW4 (Undo)INPUT_PULLUP, other leg to GND
Pin 4SW5 (Multiply)INPUT_PULLUP, other leg to GND
Pin 5SW6 (Reverse)INPUT_PULLUP, other leg to GND
Pin 6SW2 (Overdub)INPUT_PULLUP, other leg to GND
Pin 7SW3 (Mute)INPUT_PULLUP, other leg to GND
Pin 14 (A0)Expression pedal tip10K pulldown to GND
3V3Expression pedal ringReference voltage
VUSBWS2812B VCC5V power for LEDs
GNDCommon ground busAll grounds meet here

Pin numbers don’t follow switch layout. Pin 2 is SW1 but Pin 3 is SW4. I wired them in logical order on the Teensy and a different order in the enclosure. The firmware remaps.

Physical layout in the enclosure

Top down view of the finished controller showing six chrome footswitches on blue aluminum
BACK ROW (30mm from top edge)
   SW4 (Pin 3)     SW5 (Pin 4)     SW6 (Pin 5)
   Undo            Multiply        Reverse

FRONT ROW (80mm from top edge)
   SW1 (Pin 2)     SW2 (Pin 6)     SW3 (Pin 7)
   Record          Overdub         Mute

TOP LEFT: USB-B panel mount
TOP RIGHT: TRS expression jack

Connectors

Both mount on the front face. USB-B left, expression jack right. Below the top edge. Visible from the front, barely peeking out from above.

Front profile showing TRS expression jack and USB-B panel mount

LED chain wiring

Cut six individual LEDs from a WS2812B strip. Snake pattern: left to right across the top row, right to left across the bottom.

Data in → [LED0] → [LED1] → [LED2]
                                ↓
          [LED5] ← [LED4] ← [LED3]

Data order reverses on the bottom row. The firmware remaps:

const uint8_t SW_TO_LED[] = {5, 0, 1, 2, 4, 3};

Mount LEDs in drilled holes above each switch. Hot glue works fine. Keep the data wire runs short.

Ground scheme

Solder lug bolted inside the enclosure. Scrape the paint for bare metal contact. All grounds run to this single lug:

  • 6 switch grounds
  • TRS jack sleeve
  • Expression pedal 10K pulldown resistor

One wire from the lug to the Teensy GND pin. Star ground. No loops. No noise.

Expression pedal wiring

Standard TRS convention:

  • Tip goes to Pin 14 (A0) on the Teensy
  • Ring goes to 3V3
  • Sleeve goes to GND

10K pulldown from Tip to GND so the pin reads zero with no pedal connected. Parallel, not series.

Pedal works backwards? Swap Ring and Sleeve.

USB connection

USB-B D-type panel mount on the outside. Short USB-A to Micro-B cable to the Teensy inside. More reliable than a single adapter cable, and USB-B looks like it belongs on audio equipment. 24mm hole, D-type flange with screws.

Firmware

Two files. Clone the repo or drop them into footswitch_controller in your Arduino sketchbook.

github.com/fictionfred/mobius-footswitch

config.h is pin assignments, MIDI CC mapping, gesture timing, LED colors. Change this if your wiring differs from mine. footswitch_controller.ino is the gesture state machine, MIDI I/O, and LED animation engine.

Arduino IDE setup

  1. Install Arduino IDE
  2. Install Teensyduino
  3. Board: Teensy 4.0, USB Type: MIDI
  4. Libraries: Bounce2, Adafruit NeoPixel

How the gestures work

On release, the firmware waits 300ms. Second tap arrives, double tap fires. Nothing comes, single tap fires. Hold past 500ms fires immediately, no waiting.

Each switch runs its own state machine. No blocking. All six processed every loop cycle.

300ms: fast enough you don’t feel the delay, slow enough double taps register. I tried 200 and kept misfiring. 400 felt sluggish.

LED feedback

Not decoration. Information.

Bottom row: warm tones. Amber playing, deep red recording, warm white idle. Top row: cold tones. Ice blue active, cool white at rest.

The split came from the enclosure. Metallic blue aluminum. Warm amber and ice blue look right against it. Green for “playing” looked like a cheap toy.

Modes: solid, dim, blink (three speeds), sine wave pulse (10–100% brightness), 150ms tap flash. Global brightness at 50/255. For glancing at in a dim room.

MIDI mapping

Tap (primary)

SwitchCCFunction
Record1Start/stop recording
Overdub2Add layers
Mute3Silence loop, keep it running
Undo4Step back one layer
Multiply5Extend loop length
Reverse6Toggle reverse playback

Double tap (secondary)

SwitchCCFunction
Record11Clear loop
Overdub12Half speed (the Ed O’Brien trick)
Mute13Select Loop 4
Undo14Select Loop 1
Multiply15Select Loop 2
Reverse16Select Loop 3

Hold (modifier)

Three switches mapped. Record, Undo, and Multiply hold slots reserved.

SwitchCCFunction
Overdub22Insert
Mute23Pause
Reverse26Speed toggle

Half speed on Overdub. The Ed O’Brien trick. Record a loop, drop it half speed. Falls an octave, stretches to twice the length. Layer on top.

Top row double taps jump between loops: Undo → Loop 1, Multiply → Loop 2, Reverse → Loop 3. Loop 4 on Mute because the top row was full.

Expression pedal

CC 7, feedback. Full toe: infinite repeats. Full heel: decay.

Mobius configuration

Binding XML

Configuration → Bindings. Import mobius_bindings.xml or add bindings manually with Capture.

<BindingSet name="Footswitch v3" ordinal="0">

  <!-- TAP (CC#1-6) -->
  <Binding name="Record" trigger="control" channel="1" value="1"/>
  <Binding name="Overdub" trigger="control" channel="1" value="2"/>
  <Binding name="Mute" trigger="control" channel="1" value="3"/>
  <Binding name="Undo" trigger="control" channel="1" value="4"/>
  <Binding name="Multiply" trigger="control" channel="1" value="5"/>
  <Binding name="Reverse" trigger="control" channel="1" value="6"/>

  <!-- Expression pedal -->
  <Binding name="feedback" trigger="control" channel="1" value="7"/>

  <!-- DOUBLE-TAP (CC#11-16) -->
  <Binding name="Clear" trigger="control" channel="1" value="11"/>
  <Binding name="Halfspeed" trigger="control" channel="1" value="12"/>
  <Binding name="SelectLoop" trigger="control" channel="1" value="13" arguments="4"/>
  <Binding name="SelectLoop" trigger="control" channel="1" value="14" arguments="1"/>
  <Binding name="SelectLoop" trigger="control" channel="1" value="15" arguments="2"/>
  <Binding name="SelectLoop" trigger="control" channel="1" value="16" arguments="3"/>

  <!-- HOLD (CC#21-26) -->
  <Binding name="Insert" trigger="control" channel="1" value="22"/>
  <Binding name="Pause" trigger="control" channel="1" value="23"/>
  <Binding name="SpeedToggle" trigger="control" channel="1" value="26"/>

</BindingSet>

Manual binding with Capture

One at a time:

  1. Open Mobius, Configuration, Bindings
  2. Select or create “Footswitch v3” binding set
  3. Click a function in the left panel (e.g. Record)
  4. In the Trigger section, set Type to Control, Channel to 1
  5. Check Capture, then press the corresponding footswitch
  6. The CC number fills in automatically
  7. Leave Release unchecked
  8. Click Save

Session settings

Without quantization, loops drift.

SettingValueWhy
Sync SourceHostLogic Pro is the tempo master
QuantizeLoopFunctions execute at loop boundary
Switch QuantizeLoopLoop switching waits for boundary
Subcycles4Loop divided into 4 sections
Empty Loop ActionCopy TimingNew loops inherit length from current
Empty Track ActionCopy TimingSame for new tracks
Max Undo10+Keep plenty of undo layers
Mute ModeContinueLoop keeps running when muted

Build sequence

This order avoids rework.

  1. Test on breadboard first. Wire two switches and two LEDs. Verify MIDI messages appear in a MIDI monitor. Verify LEDs respond. Do not touch the enclosure until this works.
  2. Solder wires to the Teensy. No headers. Direct solder. This keeps the profile low inside the enclosure.
  3. Test all six switches and all six LEDs on breadboard. Verify every CC number, every LED index.
  4. Drill the enclosure. Pilot holes first. 12mm for switches, 5-8mm for LED holes, 10mm for TRS, 24mm for USB-B. Deburr everything.
  5. Mount panel components loosely. Switches, TRS jack, USB mount. Do not tighten yet.
  6. Install the ground lug. Scrape paint, bolt it down, check continuity to enclosure.
  7. Mount the Teensy on nylon standoffs inside the enclosure.
  8. Wire the ground bus. All switch grounds, TRS sleeve, and pulldown resistor to the solder lug.
  9. Wire switches to their Teensy pins.
  10. Wire the LED chain with the 470 ohm resistor on the data line.
  11. Wire the expression jack. Tip to A0, Ring to 3.3V, Sleeve to ground bus.
  12. Connect USB panel mount to Teensy via the internal cable.
  13. Test everything before closing. Every switch, every LED, the expression pedal. Use a MIDI monitor.
  14. Tighten and close.

Things that went wrong

USB-C adapter DOA. Adafruit 4056, USB-C to Micro-B. Zero power passthrough. The USB-B panel mount was the better choice anyway. More robust, standard cables.

3.3V driving 5V LEDs. Datasheet says WS2812B needs 3.5V minimum for logic high. 470 ohm resistor on the data line and short runs made it work. If it doesn’t, add a 74AHCT125 level shifter. I bought one and never needed it.

10ms debounce. Expected to need 20ms. Never saw a double trigger at 10.

What I would do differently

Label the switches. Layout took a week to memorise. An engraved faceplate would help anyone else.

LED diffusers. Raw WS2812Bs are point sources. A frosted cap over each would soften the light.

MIDI DIN output for hardware that doesn’t speak USB.

Everything you need

Parts, wiring, firmware, Mobius configuration. If you build one, or build something better, I’d like to hear about it.