Created
December 18, 2020 19:12
-
-
Save dlech/066cc9593eecf88d044963a0a374f65e to your computer and use it in GitHub Desktop.
background music
This file contains hidden or 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
from pybricks.hubs import InventorHub | |
from pybricks.pupdevices import Motor, ColorSensor, UltrasonicSensor | |
from pybricks.parameters import Port, Stop, Color, Button | |
from pybricks.tools import wait, StopWatch | |
JINGLE_BELLS = ( | |
["B3/4", "B3/4", "B3/2"] * 2 + ["B3/4", "D4/4", "G3/4.", "A3/8", "B3/2.", "R/4"] + | |
["C4/4", "C4/4", "C4/4.", "C4/8", "C4/4", "B3/4", "B3/4", "B3/8", "B3/8", | |
"D4/4", "D4/4", "C4/4", "A3/4", "G3/2.", "R/4"] | |
) | |
hub = InventorHub() | |
def play_note(note, duration): | |
# needs some padding so we don't get StopIteration when calling next(note) | |
note = iter(note + "\0") | |
# Note names can be A-G followed by optional # (sharp) or b (flat) or R for rest | |
c = next(note) | |
if c == 'C': | |
c = next(note) | |
if c == 'b': | |
raise ValueError("Cb is not allowed") | |
elif c == '#': | |
c = next(note) | |
freq = 17.32 | |
else: | |
freq = 16.35 | |
elif c == 'D': | |
c = next(note) | |
if c == 'b': | |
c = next(note) | |
freq = 17.32 | |
elif c == '#': | |
c = next(note) | |
freq = 19.45 | |
else: | |
freq = 18.35 | |
elif c == 'E': | |
c = next(note) | |
if c == 'b': | |
c = next(note) | |
freq = 19.45 | |
elif c == '#': | |
raise ValueError("E# is not allowed") | |
else: | |
freq = 20.60 | |
elif c == 'F': | |
c = next(note) | |
if c == 'b': | |
raise ValueError("Fb is not allowed") | |
elif c == '#': | |
c = next(note) | |
freq = 23.12 | |
else: | |
freq = 21.83 | |
elif c == 'G': | |
c = next(note) | |
if c == 'b': | |
c = next(note) | |
freq = 23.12 | |
elif c == '#': | |
c = next(note) | |
freq = 25.96 | |
else: | |
freq = 24.50 | |
elif c == 'A': | |
c = next(note) | |
if c == 'b': | |
c = next(note) | |
freq = 25.96 | |
elif c == '#': | |
c = next(note) | |
freq = 29.14 | |
else: | |
freq = 27.50 | |
elif c == 'B': | |
c = next(note) | |
if c == 'b': | |
c = next(note) | |
freq = 29.14 | |
elif c == '#': | |
raise ValueError("B# is not allowed") | |
else: | |
freq = 30.87 | |
elif c == 'R': | |
c = next(note) | |
freq = 0.0 | |
else: | |
raise ValueError("Missing note name A-G or R") | |
# Note name must be followed by the octave number | |
if freq: | |
octave = ord(c) - ord('0') | |
c = next(note) | |
if octave < 2 or octave > 8: | |
raise ValueError("Missing octave number 2-8") | |
freq *= 2 << (octave - 1) | |
# '/' delimiter is required between octave and fraction | |
if c != '/': | |
raise ValueError("Missing /") | |
c = next(note) | |
# The fractional size of the note, e.g. 4 = quarter note | |
fraction = ord(c) - ord('0') | |
c = next(note) | |
if fraction < 0 or fraction > 9: | |
raise ValueError("Missing fractional value 1, 2, 4, 8, etc.") | |
# optional second digit | |
fraction2 = ord(c) - ord('0') | |
if 0 <= fraction2 <= 9: | |
c = next(note) | |
fraction = fraction * 10 + fraction2 | |
duration /= fraction | |
# optional decorations | |
if c == '.': | |
c = next(note) | |
duration = 3 * duration / 2 | |
release = True | |
if c == '_': | |
c = next(note) | |
release = False | |
hub.speaker.beep(freq, -1) | |
if release: | |
full_duration = duration | |
duration = 7 * duration / 8 | |
timer = StopWatch() | |
while timer.time() < duration: | |
yield | |
if release: | |
hub.speaker.beep(0, -1) | |
while timer.time() < full_duration: | |
yield | |
def play_notes(notes, tempo=120): | |
duration = 4 * 60 * 1000 / tempo | |
try: | |
for n in notes: | |
yield from play_note(n, duration) | |
finally: | |
hub.speaker.beep(0, -1) | |
music = play_notes(JINGLE_BELLS, tempo=140) | |
while True: | |
try: | |
next(music) | |
except StopIteration: | |
pass | |
wait(10) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment