Overview
Bass MIDI pedals are a really popular DIY music project. They're used to control synths or other MIDI equipment with your feet while you're playing another instrument. Perfect for getting moody drones going during your solo shoegaze set. The build is housed in a pedal enclosure and uses a Raspberry Pi Pico 2, running CircuitPython, plugged into a Terminal PiCowbell for easy wiring with the foot switches.
Inspiration
This project was inspired by the Basyn MIDI Adapter. This breakout kit is specially designed to let folks connect an organ pedal board to use over MIDI.
Parts from Love My Switches
Love My Switches is an independent guitar pedal part shop. A few of the parts in this build were sourced from them.
Page last edited January 28, 2026
Text editor powered by tinymce.
Circuit Diagram
MPM3610
- MPM3610 GND to DC jack center pin (black wire)
- MPM3610 Vin to DC jack side pin (red wire)
- MPM3610 5V to Pico 2 VSYS (orange wire)
- MPM3610 GND to Pico 2 GND (black wire)
MIDI Jack
- MIDI jack pin 4 to 30 ohm resistor to Pico 2 3.3V (yellow wire)
- MIDI jack center pin to GND (black wire)
- MIDI jack pin 5 to 10 ohm resistor to Pico 2 GP0/TX (cyan wire)
LED
- LED cathode to GND (black wire)
- LED anode to 220 ohm resistor to Pico 2 GP18 (pink wire)
Power Switch
- Switch output to Pico 2 EN (purple wire)
- Switch GND to GND (black wire)
Foot Switches
- Pico 2 GND to all foot switches GND (black wires)
- Switch 1 to Pico 2 GP2 (green wire)
- Switch 2 to Pico 2 GP3 (yellow wire)
- Switch 3 to Pico 2 GP4 (blue wire)
- Switch 4 to Pico 2 GP5 (white wire)
- Switch 5 to Pico 2 GP6 (green wire)
- Switch 6 to Pico 2 GP7 (yellow wire)
- Switch 7 to Pico 2 GP8 (blue wire)
- Switch 8 to Pico 2 GP9 (white wire)
- Switch 9 to Pico 2 GP10 (green wire)
- Switch 10 to Pico 2 GP11 (yellow wire)
- Switch 11 to Pico 2 GP12 (blue wire)
- Switch 12 to Pico 2 GP13 (white wire)
- Switch 13 to Pico 2 GP14 (green wire)
- Switch 14 to Pico 2 GP15 (yellow wire)
To protect against reverse polarity for the DC jack power input, you can place a diode between the DC jack voltage output and Vin on the MPM3610.
Page last edited January 28, 2026
Text editor powered by tinymce.
Installing CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython working on your board.
Click the link above and download the latest UF2 file.
Download and save it to your desktop (or wherever is handy).
Start with your Pico unplugged from USB. Hold down the BOOTSEL button, and while continuing to hold it (don't let go!), plug the Pico into USB. Continue to hold the BOOTSEL button until the RP2350 drive appears!
If the drive does not appear, unplug your Pico and go through the above process again.
A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.
You will see a new disk drive appear called RP2350.
Drag the adafruit_circuitpython_etc.uf2 file to RP2350.
The RP2350 drive will disappear and a new disk drive called CIRCUITPY will appear.
That's it, you're done! :)
Flash Resetting UF2
If your Pico 2 ever gets into a really weird state and doesn't even show up as a disk drive when installing CircuitPython, try installing this 'nuke' UF2 which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After nuking, re-install CircuitPython
Page last edited January 28, 2026
Text editor powered by tinymce.
Code the Stomp Box
Once you've finished setting up your Pico 2 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Bass Synth MIDI Stomp Box"""
import board
import busio
import adafruit_midi
import keypad
from digitalio import DigitalInOut, Direction
# pylint: disable=unused-import
from adafruit_midi.control_change import ControlChange
from adafruit_midi.pitch_bend import PitchBend
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
from adafruit_midi.program_change import ProgramChange
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
# status LED
led = DigitalInOut(board.GP18)
led.direction = Direction.OUTPUT
led.value = True
# UART MIDI
uart = busio.UART(board.GP0, board.GP1, baudrate=31250)
# midi channel setup
midi_out_channel = 1
# midi setup - UART out on GP0
midi = adafruit_midi.MIDI(
midi_out=uart,
out_channel=(midi_out_channel - 1),
)
# foot switches as keypad object
KEY_PINS = (
board.GP2,
board.GP3,
board.GP4,
board.GP5,
board.GP6,
board.GP7,
board.GP8,
board.GP9,
board.GP10,
board.GP11,
board.GP12,
board.GP13,
board.GP14,
board.GP15,
)
notes = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
keys = keypad.Keys(KEY_PINS, value_when_pressed=False)
# variables & states
MIN_NOTE = 24 # lowest starting octave
MAX_NOTE = 84 # highest starting octave
channel_num = midi.out_channel # track channel
pressed_channel = False # did we try to change the MIDI channel
blink_count = 0 # number of times the LED has blinked
clock = ticks_ms() # time keeping
blink_timer = 500 # blink interval (0.5 seconds)
while True:
event = keys.events.get()
if event:
if event.pressed:
if event.key_number == 12:
# change MIDI channel
channel_num = (channel_num + 1) % 16
midi.out_channel = channel_num
print(channel_num + 1)
pressed_channel = True
led.value = False
blink_count = 0
clock = ticks_ms()
elif event.key_number == 13:
# checks if transposing the first note (C) by 1 octave would exceed the MAX_NOTE
# if it does, wraps the array down to start at MIN_NOTE
# otherwise, transposes all notes up by one octave
notes = [MIN_NOTE + (n - notes[0]) if notes[0] + 12 > MAX_NOTE
else n + 12 for n in notes]
else:
# otherwise send noteOn message
midi.send(NoteOn(notes[event.key_number], 120))
if event.released:
if event.key_number < 12:
midi.send(NoteOff(notes[event.key_number], 120))
if pressed_channel:
# blink LED to show what MIDI channel we're on
if ticks_diff(ticks_ms(), clock) > blink_timer:
if not led.value:
led.value = True
blink_count += 1
else:
led.value = False
clock = ticks_add(clock, blink_timer)
# reset after blinking
if blink_count == (channel_num + 1):
pressed_channel = False
blink_count = 0
led.value = True
Upload the Code and Libraries to the Pico 2
After downloading the Project Bundle, plug your Pico 2 into your computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Pico 2's CIRCUITPY drive.
- lib folder
- code.py
Your Pico 2 CIRCUITPY drive should look like this after copying the lib folder and code.py file:
How the CircuitPython Code Works
The code begins by initializing the status LED and UART for MIDI output.
# status LED
led = DigitalInOut(board.GP18)
led.direction = Direction.OUTPUT
led.value = True
# UART MIDI
uart = busio.UART(board.GP0, board.GP1, baudrate=31250)
# midi channel setup
midi_out_channel = 1
# midi setup - UART out on GP0
midi = adafruit_midi.MIDI(
midi_out=uart,
out_channel=(midi_out_channel - 1),
)
Foot Switches
All of the foot switches are passed to a Keypad object. The notes array has all of the MIDI note numbers that are assigned by default to the first 12 switches.
# foot switches as keypad object
KEY_PINS = (
board.GP2,
board.GP3,
board.GP4,
board.GP5,
board.GP6,
board.GP7,
board.GP8,
board.GP9,
board.GP10,
board.GP11,
board.GP12,
board.GP13,
board.GP14,
board.GP15,
)
notes = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
keys = keypad.Keys(KEY_PINS, value_when_pressed=False)
Variables and States
A few variables and states are used in the loop.
-
MIN_NOTEandMAX_NOTEdenote the lowest and highest starting octaves for the foot switches -
channel_numis used to track the current MIDI channel number -
pressed_channelchecks if the foot switch for changing the MIDI channel has been pressed -
blink_counttracks how many times the status LED has blinked -
clockandblink_timerare used for time keeping when blinking the LED
# variables & states MIN_NOTE = 24 # lowest starting octave MAX_NOTE = 84 # highest starting octave channel_num = midi.out_channel # track channel pressed_channel = False # did we try to change the MIDI channel blink_count = 0 # number of times the LED has blinked clock = ticks_ms() # time keeping blink_timer = 500 # blink interval (0.5 seconds)
The Loop
In the loop, keypad events are monitored for the foot switch inputs. If any of the first 12 foot switches are pressed, then a MIDI note on message is sent and a note off message is sent when the switch is released. Foot switch 13 changes the MIDI channel number and foot switch 14 changes the octave of the notes that are being sent by the foot switches.
while True:
event = keys.events.get()
if event:
if event.pressed:
if event.key_number == 12:
# change MIDI channel
channel_num = (channel_num + 1) % 16
midi.out_channel = channel_num
print(channel_num + 1)
pressed_channel = True
led.value = False
blink_count = 0
clock = ticks_ms()
elif event.key_number == 13:
# checks if transposing the first note (C) by 1 octave would exceed the MAX_NOTE
# if it does, wraps the array down to start at MIN_NOTE
# otherwise, transposes all notes up by one octave
notes = [MIN_NOTE + (n - notes[0]) if notes[0] + 12 > MAX_NOTE
else n + 12 for n in notes]
else:
# otherwise send noteOn message
midi.send(NoteOn(notes[event.key_number], 120))
if event.released:
if event.key_number < 12:
midi.send(NoteOff(notes[event.key_number], 120))
If the MIDI channel changes, then the status LED blinks the number of the channel selected. For example, if you are on MIDI channel 5, then the LED will blink 5 times. This blinking is non-blocking thanks to the ticks() library. You can press any of the foot switches while the blinking is happening.
if pressed_channel:
# blink LED to show what MIDI channel we're on
if ticks_diff(ticks_ms(), clock) > blink_timer:
if not led.value:
led.value = True
blink_count += 1
else:
led.value = False
clock = ticks_add(clock, blink_timer)
# reset after blinking
if blink_count == (channel_num + 1):
pressed_channel = False
blink_count = 0
led.value = True
Page last edited January 28, 2026
Text editor powered by tinymce.
3D Printing and Drill Templates
You can 3D print a mount for the PiCowbell that hooks onto the MIDI and DC jacks inside the enclosure. This secures all of the electronics inside of the enclosure.
The mount has mounting holes for the PiCowbell and the MPM3610. The rings slide over the DC and MIDI jacks.
Drill Templates
The drill templates for the enclosure are available as both an .STL file that you can 3D print and an .SVG file that you can print out on paper. The templates align with the edges of the enclosure.
Page last edited January 28, 2026
Text editor powered by tinymce.
Prep the Enclosure
The enclosure is a 1032L Looper Enclosure from Love My Switches. You'll drill out holes in the enclosure for the various switches and ports. You can print out the .DXF or .SVG drill templates, 3D print the .STL drill templates or use both to guide your drill. More information about the templates are available on the 3D Printing page in this guide.
In addition to the templates, you can use a center punch to help make the drilling easier. For the actual drilling, you can use a hand drill or drill press. You'll want to use a small drill bit for the pilot holes and then a step bit or paddle bits for the larger holes.
Line up the top template with the top of the enclosure. It helps to try and line up the rounded corners.
To make sure the template is straight, you can use a straight edge along the center hole line to make sure its the same distance (about 0.75 inches) from the edge all the way across.
Once you're happy with the placement, use clear packing tape to secure it.
If you're using the 3D printed template as well, you can align it with the holes and use blue tape to hold it down on the edge.
Clamp the enclosure to a flat surface. Use your drill to drill a pilot hole in each of the holes. Then, use a step bit to drill out each hole to the correct size. All of the foot switch holes are 12 mm in diameter. The LED mounting hole is 6.5 mm in diameter.
Take the side drill template and line it up with the back edge of the enclosure. Use clear packing tape to secure it to the enclosure.
Place the 3D printed template on top of the paper one, lining it up with the drill holes. Use painters tape to secure it to the enclosure.
Use a small drill bit to drill the pilot holes. Then use a step drill bit or paddle bit to fully drill the holes. Here are the diameters:
- DC Jack: 12.5 mm
- MIDI Jack: 16 mm
- MIDI Jack screws: 3.2 mm
- USB Panel Mount: 20.8 mm
Page last edited January 28, 2026
Text editor powered by tinymce.
Soldering - Components
Solder a wire to each of the resistors. Solder a third wire to pin 2 (center pin) on the MIDI DIN-5 connector. The wires should be about 4 inches long.
Solder a wire from the center pin on the DC jack to the GND pin on the MPM3610. The power circuit is wired for a center negative power supply which are used by guitar pedals!
Power Switch
The latching switch used is this DPDT latching switch from Love My Switches.
Solder a wire to pin 2 on the L side of the switch. Solder a wire to pin 3 on the L side of the switch. These wires should be about 4 inches long.
The LED mount has two parts: the main housing that the LED sits in and a small piece that has holes for each of the LED legs. This piece is inserted from the bottom of the housing to secure the LED in place.
Insert the LED legs into the holding piece for the mount and secure the LED by pushing the piece into the housing.
Page last edited January 28, 2026
Text editor powered by tinymce.
Soldering - Foot Switches
Insert and secure the first foot switch into the enclosure. You can use a 14 mm socket to tighten the nut.
All of the foot switches are going to share a ground connection. Run a short wire between the first two switches and solder the wire in place.
Continue this ground wire daisy chaining between all of the foot switches. At the fourteenth switch, run a longer ground wire that is about 4 inches in length. This wire will connect to the Pico 2 GND connection.
Each remaining solder lug on each foot switch will have a wire connected to a GPIO pin on the Pico 2. Start with the last switch with a wire that is about 3 inches long.
The wires that will be closer to the Pico 2 can be about 3 inches long and will gradually get longer the further away from the Pico 2. These should be about the length of the enclosure.
Page last edited January 28, 2026
Text editor powered by tinymce.
Terminal PiCowbell Wiring
This page goes over how all of the components screw into the terminal blocks on the PiCowbell. Some of the wiring can get a little tight as you get close to the end so take your time and pay attention to where your connections are going. Don't forget to reference the circuit diagram too!
Each foot switch will have its output connect with a GPIO on the Pico 2. You'll start with switches 13 and 14, which are the MIDI Channel and Octave switches.
- Switch 13 to GP14 (green wire)
- Switch 14 to GP15 (yellow wire)
Foot switches 9-12:
- Switch 9 to GP10 (green wire)
- Switch 10 to GP11 (yellow wire)
- Switch 11 to GP12 (blue wire)
- Switch 12 to GP13 (white wire)
Foot switches 5-8:
- Switch 5 to GP6 (green wire)
- Switch 6 to GP7 (yellow wire)
- Switch 7 to GP8 (blue wire)
- Switch 8 to GP9 (white wire)
Foot switches 1-4:
- Switch 1 to GP2 (green wire)
- Switch 2 to GP3 (yellow wire)
- Switch 3 to GP4 (blue wire)
- Switch 4 to GP5 (white wire)
That completes the foot switch wiring!
Components
Next, you'll connect the components: the status LED, power switch, MIDI jack and DC jack.
Connect the power switch to the Pico 2:
- Switch L2 to ENable (white wire)
- Switch L3 to GND (black wire)
Run the MPM3610 and the wires connected to the DC jack through the DC jack hole on the enclosure. Then, run the assembly through the DC jack nut and the smaller ring.
Connect the following wires from the MPM3610 to the Pico 2:
- MPM3610 5V to VSYS (yellow wire)
- MPM3610 GND to GND (black wire)
Insert the MIDI jack wires through the MIDI jack mounting hole. Run its wires through the ring on the 3D printed mount.
Connect the following wires to the Pico 2:
- MIDI jack pin 4 (current source) to 3.3V (red wire)
- MIDI jack pin 2/center pin to GND (black wire)
Page last edited January 28, 2026
Text editor powered by tinymce.
Assembly
Slide the rings on the 3D printed mount over the DC jack and MIDI jack. Secure the ring over the DC jack with the DC jack nut.
That finishes up all of the wiring!
Page last edited January 28, 2026
Text editor powered by tinymce.
Use
There are two ways that you can power the stomp box:
- USB micro B
- 9V center negative guitar pedal power supply
After you choose your power method, plug in the box and then turn it on by pressing the power switch. You'll see the status LED turn on.
After powering up, plug in the MIDI jack to your favorite MIDI synth. The 12 foot switches give you an octave of notes to send. The two side buttons let you control the MIDI channel (first button) or the octave (second button).
Going Further
Since this build is housed in a pedal enclosure, its super customizable to your needs for the pedal. You could also change the code to use USB MIDI instead of MIDI over UART. If you aren't looking to have MIDI accompany or harmonize with you, you could also change the code to output Control Change or other utility messages.
Page last edited January 28, 2026
Text editor powered by tinymce.