This project uses a Pimoroni RGB Keypad with a Raspberry Pi Pico to create 16 “mute” switches for MIDI, one for each MIDI channel.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
These are the key tutorials for the main concepts used in this project:
- MIDI, MicroPython and the Raspberry Pi Pico
- MIDI In for 3.3V Microcontrollers
- Pimoroni Pico Keypad Base “Getting Started” and Demo Micropython code
- Raspberry Pi Pico MIDI Proto Expander (optional)
If you are new to microcontrollers, see the Getting Started pages.
Parts list
- Raspberry Pi Pico
- Pimoroni RGB Keypad Expander
- MIDI IN and OUT interfaces suitable for 3V3 operation (e.g. DIY MIDI Interfaces or Ready-Made MIDI Modules)
- Means of connecting them all together, e.g. jumper wires, a Pimoroni Dual Expander, or in my case I’ve used my Raspberry Pi Pico MIDI Proto Expander.
The Circuit
I’m using the keypad and “expander” back-to-back, similar to how I’ve used them in the past.
If you are using an independent MIDI interface then it will need connecting to 3V3_OUT and GND for power and GP0 (RX) for MIDI IN and GP1 (TX) for MIDI OUT.
Naturally your source of MIDI data should be connected to MIDI IN and the sounding device to MIDI OUT.
The Code
There are two main threads of operation within the code:
- MIDI receiving, decoding, and re-transmitting.
- Keypad checking and LED updating.
The MIDI side uses my SimpleMIDIDecoder and passes any received MIDI messages into the decoder for handling by some callback functions. Each callback calls a new midiChannelRouter function that determines if the message is for passing on or not.
def midiChannelMuter (ch, cmd, d1, d2): if (not MIDICH[ch-1]): return if (d2 == -1): uart.write(ustruct.pack("bb",cmd+ch-1,d1)) else: uart.write(ustruct.pack("bbb",cmd+ch-1,d1,d2))
The MIDICH array has one element per MIDI channel which will be True if the channel is to be passed through or False if it is to be muted. This is using direct byte-writes to the hardware UART and knows if the message will be two or three bytes long (the decoder returns “-1” for the second byte if not used).
One thing to be careful of. If a MIDI channel is muted between a NoteOn and NoteOff message (which is probably quite likely!) then the notes will hang. To cope with this I send an “All Notes Off” message on that channel when the corresponding mute button is pressed.
Also it should be noted that whilst the decoder is quite happy receiving MIDI Running Status, it passes messages on as single messages. This means it will eventually have a performance hit if there is a lot of MIDI traffic.
The keypad handling basically comes from the Pimoroni demo code and does the following:
while True: Check the keypad states IF a button is pressed THEN Toggle the MIDICH state for that button IF channel now muted THEN Send AllNotesOff on that MIDI channel* FOREACH channel IF MIDICH is True THEN Turn on the corresponding key RGB ELSE Turn off the corresponding key RGB
Closing Thoughts
My short demo video (above) starts with just channel 1 sounding, then I gradually turn on more channels. It then finishes by showing what happens if you don’t send the AllNotesOff. My receiving Arduinos don’t listen for that message, so the notes just hang there.
As already mentioned there may be a performance hit from expanding out any Running Status messages as part of the routing process, but apart from that, it seems to work quite well!
Kevin
You could implement the filtering using PIO and DMA, this should allow to overcome any performance issues.
LikeLike
Hy Kevin how can work with 4×4 keypad schematic and code with code arduino or Raspberry Pico please
LikeLike