Turn your Akai MPK Mini into a macOS system controller. Map drum pads, knobs, joystick, and piano keys to keyboard shortcuts, app switching, volume control, media playback, and more.
Built for the MPK Mini 3, but works with any MIDI controller that sends standard note/CC/pitchwheel messages.
| Input | Action |
|---|---|
| Drum Pad 1 | Previous tab (Cmd+Shift+[) |
| Drum Pad 2 | Next tab (Cmd+Shift+]) |
| Drum Pad 3 | Cmd+Tab app switcher (hold + joystick to navigate) |
| Drum Pad 4 | Wispr Flow voice control (hold=record, double-tap=hands-free) |
| Drum Pad 5 | Play/pause music |
| Drum Pad 6 | Open Spotify (configurable to any app) |
| Drum Pad 7 | Delete key (repeats while held) |
| Drum Pad 8 | Return/Enter |
| Knob 2 | Next/previous track |
| Knob 3 | System volume (0-100%) |
| Joystick | Arrow keys (fires at extremes, repeats while held) |
| Piano keys | Jump to tabs 1-9 (Cmd+1 through Cmd+9) |
Everything is configurable via config.json.
- macOS (uses Quartz for key simulation)
- Python 3.10+
- An Akai MPK Mini (or any MIDI controller)
git clone https://github.com/tejassudsfp/midicode.git
cd midicode
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtSystem Settings → Privacy & Security → Accessibility → add your terminal app (Terminal, iTerm2, etc.)
This is required for simulating key presses.
# Direct
source .venv/bin/activate
python3 midi_controller.py
# Or use the launcher
./start.sh
# Menu bar app (shows in top bar, click to start/stop)
./start-menubar.shpython3 midi_controller.py --list # List available MIDI devices
python3 midi_controller.py --scan # See raw MIDI input from your controllerThis project is designed to be configured using Claude Code. Just tell Claude what you want each button to do:
"Map pad 5 to open Safari and pad 6 to mute/unmute"
Claude will read the CLAUDE.md file in this repo and understand the full architecture, then modify config.json and midi_controller.py for you.
- MIDI input via
mido+python-rtmidi - Key simulation via
pyobjc-framework-Quartz(CGEvents) - Media keys via NSEvent system-defined events
- Menu bar via
rumps
All key presses use kCGEventSourceStatePrivate to prevent modifier leaking (e.g., Cmd not bleeding into arrow keys). Wispr Flow uses kCGEventSourceStateCombinedSessionState specifically because it needs to see system-level modifier state.
# Create a LaunchAgent
cat > ~/Library/LaunchAgents/com.midicode.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.midicode</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/midicode/start-menubar.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOF
# Load it
launchctl load ~/Library/LaunchAgents/com.midicode.plistReplace /path/to/midicode/ with your actual path.
- Claude Code — AI pair programmer that wrote and configured this entire project
- Wispr Flow — voice-to-text dictation (Pad 4 triggers push-to-talk and hands-free modes)
- Akai MPK Mini — the MIDI keyboard this was designed for
This project was built entirely through voice (Wispr Flow) and AI (Claude Code) — no manual typing.
MIT License — see LICENSE.
Created by Tejas Sudarshan — tejas@fandesk.ai