-
-
Save spotlesscoder/ab9f134ed1b8b54895c42bd3c1601603 to your computer and use it in GitHub Desktop.
Code for the Raspberry Pico Sequencer as it can be seen here: https://www.reddit.com/r/synthdiy/comments/nd14d4/diy_circular_sequencer_made_with_raspberry_pico
This file contains 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 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