Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active August 31, 2022 22:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save todbot/ec5c6ed9101fe25bc741e22599f30361 to your computer and use it in GitHub Desktop.
Save todbot/ec5c6ed9101fe25bc741e22599f30361 to your computer and use it in GitHub Desktop.
Show incoming MIDI as raining MIDI notes on Neopixel grid / matrix in CircuitPython
# midi_visualizer.py -- show incoming MIDI as raining MIDI notes on Neopixel grid / matrix
# 31 Aug 2022 - @todbot / Tod Kurt
# inspired by
# https://www.reddit.com/r/esp32/comments/wwah4v/i_made_a_midi_to_led_interface_with_an_esp32_more/
# uses SmolMIDI from Winterbloom: https://github.com/wntrblm/Winterbloom_SmolMIDI
import time
import board
# libraries installed with circup
import usb_midi
import neopixel
import adafruit_pixel_framebuf
# local libraries in CIRCUITPY
import winterbloom_smolmidi as smolmidi
usb_out = usb_midi.ports[1]
usb_in = usb_midi.ports[0]
usb_midi_in = smolmidi.MidiIn(usb_in)
base_note = 36
play_colors = [0xff0000, 0xff0000, 0x00ffff, 0xffff00, 0xff00ff ]
dim = 35
leds_w = 16
leds_h = 8
leds_num = leds_w * leds_h
leds = neopixel.NeoPixel(board.GP15, leds_num, brightness=0.2, auto_write=False)
leds_framebuf = adafruit_pixel_framebuf.PixelFramebuffer( leds, leds_w, leds_h,
reverse_x=True, alternating=True)
leds_framebuf.fill(0x000033)
leds_framebuf.display()
playing_notes = [] # which notes are playing
def midi_receive():
global playing_notes, base_note
while msg := usb_midi_in.receive(): # get to use walrus operator!
if msg.type == smolmidi.NOTE_ON:
note = msg.data[0]
if base_note == 0: base_note = note
playing_notes.append( note )
elif msg.type == smolmidi.NOTE_OFF:
note = msg.data[0]
try:
playing_notes.remove( note )
except ValueError: # note already removed
pass
def display_notes():
# copy old notes to new line
leds_framebuf.scroll(0,1)
# display new notes
for n in playing_notes:
nn = (n % 12) + 4 #
noct = ((n-base_note) // 12) % len(play_colors)
play_color = play_colors[noct]
leds_framebuf.pixel(nn, 0, play_color)
# dim all LEDs
for y in range(leds_h):
for x in range(leds_w):
c = leds_framebuf.pixel(x,y) # this returns an int not a tuple
ca = (c >> 16) & 255, (c >> 8) & 255, c & 255 # make tuple
c = (max(ca[0] - dim,0), max(ca[1] - dim,0), max(ca[2] - dim,0)) # dim
leds_framebuf.pixel(x, y, c) # put new color back
leds_framebuf.display()
while True:
midi_receive()
display_notes()
@todbot
Copy link
Author

todbot commented Aug 31, 2022

Here's a demo video of the above code:

midi_visualizeer.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment