Skip to content

Instantly share code, notes, and snippets.

@spotlesscoder
Forked from benongithub/picoSequencer.py
Created March 3, 2024 21:08
Show Gist options
  • Save spotlesscoder/781ee6c26ed86d3d1d81b248ee320619 to your computer and use it in GitHub Desktop.
Save spotlesscoder/781ee6c26ed86d3d1d81b248ee320619 to your computer and use it in GitHub Desktop.
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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment