Created
February 3, 2023 21:50
-
-
Save remisarrailh/9d4da7d59445054ded1184b5b894334e to your computer and use it in GitHub Desktop.
co
This file contains hidden or 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 displayio | |
import terminalio | |
import adafruit_aw9523 | |
import busio | |
import adafruit_ssd1327 | |
import digitalio | |
from adafruit_display_text import label | |
from adafruit_display_shapes.circle import Circle | |
from adafruit_display_shapes.rect import Rect | |
import usb_midi | |
import adafruit_midi | |
from adafruit_midi.note_on import NoteOn | |
from adafruit_midi.note_off import NoteOff | |
from presets import * | |
from pins import * | |
# Turn on LED on Pico | |
led = digitalio.DigitalInOut(board.LED) | |
led.direction = digitalio.Direction.OUTPUT | |
led.value = True | |
# Conversion between midi notes and american notation | |
NOTES = ["C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1", "G#-1", "A-1", "A#-1", "B-1", | |
"C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", | |
"C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", | |
"C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", | |
"C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", | |
"C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", | |
"C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", | |
"C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", | |
"C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", | |
"C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", | |
"C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9" | |
] | |
displayio.release_displays() | |
# i2c setup, higher frequency for display refresh | |
i2c = busio.I2C(board.GP1, board.GP0, frequency=1000000) | |
# i2c display setup | |
display_bus = displayio.I2CDisplay(i2c, device_address=0x3d) | |
# i2c AW9523 GPIO expander setup | |
aw = adafruit_aw9523.AW9523(i2c) | |
# MIDI setup as MIDI out device | |
#midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) | |
uart = busio.UART(board.GP16, board.GP17, baudrate=31250) | |
midi_channel = 12 | |
midi = adafruit_midi.MIDI( | |
midi_in=uart, | |
midi_out=uart, | |
in_channel=1, | |
out_channel=midi_channel, | |
debug=True | |
) | |
# display dimensions | |
WIDTH = 128 | |
HEIGHT = 128 | |
# display setup | |
display = adafruit_ssd1327.SSD1327(display_bus, width=WIDTH, height=HEIGHT, brightness=1) | |
# main display group, shows default GUI menu | |
splash = displayio.Group() | |
# group for circle icons | |
circle_group = displayio.Group() | |
# group for text labels on circles | |
text_group = displayio.Group() | |
# list of circle positions | |
spots = ( | |
(16, 16), | |
(48, 16), | |
(80, 16), | |
(112, 16), | |
(16, 48), | |
(48, 48), | |
(80, 48), | |
(112, 48), | |
(16, 80), | |
(48, 80), | |
(80, 80), | |
(112, 80), | |
(16, 112), | |
(48, 112), | |
(80, 112), | |
(112, 112), | |
) | |
# creating the circles & pulling in positions from spots | |
for spot in spots: | |
circle = Circle(x0=spot[0], y0=spot[1], r=14, fill=0x888888) | |
# adding circles to their display group | |
circle_group.append(circle) | |
# square to show position on menu | |
rect = Rect(0, 0, 33, 33, fill=None, outline=0x00FF00, stroke=3) | |
splash.append(circle_group) | |
splash.append(rect) | |
# strings and positions for the MIDI note text labels | |
texts = [ | |
{'num': NOTES[midi_notes[0]], 'pos': (10, 16)}, | |
{'num': NOTES[midi_notes[1]], 'pos': (42, 16)}, | |
{'num': NOTES[midi_notes[2]], 'pos': (74, 16)}, | |
{'num': NOTES[midi_notes[3]], 'pos': (106, 16)}, | |
{'num': NOTES[midi_notes[4]], 'pos': (10, 48)}, | |
{'num': NOTES[midi_notes[5]], 'pos': (42, 48)}, | |
{'num': NOTES[midi_notes[6]], 'pos': (74, 48)}, | |
{'num': NOTES[midi_notes[7]], 'pos': (106, 48)}, | |
{'num': NOTES[midi_notes[8]], 'pos': (10, 80)}, | |
{'num': NOTES[midi_notes[9]], 'pos': (42, 80)}, | |
{'num': NOTES[midi_notes[10]], 'pos': (74, 80)}, | |
{'num': NOTES[midi_notes[11]], 'pos': (106, 80)}, | |
{'num': NOTES[midi_notes[12]], 'pos': (10, 112)}, | |
{'num': NOTES[midi_notes[13]], 'pos': (42, 112)}, | |
{'num': NOTES[midi_notes[14]], 'pos': (74, 112)}, | |
{'num':NOTES[midi_notes[15]], 'pos': (106, 112)}, | |
] | |
text_labels = [] | |
for text in texts: | |
text_area = label.Label(terminalio.FONT, text=text['num'], color=0xFFFFFF) | |
text_area.x = text['pos'][0] | |
text_area.y = text['pos'][1] | |
text_labels.append(text_area) | |
text_group.append(text_area) | |
splash.append(text_group) | |
# secondary display group, shows large circle when button is selected | |
big_splash = displayio.Group() | |
# large circle to fill display | |
big_circle = Circle(x0=64, y0=64, r=62, fill=0x888888) | |
big_splash.append(big_circle) | |
# large text to fill circle | |
big_text = label.Label(terminalio.FONT, text=' ', color=0xFFFFFF) | |
big_text.x = 38 | |
big_text.y = 60 | |
big_text.scale = 4 | |
big_splash.append(big_text) | |
selection_splash = displayio.Group() | |
selection_text = label.Label(terminalio.FONT, text=' ', color=0xFFFFFF) | |
selection_text.x = 0 | |
selection_text.y = 60 | |
selection_text.scale = 2 | |
selection_splash.append(selection_text) | |
# array for LEDs on AW9523 | |
leds = [] | |
led_pins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] | |
# setup to create the AW9523 outputs for LEDs | |
for led in led_pins: | |
led_pin = aw.get_pin(led) | |
led_pin.direction = digitalio.Direction.OUTPUT | |
leds.append(led_pin) | |
note_buttons = [] | |
for pin in note_pins: | |
note_pin = digitalio.DigitalInOut(pin) | |
note_pin.direction = digitalio.Direction.INPUT | |
note_pin.pull = digitalio.Pull.UP | |
note_buttons.append(note_pin) | |
# note states | |
note0_pressed = False | |
note1_pressed = False | |
note2_pressed = False | |
note3_pressed = False | |
note4_pressed = False | |
note5_pressed = False | |
note6_pressed = False | |
note7_pressed = False | |
note8_pressed = False | |
note9_pressed = False | |
note10_pressed = False | |
note11_pressed = False | |
note12_pressed = False | |
note13_pressed = False | |
note14_pressed = False | |
note15_pressed = False | |
# array of note states | |
note_states = [note0_pressed, note1_pressed, note2_pressed, note3_pressed, | |
note4_pressed, note5_pressed, note6_pressed, note7_pressed, | |
note8_pressed, note9_pressed, note10_pressed, note11_pressed, | |
note12_pressed, note13_pressed, note14_pressed, note15_pressed] | |
# array for 5-way switch | |
joystick = [select, up, down, left, right] | |
for joy in joystick: | |
joy.direction = digitalio.Direction.INPUT | |
joy.pull = digitalio.Pull.UP | |
# states for 5-way switch | |
select_state = None | |
up_state = None | |
down_state = None | |
left_state = None | |
right_state = None | |
midi_state = None | |
# coordinates for navigating main GUI | |
select_x = [0, 32, 64, 96] | |
select_y = [0, 32, 64, 96] | |
# y coordinate for 5-way switch navigation | |
y_pos = 0 | |
# x coordinate for 5-way switch navigation | |
x_pos = 0 | |
sub_state = False | |
# default midi number | |
midi_num = 60 | |
# default MIDI button | |
button_num = 0 | |
# default MIDI button position | |
button_pos = 0 | |
# check for blinking LED | |
led_check = None | |
# time.monotonic() device | |
clock = time.monotonic() | |
clock_select_long = time.monotonic() | |
select_long_counter = 0 | |
clock_button_repeat = time.monotonic_ns() | |
button_repeat = 0 | |
note_selection = 0 | |
# coordinates for tracking location of 5-way switch | |
up_scroll = 0 | |
down_scroll = 0 | |
left_scroll = 0 | |
right_scroll = 0 | |
switch_coordinates = [(0, 0), (1, 0), (2, 0), (3, 0), | |
(0, 1), (1, 1), (2, 1), (3, 1), | |
(0, 2), (1, 2), (2, 2), (3, 2), | |
(0, 3), (1, 3), (2, 3), (3, 3)] | |
# show main display GUI | |
display.show(splash) | |
pressed = False | |
while True: | |
# debouncing for 5-way switch positions | |
if up.value and up_state == "pressed": | |
up_state = None | |
pressed = False | |
if down.value and down_state == "pressed": | |
down_state = None | |
down_state = None | |
pressed = False | |
if left.value and left_state == "pressed": | |
left_state = None | |
pressed = False | |
if right.value and right_state == "pressed": | |
right_state = None | |
pressed = False | |
if select.value and select_state == "pressed": | |
select_state = None | |
# MIDI input | |
for i in range(16): | |
buttons = note_buttons[i] | |
if not buttons.value and note_states[i] is False: | |
# send the MIDI note and light up the LED | |
leds[i].value = True | |
midi.send(NoteOn(midi_notes[i], velocity_standard)) | |
#midi.write(bytes([0x90], notes[i], velocity_standard)) | |
note_states[i] = True | |
# if the button is released... | |
if buttons.value and note_states[i] is True: | |
# stop sending the MIDI note and turn off the LED | |
midi.send(NoteOff(midi_notes[i], velocity_standard)) | |
leds[i].value = False | |
note_states[i] = False | |
# if we're on the main GUI page | |
if not sub_state: | |
# if you press up on the 5-way switch... | |
if not up.value and up_state is None: | |
up_state = "pressed" | |
# track the switch's position | |
up_scroll -= 1 | |
if up_scroll < 0: | |
up_scroll = 3 | |
y_pos = up_scroll | |
down_scroll = up_scroll | |
# if you press down on the 5-way switch... | |
if not down.value and down_state is None: | |
down_state = "pressed" | |
# track the switch's position | |
down_scroll += 1 | |
if down_scroll > 3: | |
down_scroll = 0 | |
y_pos = down_scroll | |
up_scroll = down_scroll | |
# if you press left on the 5-way switch... | |
if not left.value and left_state is None: | |
# print("scroll", down_scroll) | |
left_state = "pressed" | |
# track the switch's position | |
left_scroll -= 1 | |
if left_scroll < 0: | |
left_scroll = 3 | |
x_pos = left_scroll | |
right_scroll = left_scroll | |
# if you press right on the 5-way switch... | |
if not right.value and right_state is None: | |
# print("scroll", down_scroll) | |
right_state = "pressed" | |
# track the switch's position | |
right_scroll += 1 | |
if right_scroll > 3: | |
right_scroll = 0 | |
x_pos = right_scroll | |
left_scroll = right_scroll | |
# update square's position on the GUI | |
rect.y = select_y[y_pos] | |
rect.x = select_x[x_pos] | |
# update the currently highlighted button on the GUI | |
for coords in switch_coordinates: | |
if x_pos == coords[0] and y_pos == coords[1]: | |
button_pos = switch_coordinates.index(coords) | |
# print(button_pos) | |
button_num = midi_notes[button_pos] | |
# if you press select on the 5-way switch... | |
if not select.value and select_state is None: | |
select_state = "pressed" | |
# grab the selected button's MIDI note | |
midi_num = button_num | |
# change into the secondary GUI menu | |
sub_state = True | |
# if an arcade button is selected to change the MIDI note... | |
if sub_state: | |
# display the secondary GUI menu | |
display.show(big_splash) | |
# display the selected button's MIDI note | |
big_text.text = NOTES[midi_num] | |
# blink the selected button's LED without pausing the loop | |
if (time.monotonic() > (clock + 1)) and led_check is None: | |
leds[button_pos].value = True | |
led_check = True | |
clock = time.monotonic() | |
if (time.monotonic() > (clock + 1)) and led_check is True: | |
leds[button_pos].value = False | |
led_check = None | |
clock = time.monotonic() | |
if (time.monotonic() > (clock_select_long + 1)): | |
if not select.value: | |
#print(select_long_counter) | |
select_long_counter += 1 | |
else: | |
if select_long_counter != 0: | |
select_long_counter = 0 | |
clock_select_long = time.monotonic() | |
# Change note if select pressed for 3 seconds | |
if select_long_counter == time_before_change_notes: | |
selection_text.text, note_selection, midi_notes = changes_notes(note_selection) | |
display.show(selection_splash) | |
# Leds show! | |
for led in leds: | |
led.value = True | |
time.sleep(0.03) | |
for led in leds: | |
led.value = False | |
time.sleep(0.03) | |
# Reset oled interface | |
select_long_counter = 0 | |
sub_state = False | |
# Reset text on OLED | |
for i in range(16): | |
text_labels[i].text = NOTES[midi_notes[i]] | |
# show main GUI display | |
display.show(splash) | |
# turn off blinking LED | |
leds[button_pos].value = False | |
# blocks the MIDI number from being set above 128 | |
if midi_num >= 128: | |
midi_num = 128 | |
# blocks the MIDI number from being set below 0 | |
if midi_num <= 0: | |
midi_num = 0 | |
# if you press right on the 5-way switch... | |
if not right.value and right_state is None: | |
# increase the MIDI number | |
midi_num += 1 | |
right_state = "pressed" | |
# if you press up on the 5-way switch... | |
if not up.value and up_state is None: | |
# increase the MIDI number | |
midi_num += 1 | |
up_state = "pressed" | |
# if you press left on the 5-way switch... | |
if not left.value and left_state is None: | |
# decrease the MIDI number | |
midi_num -= 1 | |
left_state = "pressed" | |
# if you press down on the 5-way switch... | |
if not down.value and down_state is None: | |
# decrease the MIDI number | |
midi_num -= 1 | |
down_state = "pressed" | |
# update arcade button's MIDI note | |
# allows you to check note while you're adjusting it | |
midi_notes[button_pos] = midi_num | |
# if you press select on the 5-way switch... | |
if not select.value and select_state is None: | |
print(midi_notes) | |
select_state = "pressed" | |
# change back to main menu mode | |
sub_state = False | |
# update new MIDI number text label | |
text_labels[button_pos].text = NOTES[midi_num] | |
# show main GUI display | |
display.show(splash) | |
# turn off blinking LED | |
leds[button_pos].value = False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment