diff --git a/code.py b/code.py new file mode 100644 index 0000000..59049a4 --- /dev/null +++ b/code.py @@ -0,0 +1,183 @@ +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) diff --git a/lib/adafruit_debouncer.mpy b/lib/adafruit_debouncer.mpy new file mode 100644 index 0000000..ae577e0 Binary files /dev/null and b/lib/adafruit_debouncer.mpy differ diff --git a/lib/adafruit_midi/__init__.mpy b/lib/adafruit_midi/__init__.mpy new file mode 100644 index 0000000..0dc7de9 Binary files /dev/null and b/lib/adafruit_midi/__init__.mpy differ diff --git a/lib/adafruit_midi/active_sensing.mpy b/lib/adafruit_midi/active_sensing.mpy new file mode 100644 index 0000000..0c0c571 Binary files /dev/null and b/lib/adafruit_midi/active_sensing.mpy differ diff --git a/lib/adafruit_midi/channel_pressure.mpy b/lib/adafruit_midi/channel_pressure.mpy new file mode 100644 index 0000000..c012579 Binary files /dev/null and b/lib/adafruit_midi/channel_pressure.mpy differ diff --git a/lib/adafruit_midi/control_change.mpy b/lib/adafruit_midi/control_change.mpy new file mode 100644 index 0000000..dad085c Binary files /dev/null and b/lib/adafruit_midi/control_change.mpy differ diff --git a/lib/adafruit_midi/control_change_values.mpy b/lib/adafruit_midi/control_change_values.mpy new file mode 100644 index 0000000..2415eb7 Binary files /dev/null and b/lib/adafruit_midi/control_change_values.mpy differ diff --git a/lib/adafruit_midi/midi_continue.mpy b/lib/adafruit_midi/midi_continue.mpy new file mode 100644 index 0000000..140487c Binary files /dev/null and b/lib/adafruit_midi/midi_continue.mpy differ diff --git a/lib/adafruit_midi/midi_message.mpy b/lib/adafruit_midi/midi_message.mpy new file mode 100644 index 0000000..2c7dec9 Binary files /dev/null and b/lib/adafruit_midi/midi_message.mpy differ diff --git a/lib/adafruit_midi/mtc_quarter_frame.mpy b/lib/adafruit_midi/mtc_quarter_frame.mpy new file mode 100644 index 0000000..fe374b5 Binary files /dev/null and b/lib/adafruit_midi/mtc_quarter_frame.mpy differ diff --git a/lib/adafruit_midi/note_off.mpy b/lib/adafruit_midi/note_off.mpy new file mode 100644 index 0000000..931212b Binary files /dev/null and b/lib/adafruit_midi/note_off.mpy differ diff --git a/lib/adafruit_midi/note_on.mpy b/lib/adafruit_midi/note_on.mpy new file mode 100644 index 0000000..47ebf8b Binary files /dev/null and b/lib/adafruit_midi/note_on.mpy differ diff --git a/lib/adafruit_midi/pitch_bend.mpy b/lib/adafruit_midi/pitch_bend.mpy new file mode 100644 index 0000000..422d8c7 Binary files /dev/null and b/lib/adafruit_midi/pitch_bend.mpy differ diff --git a/lib/adafruit_midi/polyphonic_key_pressure.mpy b/lib/adafruit_midi/polyphonic_key_pressure.mpy new file mode 100644 index 0000000..c864689 Binary files /dev/null and b/lib/adafruit_midi/polyphonic_key_pressure.mpy differ diff --git a/lib/adafruit_midi/program_change.mpy b/lib/adafruit_midi/program_change.mpy new file mode 100644 index 0000000..00d4156 Binary files /dev/null and b/lib/adafruit_midi/program_change.mpy differ diff --git a/lib/adafruit_midi/start.mpy b/lib/adafruit_midi/start.mpy new file mode 100644 index 0000000..0eac4fd Binary files /dev/null and b/lib/adafruit_midi/start.mpy differ diff --git a/lib/adafruit_midi/stop.mpy b/lib/adafruit_midi/stop.mpy new file mode 100644 index 0000000..3ce31af Binary files /dev/null and b/lib/adafruit_midi/stop.mpy differ diff --git a/lib/adafruit_midi/system_exclusive.mpy b/lib/adafruit_midi/system_exclusive.mpy new file mode 100644 index 0000000..cd6d6e4 Binary files /dev/null and b/lib/adafruit_midi/system_exclusive.mpy differ diff --git a/lib/adafruit_midi/timing_clock.mpy b/lib/adafruit_midi/timing_clock.mpy new file mode 100644 index 0000000..e8e4430 Binary files /dev/null and b/lib/adafruit_midi/timing_clock.mpy differ diff --git a/lib/adafruit_pixelbuf.mpy b/lib/adafruit_pixelbuf.mpy new file mode 100644 index 0000000..3868228 Binary files /dev/null and b/lib/adafruit_pixelbuf.mpy differ diff --git a/lib/adafruit_ticks.mpy b/lib/adafruit_ticks.mpy new file mode 100644 index 0000000..939beb4 Binary files /dev/null and b/lib/adafruit_ticks.mpy differ diff --git a/lib/neopixel.mpy b/lib/neopixel.mpy new file mode 100644 index 0000000..e6d0dc6 Binary files /dev/null and b/lib/neopixel.mpy differ