|
|
@@ -0,0 +1,238 @@ |
|
|
import time |
|
|
import board |
|
|
import neopixel |
|
|
import math |
|
|
import rotaryio |
|
|
import board |
|
|
import digitalio |
|
|
import adafruit_rgbled |
|
|
import busio |
|
|
import adafruit_midi |
|
|
from adafruit_midi.control_change import ControlChange |
|
|
from adafruit_midi.note_off import NoteOff |
|
|
from adafruit_midi.note_on import NoteOn |
|
|
from adafruit_midi.pitch_bend import PitchBend |
|
|
from adafruit_midi.timing_Clock import TimingClock |
|
|
from adafruit_midi.start import Start |
|
|
from adafruit_midi.stop import Stop |
|
|
|
|
|
|
|
|
###################### Midi Setup |
|
|
midiuart = busio.UART(board.GP16, board.GP17, baudrate=31250, timeout=0.00001) |
|
|
midi = adafruit_midi.MIDI( |
|
|
midi_in=midiuart, in_channel=0, midi_out=midiuart, out_channel=0, debug=True |
|
|
) |
|
|
|
|
|
|
|
|
###################### Neopixel Setup |
|
|
num_pixels = 24 |
|
|
|
|
|
pixels = neopixel.NeoPixel(board.GP9, num_pixels, pixel_order=neopixel.GRB, auto_write=False) |
|
|
pixels.brightness = 0.1 |
|
|
pixels.fill((0,0,0)) |
|
|
pixels.show() |
|
|
|
|
|
render_last = time.monotonic_ns() |
|
|
render_delay = 100000000 |
|
|
|
|
|
num_small_pixels = 12 |
|
|
|
|
|
small_pixels = neopixel.NeoPixel(board.GP8, num_small_pixels, pixel_order=neopixel.GRB, auto_write=False) |
|
|
small_pixels.brightness = 0.05 |
|
|
small_pixels.fill((0,0,0)) |
|
|
small_pixels.show() |
|
|
|
|
|
def translate(value, leftMin, leftMax, rightMin, rightMax): |
|
|
leftSpan = leftMax - leftMin |
|
|
rightSpan = rightMax - rightMin |
|
|
valueScaled = float(value - leftMin) / float(leftSpan) |
|
|
return rightMin + (valueScaled * rightSpan) |
|
|
|
|
|
def amount_small_circle(amount = 0, color=(0, 150, 156)): |
|
|
for i in range(num_small_pixels): |
|
|
if i < amount: |
|
|
small_pixels[i] = color |
|
|
else: |
|
|
small_pixels[i] = (0,0,0) |
|
|
small_pixels.show() |
|
|
|
|
|
###################### Rotary Encoder Setup |
|
|
button = digitalio.DigitalInOut(board.GP10) |
|
|
button.direction = digitalio.Direction.INPUT |
|
|
button.pull = digitalio.Pull.DOWN |
|
|
|
|
|
button_state = None |
|
|
|
|
|
encoder = rotaryio.IncrementalEncoder(board.GP18, board.GP19) |
|
|
last_position = None |
|
|
|
|
|
###################### Button Row Setup |
|
|
black_button = digitalio.DigitalInOut(board.GP4) |
|
|
black_button.direction = digitalio.Direction.INPUT |
|
|
black_button.pull = digitalio.Pull.DOWN |
|
|
black_button_event = None |
|
|
|
|
|
yellow_button = digitalio.DigitalInOut(board.GP3) |
|
|
yellow_button.direction = digitalio.Direction.INPUT |
|
|
yellow_button.pull = digitalio.Pull.DOWN |
|
|
yellow_button_event = None |
|
|
|
|
|
white_button = digitalio.DigitalInOut(board.GP5) |
|
|
white_button.direction = digitalio.Direction.INPUT |
|
|
white_button.pull = digitalio.Pull.DOWN |
|
|
white_button_event = None |
|
|
|
|
|
red_button = digitalio.DigitalInOut(board.GP2) |
|
|
red_button.direction = digitalio.Direction.INPUT |
|
|
red_button.pull = digitalio.Pull.DOWN |
|
|
red_button_event = None |
|
|
|
|
|
|
|
|
###################### Sequencer Setup Setup |
|
|
start_sequencer = False |
|
|
|
|
|
active_sequence = 0 |
|
|
num_sequence = 5 |
|
|
|
|
|
amo = [0, 0, 0, 0, 0] |
|
|
off = [12, 12, 12, 12, 12] |
|
|
|
|
|
sequence = [] |
|
|
for i in range(num_sequence): |
|
|
sequence.append([(0,0,0) for _ in range(num_pixels)]) |
|
|
|
|
|
|
|
|
beats_per_minute = 120 |
|
|
steps_per_beat = 6 |
|
|
tick_time = ((60 / beats_per_minute) / steps_per_beat) * 1000000000 |
|
|
|
|
|
amount_small_circle(math.floor(translate(beats_per_minute, 40, 240, 0, 12))) |
|
|
# print("Tick time in nano seconds: ", tick_time) |
|
|
tick_last = time.monotonic_ns() |
|
|
# print("Tick last: ", tick_last) |
|
|
tick_counter = 12 |
|
|
tick_color = [(196, 0, 163), (101, 0, 200), (2, 179, 75), (212, 141, 0), (0, 212, 14)] |
|
|
|
|
|
beat_start_color = [(0, 71, 212), (227, 204, 0), (204, 0, 112), (0, 204, 143), (183, 0, 255) ] |
|
|
beat_step_color = [(0, 23, 69),(92, 82, 0), (60, 0, 30), (0, 74, 52), (30, 0, 30), ] |
|
|
|
|
|
#beat_led = digitalio.DigitalInOut(board.GP11) |
|
|
#beat_led.direction = digitalio.Direction.OUTPUT |
|
|
#beat_led.value = True |
|
|
RED_LED = board.GP11 |
|
|
GREEN_LED = board.GP12 |
|
|
BLUE_LED = board.GP13 |
|
|
|
|
|
# Create a RGB LED object |
|
|
beat_led = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED, invert_pwm=True) |
|
|
beat_led.color = (0,0,0) |
|
|
|
|
|
###################### Helper Functions |
|
|
def placePixels(amount = 0, offset = 0, start_color = (255, 0, 0), step_color = (255, 255, 255)): |
|
|
# pixels.fill((0,0,0)) |
|
|
# pixels.show() |
|
|
# print("Placing Pixels: ", amount, offset) |
|
|
seq = [(0,0,0) for _ in range(num_pixels)] |
|
|
if amount == 0: |
|
|
return seq |
|
|
else: |
|
|
step_distance = num_pixels / amount |
|
|
for i in range(amount): |
|
|
if i == 0: |
|
|
seq[(math.floor(i * step_distance) + offset) % num_pixels] = start_color |
|
|
else: |
|
|
seq[(math.floor(i * step_distance) + offset) % num_pixels] = step_color |
|
|
return seq |
|
|
###################### Main Loop |
|
|
while True: |
|
|
|
|
|
position = encoder.position |
|
|
if last_position is None or position != last_position: |
|
|
if last_position is not None: |
|
|
if not button.value and not red_button.value: |
|
|
amo[active_sequence] = amo[active_sequence] - (last_position - position) |
|
|
if amo[active_sequence] > num_pixels: |
|
|
amo[active_sequence] = num_pixels |
|
|
elif amo[active_sequence] < 0: |
|
|
amo[active_sequence] = 0 |
|
|
elif button.value and not red_button.value: |
|
|
off[active_sequence] = off[active_sequence] - (last_position - position) |
|
|
elif not button.value and red_button.value: |
|
|
beats_per_minute -= (last_position - position) |
|
|
if beats_per_minute < 40: |
|
|
beats_per_minute = 40 |
|
|
elif beats_per_minute >= 240: |
|
|
beats_per_minute = 240 |
|
|
tick_time = ((60 / beats_per_minute) / steps_per_beat) * 1000000000 |
|
|
amount_small_circle(math.floor(translate(beats_per_minute, 40, 240, 0, 12))) |
|
|
last_position = position |
|
|
|
|
|
if not button.value and button_state is None: |
|
|
button_state = "pressed" |
|
|
if button.value and button_state == "pressed": |
|
|
print("Button pressed.") |
|
|
button_state = None |
|
|
|
|
|
if black_button.value and black_button_event is None: |
|
|
black_button_event = True |
|
|
if not black_button.value and not black_button_event: |
|
|
black_button_event = None |
|
|
|
|
|
if yellow_button.value and yellow_button_event is None: |
|
|
yellow_button_event = True |
|
|
if not yellow_button.value and not yellow_button_event: |
|
|
yellow_button_event = None |
|
|
|
|
|
if yellow_button_event: |
|
|
start_sequencer = not start_sequencer |
|
|
#time.sleep(0.001) |
|
|
yellow_button_event = False |
|
|
|
|
|
if (time.monotonic_ns() - tick_last) >= tick_time: |
|
|
# print("Beat") |
|
|
note_list = ["C2", "D2", "E2", "G2", "A2"] |
|
|
send_list = [] |
|
|
for s in range(len(sequence)): |
|
|
sequence[s] = placePixels(amo[s], off[s], beat_start_color[s], beat_step_color[s]) |
|
|
if (sequence[s][tick_counter] != (0,0,0)) and start_sequencer: |
|
|
beat_led.color = tick_color[s] |
|
|
send_list.append(NoteOn(note_list[s], 120)) |
|
|
# else: |
|
|
# beat_led.color = (0,0,0) |
|
|
if len(send_list) > 0: |
|
|
midi.send(send_list[0]) |
|
|
|
|
|
time.sleep(0.01) |
|
|
|
|
|
send_list = [] |
|
|
for s in range(len(sequence)): |
|
|
if (sequence[s][tick_counter] != (0,0,0)) and start_sequencer: |
|
|
send_list.append(NoteOff(note_list[s], 120)) |
|
|
#beat_led.color = (0, 0, 0) |
|
|
if len(send_list) > 0: |
|
|
midi.send(send_list[0]) |
|
|
|
|
|
if black_button_event and active_sequence < num_sequence-1: |
|
|
active_sequence += 1 |
|
|
black_button_event = False |
|
|
elif black_button_event and active_sequence == num_sequence-1: |
|
|
active_sequence = 0 |
|
|
black_button_event = False |
|
|
|
|
|
sequence[active_sequence][tick_counter] = tick_color[active_sequence] |
|
|
|
|
|
|
|
|
if tick_counter < num_pixels - 1 and start_sequencer: |
|
|
tick_counter += 1 |
|
|
elif start_sequencer: |
|
|
tick_counter = 0 |
|
|
tick_last = time.monotonic_ns() |
|
|
for i in range(num_pixels): |
|
|
pixels[i] = sequence[active_sequence][i] |
|
|
pixels.show() |
|
|
sequence = [] |
|
|
for i in range(num_sequence): |
|
|
sequence.append([(0,0,0) for _ in range(num_pixels)]) |
|
|
render_last = time.monotonic_ns() |
|
|
|
|
|
|