A custom USB MIDI controller built with a Raspberry Pi Pico W and CircuitPython, featuring per-application volume control on Linux via MIDIVol.
Hardware:
- 3 slide potentiometers for volume control
- 11 programmable buttons (media keys, mute toggles, keyboard shortcuts)
- 2 rotary encoders (system volume, navigation)
- 9 NeoPixel LEDs (3 for pots, 6 for buttons) with visual feedback
- SSD1306 OLED display (128x64) showing real-time control values
- Boot splash animation
Software (MIDIVol - Linux):
- Per-application volume control via PipeWire/PulseAudio
- Assign multiple apps to each potentiometer
- Mute toggle per channel with LED feedback on the controller
- MIDI Learn mode: press a physical button to assign it as mute toggle
- System master volume displayed on the controller's OLED
- System tray integration (runs in background)
- Persistent configuration (auto-saved, restored on startup)
| Component | Specification |
|---|---|
| MCU | Raspberry Pi Pico W |
| ADC | ADS1015 (I2C, 12-bit) |
| Display | SSD1306 OLED 128x64 (I2C) |
| LEDs | 9x NeoPixel (WS2812B) |
| Potentiometers | 3x linear slide |
| Encoders | 2x rotary with push button |
| Buttons | 11x momentary push |
| Component | GPIO |
|---|---|
| I2C (ADS1015 + SSD1306) | SCL=GP1, SDA=GP0 |
| Pot LEDs (3x NeoPixel) | GP6 |
| Button LEDs (6x NeoPixel) | GP5 |
| Encoder 1 (Volume) | GP17, GP18 |
| Encoder 2 (Navigation) | GP20, GP21 |
| Buttons | GP7, GP8, GP9, GP10, GP11, GP16, GP19, GP22, GP26, GP27, GP28 |
| Message | Data | Description |
|---|---|---|
| CC 58 | 0-127 | Potentiometer 0 value |
| CC 59 | 0-127 | Potentiometer 1 value |
| CC 60 | 0-127 | Potentiometer 2 value |
| NoteOn N | velocity 100 | Button press (N = button key number) |
All messages sent on MIDI Channel 0.
| Message | Value | Effect |
|---|---|---|
| CC 0 | 1/0 | Pot 2 LED on (red) / off |
| CC 1 | 1/0 | Pot 1 LED on (red) / off |
| CC 2 | 1/0 | Pot 0 LED on (red) / off |
| CC 7 | 1/0 | Global mute: all LEDs red / all off |
| CC 8 | 0-127 | Display master volume (0-100%) on OLED |
| Button | Action |
|---|---|
| Button 3 | Consumer Control: Mute |
| Button 5 | Consumer Control: Play/Pause |
| Button 7 | Consumer Control: Next Track |
| Button 10 | Consumer Control: Previous Track |
| Button 8 | Keyboard: F13 |
| Button 6 | Keyboard: F14 |
| Button 9 | Keyboard: F15 |
| Encoder 1 | Consumer Control: Volume Up/Down |
The firmware runs CircuitPython 9.2.7 on the Raspberry Pi Pico W.
- Flash CircuitPython 9.2.7 on the Pico W (download)
- Copy all files from
firmware/to the CIRCUITPY drive - Install required Adafruit libraries to
lib/on the CIRCUITPY drive:adafruit_ads1x15adafruit_midiadafruit_hidadafruit_displayio_ssd1306adafruit_display_textadafruit_display_shapesadafruit_bitmap_fontadafruit_imageloadadafruit_simplemathneopixelasyncio
GPIO22 acts as a safety button during boot:
- Pressed: USB drive + serial console enabled (for development)
- Released: Both disabled (prevents accidental file edits)
One-liner install:
curl -fsSL https://raw.githubusercontent.com/lucasjbx/midi_controller/main/install.sh | bashThen run midivol or search for "MIDIVol" in your app menu.
See linux_app/README.md for full documentation and alternative install methods.
On Windows, this controller works with MIDI Mixer.
MIT