Skip to main content
Version: ACS CC

MIDI Controller

DIY USB MIDI Controller

info

Author: Gheorghita Vlad-Gabriel
GitHub Project Link: link

Description

A custom USB MIDI controller built using a Raspberry Pi Pico 2W and tactile switches to detect and transmit MIDI signals (Note On/Off + Velocity) to a DAW using the USB MIDI protocol.

Motivation

As someone passionate about composing music and making beats, I've always been curious about how physical MIDI instruments work under the hood. Instead of buying an off-the-shelf MIDI controller, I decided to build one myself to combine my love for music with my skills in electronics and programming. This project allows me to deepen my understanding of how musical interfaces communicate with digital audio workstations and explore creative, cost-effective solutions for real-world problems.

Architecture

Block Diagram

Log

Week 5 - 11 May

  • Studied all the components to make them work
  • Done draft documentation
  • First order of hardware
  • Done key logic and hardware prototype on breadboard
  • Made measurements for 3D printed case, caps and keys

Week 12 - 18 May

  • Finished hardware:
    • Soldered wires and components on Final PCB
    • Connected components on pre-planned pins (check schematic)
    • Done final schematic
    • 3D printed main case
  • Start implementing software:
    • Done logic for multiplexing of keys
    • Done logic for filter knob (potentiometer)
    • Done logic for display
    • Done MIDI communication between device and controller

Week 19 - 25 May

  • Finished software:
    • Tweaked different values (voltage levels for key press, velocity computing etc.)
    • Refined logic for each component
    • Organized code
  • Finished final product:
    • 3D printed missing parts (keys, button caps and cover)
    • Glued everything together

Hardware

The DIY MIDI controller is built around the Raspberry Pi Pico 2W, with custom-designed circuitry implemented on homemade PCB boards. All components are connected using solid-core wires stripped from a UTP (Ethernet) cable, ensuring reliable point-to-point wiring across the board.

Circuit

The controller features 12 keys, each equipped with two tactile switches mounted at different elevations. This physical arrangement enables velocity sensitivity by measuring the time interval between the activation of the first and second switches. In total, 24 switches are scanned.

To efficiently read these switches using minimal GPIOs, a 16-channel analog multiplexer is used (12 channels active). Each switch is wired into a voltage divider, producing distinct analog voltage levels depending on press state:

  • more than 2650: no press (send Note OFF)
  • between 2000–2500: one pressed (start timer)
  • less than 1000: both pressed (stop timer, compute velocity, send Note ON)

The multiplexer’s selector lines are controlled via four GPIOs, while the SIG pin is connected to an ADC input on the Pico. Each key is scanned sequentially in a loop, with debouncing and averaging applied.

A potentiometer is connected directly to another ADC pin, providing continuous control input which is mapped to a MIDI filter parameter (e.g., cutoff frequency). Its value is read periodically and translated into MIDI Control Change (CC) messages.

For user interaction, the controller includes:

  • An SSD1306 OLED display, driven via I2C, used to render a menu interface for settings such as octave selection and filter CC channel.
  • Four momentary buttons connected to GPIOs:
    • Menu: enter/exit menu mode
    • Select: short/long presses toggle modes or confirm selections
    • Up/Down: navigate between options

The menu uses a carousel-style interface, offering intuitive cycling through options with feedback on the screen.

Schematics

Schematic

Software

The firmware for the MIDI controller is written in Rust, using the embassy async runtime for embedded systems. It targets the Raspberry Pi Pico 2W (RP2040) microcontroller and uses the following major components:

  1. Note Detection with Velocity
    Reads from the buttons under each key via analog multiplexer. Measures time between two switch presses for each key to estimate velocity and sends MIDI note-on events accordingly.
  2. Filter Control via Potentiometer
    Continuously samples the potentiometer and sends MIDI CC messages on a user-configurable channel (70–79) if the value has changed significantly.
  3. User Menu System via Button Interface & OLED Display
    Uses four buttons (Menu, Select, Up, Down) and an I2C SSD1306 OLED screen to:
    • Select between Octave and Filter modes.
    • Modify current octave (C0–C9).
    • Modify the active MIDI filter channel.
  4. USB MIDI Output
    Implements a class-compliant USB MIDI device that sends:
    • Note on/off messages.
    • Control Change messages for the filter.
LibraryDescriptionUsage
embassy-rpRust + async embeddedFramework for embedded applications using async features on the Raspberry Pi Pico 2W
ssd1306Driver for SSD1306 displayDisplay menu for filter and octave selection
embedded-graphics2D graphics libraryDrawing primitives and text rendering for embedded displays
static-cellAllows defining static, lazily initialized values safelyStore USB Config information
embassy-usbUSB device stack for async embedded RustConfigure USB connection to device
defmtLogging framework for embedded development (formatted debug output)Debugging Software and Hardware

Bill of Materials

DeviceUsagePrice
Raspberry Pi Pico 2WMain and debug microcontroller79.32 RON
Breadboard Kit HQ 830pPrototyping and testing22.00 RON
6 x 6 x 6 Push ButtonDual-switch per key for velocity detection10.80 RON
CD74HC4067 16 Channel Analog MultiplexerMultiplexing of keys5.77 RON
100k Mono PotentiometerOptional control knob for filter adjustments1.49 RON
Universal PCB Prototype Board 8x12cmSoldering base for final PCB7.98 RON
Universal PCB Prototype Board 6x8cmSoldering base for final PCB4.98 RON
Colored 40p 2.54 mm Pitch Male Pin HeaderWiring headers for connections2.97 RON
20p Female Pin Header 2.54 mmWiring headers for connections12.27 RON
4p Female Pin Header 2.54 mmWiring headers for connections0.98 RON
SSD1306 0.96" OLED DISPLAYFor showing filter and octave menu27.37
3D Printer materialsCase and keys50 RON
Total-225.93 RON
  1. USB MIDI Specification
  2. embassy-rp: Rust + async for embedded
  3. ssd1306
  4. ADC lab
  5. Async lab
  6. I2C lab
  7. embassy-usb
  8. MIDI Protocol Reference
  9. RP2040 Datasheet
  10. Example project 1
  11. Example project 2