Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jedgarpark/1a881457f0885963bd0c3e83f9e52593 to your computer and use it in GitHub Desktop.
Save jedgarpark/1a881457f0885963bd0c3e83f9e52593 to your computer and use it in GitHub Desktop.
# SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2024 Tod Kurt
# SPDX-FileCopyrightText: Copyright (c) 2024 John Park
# SPDX-License-Identifier: Unlicense
#
# Forward MIDI from device on USB Host port to computer via USB MIDI
# and 5-pin serial MIDI via MIDI Feather Wing or similar MIDI output.
# Suppots hot-plug of the device on the USB Host port.
#
# adapted from https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_MIDI/blob/main/examples/usb_host_midi_simpletest.py
# needs "circup install adafruit_midi adafruit_usb_host_descriptors"
# and hand-copy library from https://github.com/todbot/Adafruit_CircuitPython_USB_Host_MIDI
# USB MIDI on ESP32-S2 needs boot.py enablement
# https://github.com/todbot/circuitpython-tricks?tab=readme-ov-file#enable-usb-midi-in-bootpy-for-esp32-s2-and-stm32f4
# to do:
# -use tft buttons to remap cc numbers
# -buttons to transpose key?
# -buttons to change MIDI channel output
# -button D0 for MIDI panic message
# -
import time
# import asyncio
import board
import busio
import usb
import usb_midi
import max3421e
import adafruit_usb_host_midi
import terminalio
import winterbloom_smolmidi as smolmidi
from adafruit_display_text import label
import displayio
import digitalio
import keypad
from cedargrove_midi_tools import note_to_name
display = board.DISPLAY
BORDER = 20
FONTSCALE = 2
R = 0#255
G = 255#191
B = 0
MONO_COLOR = ((R, G, B))
BACKGROUND_COLOR = ((R//6, G//6, B//6)) # 0x000900
# FOREGROUND_COLOR = 0x003000
TEXT_COLOR = MONO_COLOR # 0x00FF00
screen = displayio.Group()
display.root_group = screen
color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = BACKGROUND_COLOR
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
screen.append(bg_sprite)
# device label
text = "MIDI device"
device_label = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR)
device_width = device_label.bounding_box[2] * FONTSCALE
device_group = displayio.Group(scale=FONTSCALE,x=2,y=12,)
device_group.append(device_label) # Subgroup for text scaling
screen.append(device_group)
# channel label
text = "ch. "
channel_label = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR)
channel_width = channel_label.bounding_box[2] * FONTSCALE
channel_group = displayio.Group(scale=FONTSCALE,x=2,y=42,)
channel_group.append(channel_label) # Subgroup for text scaling
screen.append(channel_group)
# message label
text = "-- --"
note_label = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR)
note_width = note_label.bounding_box[2] * FONTSCALE
note_group = displayio.Group(scale=FONTSCALE,x=2,y=64,)
note_group.append(note_label) # Subgroup for text scaling
screen.append(note_group)
# message label
text = "cc: -- --"
cc_label = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR)
cc_width = cc_label.bounding_box[2] * FONTSCALE
cc_group = displayio.Group(scale=FONTSCALE,x=2,y=86,)
cc_group.append(cc_label) # Subgroup for text scaling
screen.append(cc_group)
# message label
text = "pitch bend 64"
pb_label = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR)
pb_width = cc_label.bounding_box[2] * FONTSCALE
pb_group = displayio.Group(scale=FONTSCALE,x=2,y=108,)
pb_group.append(pb_label) # Subgroup for text scaling
screen.append(pb_group)
spi = board.SPI()
cs = board.D10
irq = board.D9
host_chip = max3421e.Max3421E(spi, chip_select=cs, irq=irq)
# # You must wire up the needed resistors and jack yourself, or use the MIDI Feather wing
uart = busio.UART(rx=board.RX, tx=board.TX, baudrate=31250, timeout=0.001)
midi_usb_out = usb_midi.ports[1]
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
led_state = False
button0 = keypad.Keys((board.D0,), value_when_pressed=False, pull=True)
BUTTON_PINS = (board.D1, board.D2)
buttons = keypad.Keys(BUTTON_PINS, value_when_pressed=True, pull=True)
def send_midi_panic():
msg.type=smolmidi.NOTE_OFF
for x in range(128):
msg.data[0]=x
msg_bytes=bytes(msg) # wrap the message back up for sending
midi_usb_out.write(msg_bytes)
uart.write(msg_bytes)
def look_for_midi_usb_device():
"""Look for MIDI device on USB Host port, returns None if no device"""
midi_usb_device = None
for device in usb.core.find(find_all=True):
try:
midi_usb_device = adafruit_usb_host_midi.MIDI(device)
print("Found vid/pid %04x/%04x" % (device.idVendor, device.idProduct),
device.manufacturer, device.product)
device_label.text=(str(device.product))
time.sleep(2)
except ValueError:
print("bad device:", device)
device_label.text=("bad device:"+(str(device.product)))
return midi_usb_device
while True:
midi_usb_device = look_for_midi_usb_device()
if midi_usb_device:
print("Found MIDI device: ", midi_usb_device)
midi_device = smolmidi.MidiIn(midi_usb_device)
try:
while True:
event0 = button0.events.get()
if event0:
button_number = event0.key_number
print("button", button_number)
if event0.pressed:
if button_number == 0:
send_midi_panic()
print("midi panic")
event = buttons.events.get()
if event:
button_number = event.key_number
print("button", button_number)
if event.pressed:
if button_number == 0:
send_midi_panic()
print("midi panic")
msg = midi_device.receive()
if msg:
led.value=True
led_state=True
channel_label.text=("ch." + str(msg.channel+1))
msg_type_hex = (hex(msg.type))
if msg.type == smolmidi.NOTE_ON:
print("ch", msg.channel+1, msg_type_hex, "NOTE_ON", msg.data[0], msg.data[1])
# note_str=( "note on " + str(msg.data[0])+ " " + str(msg.data[1]) )
note_str=( note_to_name(msg.data[0])+ " " + str(msg.data[1]) )
note_label.text=(note_str)
# msg.data[0] = msg.data[0]+12 # bump up an ocatave
elif msg.type == smolmidi.NOTE_OFF:
print(msg_type_hex, "NOTE_OFF", msg.data[0], msg.data[1])
# note_str=( "note off " + str(msg.data[0])+ " " + str(msg.data[1]) )
note_str=( note_to_name(msg.data[0])+ " --")
note_label.text=(note_str)
# msg.data[0] = msg.data[0]+12 # bump up an ocatave
elif msg.type == smolmidi.CC:
print(msg_type_hex, "CC", msg.data[0], msg.data[1])
note_str=( "cc: " + str(msg.data[0])+ " " + str(msg.data[1]) )
cc_label.text=(note_str)
if msg.data[0]==82:
msg.data[0]=23
elif msg.type == smolmidi.PITCH_BEND:
print(msg_type_hex, "PITCH_BEND", msg.data[1])
note_str=( "pitch bend " + str(msg.data[1]) )
pb_label.text=(note_str)
elif msg.type == smolmidi.CHANNEL_PRESSURE:
print(msg_type_hex, "CHANNEL_PRESSURE", msg.data[0])
msg_bytes = bytes(msg)
# print("msg:", ["%2x" % v for v in msg_bytes])
msg_bytes=bytes(msg) # wrap the message back up for sending
midi_usb_out.write(msg_bytes)
uart.write(msg_bytes)
if led_state:
led.value=False
led_state=False
except usb.core.USBError:
print("device unplug? looking again for device")
device_label.text="looking for device"
else:
time.sleep(0.5)
print("looking for device")
device_label.text="looking for device"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment