Created
January 21, 2021 22:27
-
-
Save sandyjmacdonald/804dc737e7cb798d1b4fa34adc87e2d4 to your computer and use it in GitHub Desktop.
RGB MIDI controller example for Pimoroni RGB Keypad for Raspberry Pi Pico
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
import board | |
import busio | |
import usb_midi | |
import adafruit_midi | |
from adafruit_midi.note_off import NoteOff | |
from adafruit_midi.note_on import NoteOn | |
from adafruit_bus_device.i2c_device import I2CDevice | |
import adafruit_dotstar | |
from digitalio import DigitalInOut, Direction, Pull | |
# RGB MIDI controller example for Pimoroni RGB Keypad for Raspberry Pi Pico | |
# Prerequisites | |
# | |
# Requires Adafruit CircuitPython: https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython | |
# | |
# Also requires the following CircuitPython libs: adafruit_midi, adafruit_bus_device, adafruit_dotstar | |
# (drop them into the lib folder) | |
# | |
# Save this code in code.py on your Raspberry Pi Pico CIRCUITPY drive | |
# Pull CS pin low to enable level shifter | |
cs = DigitalInOut(board.GP17) | |
cs.direction = Direction.OUTPUT | |
cs.value = 0 | |
# Set up APA102 pixels | |
num_pixels = 16 | |
pixels = adafruit_dotstar.DotStar(board.GP18, board.GP19, num_pixels, brightness=0.1, auto_write=True) | |
# Set up I2C for IO expander (addr: 0x20) | |
i2c = busio.I2C(board.GP5, board.GP4) | |
device = I2CDevice(i2c, 0x20) | |
# Set USB MIDI up on channel 0 | |
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) | |
# Function to map 0-255 to position on colour wheel | |
def colourwheel(pos): | |
if pos < 0 or pos > 255: | |
return (0, 0, 0) | |
if pos < 85: | |
return (255 - pos * 3, pos * 3, 0) | |
if pos < 170: | |
pos -= 85 | |
return (0, 255 - pos * 3, pos * 3) | |
pos -= 170 | |
return (pos * 3, 0, 255 - pos * 3) | |
# List to store the button states | |
held = [0] * 16 | |
# Keep reading button states, setting pixels, sending notes | |
while True: | |
with device: | |
# Read from IO expander, 2 bytes (8 bits) correspond to the 16 buttons | |
device.write(bytes([0x0])) | |
result = bytearray(2) | |
device.readinto(result) | |
b = result[0] | result[1] << 8 | |
# Loop through the buttons | |
for i in range(16): | |
if not (1 << i) & b: # Pressed state | |
pixels[i] = colourwheel(i * 16) # Map pixel index to 0-255 range | |
if not held[i]: | |
midi.send(NoteOn(36 + i, 100)) # If not already held, then send note | |
held[i] = 1 | |
else: # Released state | |
pixels[i] = (0, 0, 0) # Turn pixel off | |
midi.send(NoteOff(32 + i, 0)) # If not held, send note off | |
held[i] = 0 # Set held state to off |
Would anyone here have any info on how to add a few buttons and a slide pot to this code? I made a small macropad (have not wired it yet) and I would like to add it in addition to the pico Rob keypad. Any help would be super appreciated!!
I have just started playing with circuitpython midi libs and I have a similar setup: two buttons instead of 9, and a rotary encoder instead of a slide pot. But maybe you could adapt it.
import time
import board
import digitalio
import rotaryio
import usb_midi
import adafruit_midi
from adafruit_midi.control_change import ControlChange
midi_usb_c0 = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)
midi_usb_c1 = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=1)
cc_number = 0
button = digitalio.DigitalInOut(board.GP1)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
button_last = None
btns = [digitalio.DigitalInOut(board.GP4), digitalio.DigitalInOut(board.GP5)]
btns_last = [None, None]
btns_cc_values = [0, 0]
for b in btns:
b.direction = digitalio.Direction.INPUT
b.pull = digitalio.Pull.UP
encoder = rotaryio.IncrementalEncoder(board.GP2, board.GP3)
enc_last = None
enc_min = 0
enc_max = 127
encoder.position = 64
while True:
enc = encoder.position
btns_changed = any([bl != b.value for bl, b in zip(btns_last, btns)])
if (enc_last != enc) or (button_last != button.value) or btns_changed:
if enc > enc_max:
enc = enc_max
elif enc < enc_min:
enc = enc_min
encoder.position = enc
# set current encoder value as button cc
if (button_last != button.value) and (button.value is False):
btns_cc_values[0] = enc
# send discreete midi cc from button
if btns_changed:
midi_usb_c1.send(ControlChange(cc_number, btns_cc_values[0]))
print("Button seinding midi cc", btns_cc_values[0])
if (enc_last != enc):
midi_usb_c0.send(ControlChange(cc_number, enc))
print(
"Button values", button.value,
[btns[i].value for i in range(len(btns))],
"Rotary encoder", enc)
enc_last = enc
button_last = button.value
for i in range(len(btns)):
btns_last[i] = btns[i].value
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @kenimaister thank you for your comment, it fixed my problem of the mirrored (inverted?) keys! Now I can enjoy using the keypad with Ableton without having to do some additional mental gymnastics! And also thank you again to @sandyjmacdonald for the code! It has gotten me into playing around with making some fun tracks and I have also gotten addtional MIDI equipment to do more fun stuff! You're all wonderful!