A Python bridge that converts MIDI messages from an Allen & Heath XONE:K2 controller into OSC (Open Sound Control) messages.
- Real-time MIDI to OSC conversion
- Full 3-layer support (RED/AMBER/GREEN)
- Support for all XONE:K2 controls:
- Rotary potentiometers (12 knobs × 3 layers = 36 controls)
- Rotary encoders (6 encoders × 3 layers = 18 controls)
- Linear faders (4 faders × 3 layers = 12 controls)
- Buttons (20 buttons × 3 layers = 60 controls)
- Special buttons (LAYER, EXIT, encoder switches)
- Tri-color LED support for button feedback
- Configurable OSC destination
- Verbose and quiet modes for debugging
- MIDI port listing utility
- Comprehensive error handling and logging
- Python 3.7+
- Allen & Heath XONE:K2 controller
- Dependencies listed in
requirements.txt
- Clone or download this repository
- Install dependencies:
pip install -r requirements.txtpython bridge.pyThis will connect to the default XONE:K2 MIDI port and send OSC messages to 127.0.0.1:5111.
python bridge.py --host 192.168.1.100 --port 8000 --midi "XONE:K2"Options:
--host OSC-host: OSC destination hostname or IP (default: 127.0.0.1)--port OSC-port: OSC destination port (default: 5111)--midi MIDI-port: MIDI device name (default: XONE:K2)-v, --verbose: Enable verbose debug output-q, --quiet: Suppress non-error output--list-ports: List available MIDI ports and exit
python bridge.py --list-portsMessages are sent in the following format:
/xone/k2/layer{N}/{control_type}/{control_id} {value}
Where {N} is the layer number (1=RED, 2=AMBER, 3=GREEN).
Control Types:
rp- Rotary potentiometers (value: 0-127)re- Rotary encoders (value: "inc" or "dec")fader- Linear faders (value: 0-127)button- Buttons (value: "pressed" or "released")
Examples:
/xone/k2/layer1/rp/1 64- Layer 1 (RED) rotary pot 1 at middle position/xone/k2/layer2/re/2 inc- Layer 2 (AMBER) rotary encoder 2 turned clockwise/xone/k2/layer3/fader/3 127- Layer 3 (GREEN) fader 3 at maximum/xone/k2/layer1/button/A pressed- Layer 1 button A pressed/xone/k2/layer2/button/EXIT pressed- Layer 2 EXIT button pressed
The XONE:K2 supports 3 layers when Latching Layers mode is enabled:
- Layer 1 (RED) - Default layer
- Layer 2 (AMBER) - Toggle by pressing LAYER button once
- Layer 3 (GREEN) - Toggle by pressing LAYER button again
Each layer provides independent control over all buttons, encoders, pots, and faders.
- IDs: 1-12
- Each layer sends different MIDI CC values
- IDs: 1-6
- Values: "inc" (clockwise) or "dec" (counter-clockwise)
- Includes push-button functionality (sends button events)
- IDs: 1-4
- Range: 0-127
- Numeric buttons: 1-12 (top 3 rows of button matrix)
- Letter buttons: A-P (bottom 4 rows of button matrix)
- Special buttons:
LAYER- Switches between layersEXIT- Bottom right square buttonENCODER_LEFT- Left encoder push switchENCODER_RIGHT- Right encoder push switch
To use the 3-layer functionality, you must enable Latching Layers on your XONE:K2:
- Enter Setup Mode: Hold down encoder [1] (top-left) while plugging in the USB cable
- Switch matrix LEDs will flash RED 3 times
- Navigate to Latching Layers: Rotate encoder [1] clockwise until switch 'B' (second switch) lights up GREEN
- Press encoder [1] to enter Latching Layers configuration
- Select a mode by rotating the encoder:
- Position 1: OFF (layers disabled)
- Position 2: Switch Matrix only
- Position 3: Pot Switches only
- Position 4: All Switches
- Position 5: All Controls (recommended - includes faders and pots)
- Press encoder [1] to save
- Press EXIT (amber switch) to exit setup mode - LEDs will flash RED 3 times
The LAYER button will now illuminate RED (Layer 1), and you can toggle between RED → AMBER → GREEN layers.
The following improvements were made to the original code:
- Added comprehensive docstrings for all functions
- Type hints for function parameters and return values
- Detailed inline comments
- Try-catch blocks around critical sections
- Graceful error messages and recovery
- Proper cleanup on exit
- Replaced print statements with proper logging
- Configurable log levels (DEBUG, INFO, ERROR)
- Structured log format with timestamps
- Constants in UPPER_CASE (PEP 8 compliance)
- More descriptive variable names
- Better function naming (e.g.,
mutaliate→send_osc) - Removed unused code
- Full 3-layer support with automatic layer detection
- Layer information included in OSC message paths
- Support for all 171 MIDI controls (57 controls × 3 layers)
- Button mapping for all encoder switches and special buttons
--list-portsoption to display available MIDI devices- Proper keyboard interrupt handling (Ctrl+C)
- Resource cleanup function
- Better command-line help text with examples
- Fixed OSC byte encoding for string values
- Added bounds checking for control_id mapping
- Improved button ID validation
- Fixed event loop that was incrementing uselessly
- Better separation of concerns
- More modular function design
- Improved main() entry point
MIDI device not found:
python bridge.py --list-portsUse the exact name shown in the list for the --midi parameter.
OSC messages not received:
- Verify the destination host/port
- Check firewall settings
- Use verbose mode to confirm messages are being sent:
python bridge.py -v
GPL-3.0-or-later
Original: nik gaffney nik@fo.am
Author: chenghsienyu
Modified: 2025-10-22