A stateful python interface for USB MIDI controllers.
Project description
A general, stateful python interface for MIDI controllers that abstracts hardware differences behind a simple API.
Overview
Padbound provides a high-level abstraction over MIDI controllers, allowing applications to work with three fundamental control types (toggles, momentary triggers, continuous controls) and RGB colors without dealing with raw MIDI messages.
Features
- Three Control Types: Toggle, Momentary, and Continuous controls with unified API
- Progressive State Discovery: Honest representation of hardware limitations (knobs/faders start in "unknown" state)
- Capability-Based API: Validates hardware support before attempting operations
- Thread-Safe: Safe concurrent access from callbacks and main thread
- Plugin Architecture: Extensible system for supporting different controllers
- Callback System: Global, per-control, and type-based callbacks with error isolation
- Bank Support: Handles controllers with bank switching (when supported)
- Strict/Permissive Modes: Choose between errors or warnings for unsupported operations
Installation
pip install -e .
Quick Start
from padbound import Controller, ControlType
# Auto-detect and connect to controller
with Controller(plugin='auto', auto_connect=True) as controller:
# Register callback for a specific pad
controller.on_control('pad_1', lambda state: print(f"Pad 1: {state.is_on}"))
# Register callback for all continuous controls (knobs/faders)
def on_continuous(control_id, state):
if state.is_discovered:
print(f"{control_id}: {state.normalized_value:.2f}")
controller.on_type(ControlType.CONTINUOUS, on_continuous)
# Main loop
while True:
controller.process_events()
Examples
See the examples/ directory for controller-specific demos:
demo_akai_lpd8.py- AKAI LPD8 MK2demo_akai_apc_mini_mk2.py- AKAI APC mini MK2demo_presonus_atom.py- PreSonus ATOMdemo_xjam.py- Xjamdemo_x_touch_mini.py- Behringer X-Touch Mini
Callback Registration
from padbound import Controller, ControlType
with Controller(plugin='auto', auto_connect=True) as controller:
# Per-control callback
controller.on_control('pad_1', lambda state: print(f"Pad 1: {state.is_on}"))
# Per-type callback (all toggles, all continuous, etc.)
controller.on_type(ControlType.TOGGLE, lambda cid, state: print(f"{cid} toggled"))
# Per-category callback (e.g., all transport buttons)
controller.on_category('transport', lambda cid, state: print(f"Transport: {cid}"))
# Global callback (all controls)
controller.on_global(lambda cid, state: print(f"Any control: {cid}"))
while True:
controller.process_events()
Setting Control State
from padbound import Controller
with Controller(plugin='auto', auto_connect=True) as controller:
# Set pad LED color and state
if controller.can_set_state('pad_1', is_on=True, color='red'):
controller.set_state('pad_1', is_on=True, color='red')
# Query control state
state = controller.get_state('pad_1')
if state:
print(f"Pad 1 is {'on' if state.is_on else 'off'}")
Using Configuration
from padbound import Controller, ControllerConfig, BankConfig, ControlConfig, ControlType
# Configure pad colors and types
config = ControllerConfig(banks={
'bank_1': BankConfig(controls={
'pad_1': ControlConfig(type=ControlType.TOGGLE, color='red', off_color='dim_red'),
'pad_2': ControlConfig(type=ControlType.MOMENTARY, color='green'),
})
})
with Controller(plugin='auto', config=config, auto_connect=True) as controller:
while True:
controller.process_events()
Supported Controllers
Capability Comparison
| Controller | Pads | Knobs/Encoders | Faders | Buttons | RGB LEDs | LED Modes | Banks | Persistent Config | Special Features |
|---|---|---|---|---|---|---|---|---|---|
| AKAI LPD8 MK2 | 8 | 8 knobs | — | — | ✓ Full | Solid | 4 (HW) | ✓ SysEx | Multi-signal pads (NOTE/CC/PC) |
| AKAI APC mini MK2 | 64 | — | 9 | 17 | ✓ Full | Solid/Pulse/Blink | 1 | — | Fader position discovery |
| PreSonus ATOM | 16 | 4 | — | 20 | ✓ Full | Solid/Pulse/Blink | 8 (HW) | — | Native Control mode, encoder acceleration |
| Xjam | 16 | 6 | — | — | — | — | 3 (HW) | ✓ SysEx | Multi-signal pads, multiple encoder modes |
| X-Touch Mini | 16 | 8 + buttons | 1 | — | Single | Solid | 2 (HW) | — | Deferred LED feedback, auto-reflecting encoder rings |
Legend:
- HW = Hardware-managed bank switching
- RGB LEDs: Full = True RGB color support, Single = On/off only
- LED Modes: Animation/behavior modes supported
- Persistent Config: Device stores configuration in non-volatile memory
Detailed Controller Information
AKAI LPD8 MK2
Control Surface: 8 RGB pads + 8 knobs
Banks: 4 banks with hardware-based switching
Capabilities:
- Pad LED Feedback: Full RGB via SysEx
- Pad LED Modes: Solid
- Pad Modes: Toggle or momentary (global per bank)
- Knob Feedback: None (read-only)
- Configuration: Persistent (SysEx)
AKAI APC mini MK2
Control Surface: 8×8 RGB pad grid + 9 faders + 17 buttons
Banks: Single layer
Capabilities:
- Pad LED Feedback: Full RGB via SysEx
- Pad LED Modes: Solid, pulse, blink
- Pad Modes: Toggle or momentary (per pad)
- Fader Feedback: None (read-only, initial position discovered)
- Button LED Feedback: Single-color (red for track, green for scene)
- Configuration: Volatile
PreSonus ATOM
Control Surface: 16 RGB pads (4×4) + 4 encoders + 20 buttons
Banks: 8 hardware-managed banks (not software-accessible)
Capabilities:
- Pad LED Feedback: Full RGB via Native Control mode
- Pad LED Modes: Solid, pulse, breathe
- Pad Modes: Toggle or momentary (per pad)
- Encoder Type: Relative with acceleration
- Encoder Feedback: None (read-only)
- Button LED Feedback: Single-color
- Configuration: Volatile
Xjam (ESI/Artesia Pro)
Control Surface: 16 pads + 6 knobs per bank
Banks: 3 banks (Green, Yellow, Red) with synchronized pad/knob switching
Capabilities:
- Pad LED Feedback: None (hardware-managed)
- Pad Modes: Toggle or momentary (global)
- Knob Type: Configurable (absolute or 3 relative modes)
- Knob Feedback: None (read-only)
- Configuration: Persistent (SysEx)
Behringer X-Touch Mini
Control Surface: 8 encoders with buttons + 16 pads + 1 fader
Banks: 2 layers (A, B) with hardware switching
Capabilities:
- Pad LED Feedback: Single-color
- Pad LED Modes: Solid
- Pad Modes: Toggle or momentary (per pad)
- Encoder Type: Absolute
- Encoder Feedback: LED ring auto-reflects value
- Encoder Button Feedback: Single-color
- Fader Feedback: None (read-only)
- Configuration: Volatile
Documentation
TBD
Acknowledgements
Some protocol information for supported controllers was gathered from:
- AKAI LPD8 MK2: stephensrmmartin/lpd8mk2
- PreSonus ATOM: EMATech/AtomCtrl
- Behringer X-Touch Mini: AndreasPantle/X-Touch-Mini-HandsOn
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file padbound-0.1.0.tar.gz.
File metadata
- Download URL: padbound-0.1.0.tar.gz
- Upload date:
- Size: 223.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cf016c5927fb87d892cbab9f26f46c9dbf6c18d74a19a84247403a592638e37
|
|
| MD5 |
67aef623e2618a748f44c95fbf5dc7f3
|
|
| BLAKE2b-256 |
ac7c8cff9530a53a7b060dc720302d35faadc6edc0a201b9175a5c4f25d7043a
|
File details
Details for the file padbound-0.1.0-py3-none-any.whl.
File metadata
- Download URL: padbound-0.1.0-py3-none-any.whl
- Upload date:
- Size: 89.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdbac61d1a4ec005b34c1e7470a5e46d4a810972a1f999089a0bc9aa4d070424
|
|
| MD5 |
6ea95084f44c6e49be7267fd60ca156a
|
|
| BLAKE2b-256 |
8832dda09a963b378bc11a84ad89fd32a863f11c41857fc0dacbdc82c14f50ea
|