
Designing a Multi-input MIDI Encoder for Multiple Switch Closures
This post describes the design of a multi-input MIDI encoder intended for switch-heavy control applications like Virtual Pipe Organs or Amateur Radio Station Automation.
Why a Multi-input MIDI Encoder?
Most of the hardware projects I enjoy start the same way: with a physical problem that doesn’t look very complicated until you try to solve it cleanly. In this case, the problem was easy to describe—detect a large number of switch closures and make them visible to a computer—but harder to execute reliably, repeatably, and at scale.
Although this project grew out of a Virtual Pipe Organ build, the underlying design problem will be familiar to many amateur radio operators and station builders: how to connect a panel full of physical controls to modern software in a way that is robust, flexible, and easy to extend.
This post focuses on the technical design of a 48-input USB-connected encoder, how it evolved from a prototype to a manufactured circuit board, and why the resulting architecture generalizes well beyond its original musical application.
⸻
The Problem Space
The hardware requirements were deceptively simple:
- 48 independent SPST switch closures
- Each switch pulls a line to ground when activated
- Both press and release events must be detected
- Output must be delivered over USB
In practice, this raises several immediate constraints:
- Input count exceeds the GPIO capacity of most microcontrollers
- Mechanical switch bounce must be handled cleanly
- Multiple simultaneous activations must be supported
- False triggers or stuck states are unacceptable
- USB reliability matters more than raw speed
While the original application involved organ pedals and stop tabs, these constraints apply just as readily to control panels, macro keypads, antenna switching logic, and other station automation tasks.
⸻
Architecture Overview
At the center of the design is a Teensy 4.0, chosen primarily for its native USB support and generous performance margin. Rather than multiplexing inputs or consuming valuable GPIO pins, I used dedicated I/O expanders to handle switch detection.
The system architecture consists of:
- 3 × MCP23017 I²C GPIO expanders
- 48 digital inputs total
- Single shared I²C bus
- USB connection directly from the Teensy
Each MCP23017 provides 16 GPIO pins with internal pull-up resistors, making them ideal for detecting switches that pull to ground. By assigning each expander a unique I²C address, the system scales cleanly to the required input count with minimal wiring complexity.
⸻
Firmware Design Goals
From the outset, the firmware had several non-negotiable goals:
- Deterministic behavior
- No global delays
- Independent handling of each input
- Clean separation between input sampling and output generation
The main loop follows a consistent pattern:
- Read all MCP23017 GPIO registers once per scan
- Cache the results locally
- Evaluate each input independently
- Apply debounce and lockout logic
- Emit output events only on validated state changes
Reading all GPIO ports in a single pass significantly reduces I²C traffic and avoids subtle timing issues that can arise when inputs are read individually.
⸻
Debounce and Lockout Strategy
Mechanical switches bounce. Reed switches bounce less—but they still bounce.
Rather than relying on delay-based debouncing, the firmware uses a state stability counter. A potential state change must be observed consistently for several consecutive scans before it is accepted. Once accepted, a short per-input lockout window suppresses any residual chatter.
This approach has several advantages:
- Each input debounces independently
- Simultaneous activations are handled cleanly
- No blocking delays slow the scan loop
The result is fast, predictable behavior without false retriggering.
⸻
MIDI Output Strategy
For the production version, the encoder emits MIDI Continuous Controller (CC) messages:
- One CC number per physical input
- Value 127 on activation
- Value 0 on release
This mapping works particularly well with virtual organ software such as Hauptwerk, which can dynamically learn and assign CC inputs.
To avoid any possibility of stuck states, the firmware also sends a MIDI safety (“panic”) sequence on boot, resetting controllers and ensuring the system starts in a known state.
⸻
Beyond MIDI: USB as a Control Interface
Although this encoder currently emits MIDI messages, that choice was driven by the needs of the musical application—not by any limitation of the hardware.
At its core, the firmware is simply detecting validated state changes and emitting structured events. MIDI is one convenient transport, but far from the only option.
With minimal firmware changes, the same architecture could support:
- USB serial output (ASCII or binary protocols)
- Human Interface Device (HID) keypresses
- Hybrid USB devices presenting multiple interfaces simultaneously
For amateur radio operators, this opens up a wide range of possibilities: custom CAT control panels, macro triggers for logging software, band-dependent automation, or Stream Deck–style physical interfaces tailored to a specific operating style.
Seen in that light, this project is best understood as a general-purpose, scalable input front end, with behavior defined almost entirely in software.
⸻
Hardware Evolution: From Prototype to PCB
The earliest versions of this encoder were built on prototyping boards. That approach worked well for validating the firmware and electrical design, but hand-wiring dozens of inputs is neither pleasant nor repeatable.
Once the design stabilized, it made sense to move to a custom printed circuit board.
The production board was designed in KiCad and integrates:
- Three MCP23017 expanders
- Power distribution and decoupling
- I²C pull-ups
- JST-XH connectors for switch inputs
- A Teensy 4.0 socket
The electrical design is straightforward, but care was taken with grounding, decoupling, and I²C signal routing to ensure reliability.
⸻
Manufacturing with PCBWay
PCBWay provided fabrication and partial SMT assembly support for this project, covering most of the production cost for a small run of boards.
As the design moved from prototype to production hardware, I submitted the Gerbers and BOM for review. During that process, their production team flagged a discrepancy between the BOM and the PCB specifications — a detail I had overlooked. That brief exchange was reassuring. The issue was clarified quickly, and it demonstrated that the design files were being reviewed carefully rather than simply processed automatically.
The assembled boards arrived clean, well-labeled, and exactly as designed. The SMT components were precisely placed, solder joints were uniform, and there was no rework required before final assembly. Packaging was secure and professional, and the boards arrived in excellent condition.
Their assistance allowed me to move quickly from schematic to finished boards, freeing up time for integration work inside the console. I’m grateful for their help in bringing this stage of the Virtual Pipe Organ project to life.
Final assembly involved only through-hole components: the Teensy module and the input connectors. For a project of this scale, that division of labor worked extremely well.
⸻
Tooling Notes
Two tools played important roles in this project:
- KiCad, which has matured considerably in recent versions
- ChatGPT, which served as a capable (if occasionally overconfident) design assistant
ChatGPT was particularly useful for architecture discussions, code structure, debugging, and validating assumptions before committing them to hardware. Like any assistant, it works best when its suggestions are verified against reality.
⸻
Code Availability
All firmware for this project is publicly available on GitHub:
👉 https://github.com/jbkerkhoff/Organ_Pedals_Tab_Stops_MIDI
The repository includes source code, hardware notes, and a tagged v1.0 release representing a stable baseline.
This encoder is part of a larger Virtual Pipe Organ project documented at Roy Creek Ranch, where the focus shifts from electronics to restoration, integration, and long-term system design.
The encoder itself stands on its own as a flexible building block for many kinds of control projects.







2 Replies to “Designing a Multi-input MIDI Encoder for Multiple Switch Closures”