rpi-pico-candle/music.py

130 lines
3.1 KiB
Python
Raw Normal View History

2022-11-28 22:49:02 +01:00
# SPDX-License-Identifier: MIT
#
# Little christmas candle
#
# Author: Nils Freydank <nils.freydank@datenschutz-ist-voll-doof.de>
# Year: 2022
# Copyright: MIT
import json
import machine
import time
pin_piezo = machine.Pin(12)
def _note_to_freq(note_name: str) -> int:
"""
Translate note names from strings into frequency values.
"""
freq: int = 0
# frequencies, see e.g.
# https://en.wikipedia.org/wiki/Piano_key_frequencies
note_names: dict = {
"c4": 262,
"cis4": 277,
"d4": 294,
"e4": 330,
"f4": 349,
"fis4": 370,
"g4": 392,
"a4": 440,
"b4": 466,
"h4": 494,
"c5": 523,
"cis5": 554,
"d5": 587,
"e5": 659,
"f5": 698,
"fis5": 740,
"g5": 784,
"a5": 880,
"b5": 923,
"h5": 988,
"c6": 1047,
}
try:
freq = note_names[note_name]
except KeyError:
freq = -1
print(f"exc in _note_to_freq() for {note_name}.")
return freq
def _len_to_second(len_name: str, len_scaling: float = 0.6) -> float:
time: float = 0.0
len_names = {
"_t": 0.125 * len_scaling, # thirty-second note or pause
"_s": 0.25 * len_scaling, # sixteenth note or pause
"_e": 0.5 * len_scaling, # eight note or pause
"_q": 1.0 * len_scaling, # quarter note or pause
"_h": 2.0 * len_scaling, # half note or pause
"_f": 4.0 * len_scaling, # whole note or pause
}
try:
for elem in len_name.split("+"):
time += len_names[elem.replace(" ", "")]
except KeyError:
time = 0.0
print(f"exc in _len_to_second() for {elem}.")
print("Do you have a typo there, e.g. 'a' + 'b' instead of 'a + b'?")
return time
def play_note(note_name: str, duration: str, loud: bool = False) -> int:
if loud:
duty_cycle: int = 16_000
else:
duty_cycle: int = 400
real_pwm_freq: int = 0
pwm_piezo = machine.PWM(pin_piezo)
pwm_piezo.freq(_note_to_freq(note_name))
real_pwm_freq = pwm_piezo.freq()
pwm_piezo.duty_u16(duty_cycle)
time.sleep(_len_to_second(duration))
pwm_piezo.duty_u16(0)
time.sleep(0.05)
return real_pwm_freq
def pause(duration: str) -> None:
time.sleep(_len_to_second(duration))
time.sleep(0.05)
def play_music(file_name: str = "o-tannenbaum.json") -> None:
data: dict = {}
try:
with open(file_name, "r") as f:
data = json.load(f)
try:
if data["metadata"]["format"] == "json-0.1.0":
for notes in data["music"]:
for note in notes.keys():
if note == "0":
pause(notes[note])
else:
play_note(note, notes[note])
elif data["metadata"]["format"] == "json-0.2.0":
pass
except:
print(f"play_oh_tannnebaum() failed to parse {data}.")
except FileNotFoundError:
print("Could not load the JSON file containing the song's details.")
# vim:fileencoding=utf-8:ts=4:syntax=python:expandtab