Last active
January 2, 2025 14:32
-
-
Save haveyouwantto/8014511cb6adea77973e4235204bb85d to your computer and use it in GitHub Desktop.
ESP32 PWM
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 time import sleep | |
from machine import Pin, PWM | |
import struct | |
# Function to calculate the frequency of a musical note based on its MIDI note number | |
def get_freq(note): | |
return int(440 * 2 ** ((note - 69) / 12.0)) | |
# Lists for note offsets and PWM duty values | |
offset = [0, -24, 0, 0, 0, -12, 12, 24, 36, 0, 0, 0, 0, 0, 0, 0] | |
duty = [24576, 32768, 0, 0, 0, 24576, 32768, 32768, 32768, 8192, 8192, 32768, 16384, 32768, 16384, 32768] | |
# Class for managing sound on multiple channels | |
class SoundManager: | |
def __init__(self, *pins): | |
self.channels = [] | |
self.size = len(pins) | |
for pin in pins: | |
pwm = PWM(Pin(pin)) | |
pwm.freq(48000) | |
self.channels.append(pwm) | |
self.active = 0 | |
def add(self, freq, inst): | |
if self.active < self.size: | |
self.channels[self.active].duty_u16(duty[inst]) | |
self.channels[self.active].freq(freq) | |
self.active += 1 | |
def clear(self): | |
self.active = 0 | |
def stop(self): | |
for p in self.channels: | |
p.freq(48000) | |
self.active = 0 | |
# Initialize the SoundManager with specified pins | |
snd = SoundManager(4, 5, 19, 22) | |
# Open and read the music file in binary mode | |
f = open('music/牛仔很忙.mcs', 'rb') | |
# Read the magic bytes, version, delay, and length from the file | |
magic = f.read(4) | |
version, delay, length = struct.unpack("<hfi", f.read(10)) | |
print(version, delay, length) | |
# Clear any existing sounds | |
snd.clear() | |
print(1) | |
# Function to pause the sound for a specified time | |
def pause(time): | |
sleep(time * 0.05 * delay) | |
snd.stop() | |
# Function to play a note with a given frequency and instrument | |
def play(freq, inst): | |
snd.add(freq, inst) | |
try: | |
while True: | |
for i in range(length): | |
# Read timing, instrument, and note data from the file | |
timing, inst, note = struct.unpack("<hbb", f.read(4)) | |
print(i, timing, inst, note) | |
if inst in (2, 3, 4): # Check if the instrument is for percussion | |
if timing != 0: | |
pause(timing) | |
continue | |
if version == 0: | |
play(get_freq(note + offset[inst]), inst) | |
if timing != 0: | |
pause(timing) | |
elif version == 1: | |
if timing != 0: | |
pause(timing) | |
play(get_freq(note + offset[inst]), inst) | |
snd.stop() | |
sleep(1) | |
f.seek(14) | |
except KeyboardInterrupt: | |
snd.stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment