Skip to content

Instantly share code, notes, and snippets.

@GottZ
Last active April 26, 2023 11:15
Show Gist options
  • Save GottZ/5e6477eccf36e6eda4f3ffa6b89d4e95 to your computer and use it in GitHub Desktop.
Save GottZ/5e6477eccf36e6eda4f3ffa6b89d4e95 to your computer and use it in GitHub Desktop.
little CircuitPython USB MIDI wrapper for the Adafruit Neo Trinkey SAMD21 USB. It forwards the touch inputs to control channels 1 and 2 and allows setting the LED's according to line
# for Adafruit Neo Trinkey SAMD21 USB https://www.adafruit.com/product/4870
# code is at: https://gist.github.com/GottZ/5e6477eccf36e6eda4f3ffa6b89d4e95
# revision 4
#
# touch pads will send control change events for 1 and 2 with 127 and 0 for their state
# when touching both at once, it will emit a control change event with id 3 additionally to 1 and 2
# if you want this with a delay, just remove # for all code lines that have been commented out
#
# the four neopixel LED's will respond to defined control change events as defined in the midipixels tuple
# 10, 20, 30 and 40 describe the led position. 10 is red, 11 is green, 12 is blue, 13 set's rgb to greyscale
# 50 is special, it will behave like a led but instead change all led's at once.
#import time
import board
import neopixel
import touchio
import usb_midi
import adafruit_midi
from adafruit_midi.midi_message import MIDIMessage
from adafruit_midi.control_change import ControlChange
# neopixels:
pixels = neopixel.NeoPixel(board.NEOPIXEL, 4, brightness=1, auto_write=False)
# touch pads:
touch1 = touchio.TouchIn(board.TOUCH1)
touch2 = touchio.TouchIn(board.TOUCH2)
# generic midi boilerplate:
midi = adafruit_midi.MIDI(
midi_in=usb_midi.ports[0],
midi_out=usb_midi.ports[1],
in_channel=0,
out_channel=0,
)
# state machines:
touch1_pressed = False
touch2_pressed = False
touch3_pressed = False # both touch inputs together
# you may enable these commented out things (also down in the code) to have a delay for the third touch event.
#touch1_ev = None
#touch2_ev = None
#touch3_delay = 0.1
# neopixel midi channels:
midipixels = {
# bottom right
10: (0, 0), # red
11: (0, 1), # green
12: (0, 2), # blue
13: (0, (0, 1, 2)), # white
# bottom left
20: (1, 0),
21: (1, 1),
22: (1, 2),
23: (1, (0, 1, 2)),
# top left
30: (2, 0),
31: (2, 1),
32: (2, 2),
33: (2, (0, 1, 2)),
# top right
40: (3, 0),
41: (3, 1),
42: (3, 2),
43: (3, (0, 1, 2)),
# all 4 led's:
50: ((0, 1, 2, 3), 0),
51: ((0, 1, 2, 3), 1),
52: ((0, 1, 2, 3), 2),
53: ((0, 1, 2, 3), (0, 1, 2)),
}
while True:
#now = time.monotonic()
if touch1_pressed is not touch1.value:
touch1_pressed = not touch1_pressed
#touch1_ev = (None, now)[touch1_pressed]
midi.send(ControlChange(1, (0, 127)[touch1_pressed]))
if touch2_pressed is not touch2.value:
touch2_pressed = not touch2_pressed
#touch2_ev = (None, now)[touch2_pressed]
midi.send(ControlChange(2, (0, 127)[touch2_pressed]))
#if not touch3_pressed and touch1_pressed and touch2_pressed and (touch1_ev + touch3_delay) < now and (touch2_ev + touch3_delay) < now:
if not touch3_pressed and touch1_pressed and touch2_pressed:
touch3_pressed = True
midi.send(ControlChange(3, 127))
elif touch3_pressed and (not touch1_pressed or not touch2_pressed):
touch3_pressed = False
midi.send(ControlChange(3, 0))
msg = midi.receive()
if msg is None:
continue
if not isinstance(msg, ControlChange):
continue
control = msg.control
value = msg.value
if control not in midipixels:
continue
(pt, it) = midipixels[control]
if type(pt) is not tuple:
pt = (pt,)
if type(it) is not tuple:
it = (it,)
for p in pt:
for i in it:
pixels[p] = pixels[p][0:i] + (value,) + pixels[p][i + 1 : 3]
pixels.show()
@GottZ
Copy link
Author

GottZ commented Apr 26, 2023

20230426_130959.mp4

video showing how it can be used

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