ebbes-gma3-encoder-midi-con.../code.py

184 lines
5.9 KiB
Python

import board
import digitalio
import time
import usb_midi
import neopixel
from adafruit_midi import MIDI
from adafruit_midi.control_change import ControlChange
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff
from digitalio import DigitalInOut, Direction, Pull
from adafruit_debouncer import Debouncer
midi = MIDI(midi_out=usb_midi.ports[1], out_channel=0)
led = neopixel.NeoPixel(board.GP5, 7, brightness=0.5, auto_write=True)
encoder_colors = [
(255, 0, 0), # Red
(0, 255, 0), # Green
(0, 0, 255), # Blue
(0, 255, 255), # Cyan
(255, 0, 255) # Magenta
]
# Encoder Pins
clk = DigitalInOut(board.GP20)
clk.direction = Direction.INPUT
clk.pull = Pull.UP
dt = DigitalInOut(board.GP18)
dt.direction = Direction.INPUT
dt.pull = Pull.UP
last_clk = clk.value
# Buttons
enc_button_pin = DigitalInOut(board.GP17)
enc_button_pin.switch_to_input(pull=Pull.UP)
enc_button = Debouncer(enc_button_pin)
next_button_pin = DigitalInOut(board.GP15)
next_button_pin.switch_to_input(pull=Pull.UP)
next_button = Debouncer(next_button_pin)
back_button_pin = DigitalInOut(board.GP14)
back_button_pin.switch_to_input(pull=Pull.UP)
back_button = Debouncer(back_button_pin)
mode_toggle_button_pin = DigitalInOut(board.GP13)
mode_toggle_button_pin.switch_to_input(pull=Pull.UP)
mode_toggle_button = Debouncer(mode_toggle_button_pin)
# States
current_encoder = 0
encoder_cc_notes = [1, 2, 3, 4, 5]
encoder_bttn_notes = [11, 12, 13, 14, 15]
mode_toggle_note = 21
# Functions
def encoder_sweep(direction):
sweep_order = [3, 4, 5, 6] if direction == "CW" else [6, 5, 4, 3]
for i in sweep_order:
led[i] = (255, 255, 255)
if direction == "CW" and i > 3:
led[i - 1] = (100, 100, 100)
elif direction == "CCW" and i < 6:
led[i + 1] = (100, 100, 100)
time.sleep(0.02)
led[i] = encoder_colors[current_encoder]
if direction == "CW" and i > 3:
led[i - 1] = encoder_colors[current_encoder]
elif direction == "CCW" and i < 6:
led[i + 1] = encoder_colors[current_encoder]
def startup_animation():
print("Running startup LED test animation...")
start_time = time.monotonic()
button_indices = [0, 1, 2]
encoder_indices = [3, 4, 5, 6]
while time.monotonic() - start_time < 5:
for i in range(len(encoder_indices)):
led[encoder_indices[i]] = (255, 255, 255)
if i > 0:
led[encoder_indices[i - 1]] = (0, 0, 0)
time.sleep(0.05)
led[encoder_indices[-1]] = (0, 0, 0)
# Fade up and down the button LEDs
for b in range(0, 256, 10):
for i in button_indices:
led[i] = (b, b, b)
time.sleep(0.01)
for b in range(255, -1, -10):
for i in button_indices:
led[i] = (b, b, b)
time.sleep(0.01)
# Fade in to start colors
target_colors = [
encoder_colors[(current_encoder + 1) % len(encoder_colors)], # LED 0
encoder_colors[(current_encoder - 1) % len(encoder_colors)], # LED 1
(63, 63, 63), # LED 2 at 25% white
]
for step in range(0, 101, 5):
for i in range(3):
led[i] = tuple(int(c * step / 100) for c in target_colors[i])
for i in range(3, 7):
led[i] = tuple(int(c * step / 100) for c in encoder_colors[current_encoder])
time.sleep(0.02)
# -------------------- Startup -----------------------
print("MIDI Encoder Controller started.")
startup_animation()
led[3:7] = [encoder_colors[current_encoder]] * 4
led[0] = encoder_colors[(current_encoder + 1) % len(encoder_colors)]
led[1] = encoder_colors[(current_encoder - 1) % len(encoder_colors)]
led[2] = (63, 63, 63) # Mode toggle LED default 25% white
mode_button_state_note = 0
# -------------------- Main Loop ---------------------
while True:
enc_button.update()
next_button.update()
back_button.update()
mode_toggle_button.update()
# Rotary Encoder Logic
if clk.value != last_clk and clk.value == False:
direction = None
if dt.value != clk.value:
direction = "CW"
midi.send(ControlChange(encoder_cc_notes[current_encoder], 1))
else:
direction = "CCW"
midi.send(ControlChange(encoder_cc_notes[current_encoder], 127))
encoder_sweep(direction)
last_clk = clk.value
# Encoder Button
if enc_button.fell:
midi.send(NoteOn(encoder_bttn_notes[current_encoder], 127))
if enc_button.rose:
midi.send(NoteOff(encoder_bttn_notes[current_encoder], 0))
# Next Encoder Button
if next_button.fell:
current_encoder = (current_encoder + 1) % len(encoder_cc_notes)
forward_color = encoder_colors[(current_encoder + 1) % len(encoder_colors)]
backward_color = encoder_colors[(current_encoder - 1) % len(encoder_colors)]
led[3:7] = [encoder_colors[current_encoder]] * 4
led[0] = forward_color
led[1] = backward_color
# Back Encoder Button
if back_button.fell:
current_encoder = (current_encoder - 1) % len(encoder_cc_notes)
forward_color = encoder_colors[(current_encoder + 1) % len(encoder_colors)]
backward_color = encoder_colors[(current_encoder - 1) % len(encoder_colors)]
led[3:7] = [encoder_colors[current_encoder]] * 4
led[0] = forward_color
led[1] = backward_color
# Mode Toggle Button
if mode_toggle_button.fell:
if mode_button_state_note == 0:
mode_button_state_note = 127
elif mode_button_state_note == 127:
mode_button_state_note = 0
else:
mode_button_state_note = 0
midi.send(NoteOn(mode_toggle_note, mode_button_state_note))
for b in range(100, 24, -5):
level = int(255 * b / 100)
led[2] = (level, level, level)
time.sleep(0.02)
led[2] = (63, 63, 63)
time.sleep(0.001)