kopia lustrzana https://github.com/pimoroni/pimoroni-pico
132 wiersze
3.3 KiB
Python
132 wiersze
3.3 KiB
Python
import time
|
|
import random
|
|
from stellar import StellarUnicorn, Channel
|
|
from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN, PEN_P8
|
|
|
|
"""
|
|
A gloriously terrible melody maker.
|
|
|
|
Use Vol + and Vol - to move up/down (note pitch)
|
|
|
|
Use Lux - and D to move left/right (note position)
|
|
|
|
Press A to set a note.
|
|
|
|
Press B to delete a note.
|
|
|
|
Use Lux + to play/pause.
|
|
"""
|
|
|
|
NOTE_DURATION = 125
|
|
|
|
su = StellarUnicorn()
|
|
su.set_brightness(0.5)
|
|
graphics = PicoGraphics(DISPLAY_STELLAR_UNICORN, pen_type=PEN_P8)
|
|
|
|
boopety_beepety = su.synth_channel(0)
|
|
boopety_beepety.configure(
|
|
waveforms=Channel.SQUARE | Channel.SINE,
|
|
attack=0.1,
|
|
decay=0.5,
|
|
sustain=0.0,
|
|
release=1.0,
|
|
volume=1.0
|
|
)
|
|
|
|
su.play_synth()
|
|
|
|
black = graphics.create_pen(0, 0, 0)
|
|
note = graphics.create_pen(255, 255, 255)
|
|
cursor_bg = graphics.create_pen(64, 0, 0)
|
|
cursor = graphics.create_pen(255, 0, 0)
|
|
playhead = graphics.create_pen(0, 128, 0)
|
|
|
|
cursor_position = [0, 0]
|
|
|
|
playhead_position = 0
|
|
|
|
width, height = graphics.get_bounds()
|
|
|
|
notes = [random.randint(0, height) for _ in range(width)]
|
|
|
|
last_note_advance = time.ticks_ms()
|
|
|
|
last_action = time.ticks_ms()
|
|
|
|
playing = True
|
|
|
|
|
|
def debounce(button, duration=100):
|
|
global last_action
|
|
if su.is_pressed(button) and time.ticks_ms() - last_action > duration:
|
|
last_action = time.ticks_ms()
|
|
return True
|
|
return False
|
|
|
|
|
|
def note_to_frequency(note_number):
|
|
return int((2 ** ((note_number - 69.0) / 12)) * 440)
|
|
|
|
|
|
while True:
|
|
if debounce(StellarUnicorn.SWITCH_D):
|
|
cursor_position[0] -= 1
|
|
cursor_position[0] %= width
|
|
|
|
if debounce(StellarUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
|
cursor_position[0] += 1
|
|
cursor_position[0] %= width
|
|
|
|
if debounce(StellarUnicorn.SWITCH_VOLUME_DOWN):
|
|
cursor_position[1] += 1
|
|
cursor_position[1] %= height
|
|
|
|
if debounce(StellarUnicorn.SWITCH_VOLUME_UP):
|
|
cursor_position[1] -= 1
|
|
cursor_position[1] %= height
|
|
|
|
if debounce(StellarUnicorn.SWITCH_BRIGHTNESS_UP, 500):
|
|
playing = not playing
|
|
if not playing:
|
|
boopety_beepety.trigger_release()
|
|
|
|
if su.is_pressed(StellarUnicorn.SWITCH_A):
|
|
notes[cursor_position[0]] = cursor_position[1]
|
|
|
|
if su.is_pressed(StellarUnicorn.SWITCH_B):
|
|
notes[cursor_position[0]] = None
|
|
|
|
if time.ticks_ms() - last_note_advance > NOTE_DURATION:
|
|
current_note = None
|
|
if playing:
|
|
playhead_position += 1
|
|
playhead_position %= width
|
|
current_note = notes[playhead_position]
|
|
if current_note is not None:
|
|
current_note = height - current_note # Bottom = Low, Top = High
|
|
current_note += 36 # Shift up the scale a couple of octaves
|
|
current_freq = note_to_frequency(current_note)
|
|
boopety_beepety.frequency(current_freq)
|
|
boopety_beepety.trigger_attack()
|
|
last_note_advance = time.ticks_ms()
|
|
|
|
graphics.set_pen(black)
|
|
graphics.clear()
|
|
|
|
graphics.set_pen(playhead)
|
|
graphics.line(playhead_position, 0, playhead_position, height)
|
|
|
|
graphics.set_pen(cursor_bg)
|
|
graphics.line(cursor_position[0], 0, cursor_position[0], height)
|
|
|
|
graphics.set_pen(note)
|
|
for x in range(width):
|
|
y = notes[x]
|
|
if y is not None:
|
|
graphics.pixel(x, y)
|
|
|
|
graphics.set_pen(cursor)
|
|
graphics.pixel(*cursor_position)
|
|
|
|
su.update(graphics)
|