# optimiert durch ChatGPT 5.1 am 11.12.2025
from machine import Pin, PWM
from time import sleep
class Music:
# Frequenzen der Noten
freq = {
"C1": 33, "C#1": 35, "D1": 37, "D#1": 39, "E1": 41, "F1": 44, "F#1": 46, "G1": 49, "G#1": 52,
"A1": 55, "A#1": 58, "B1": 62, "C2": 65, "C#2": 69, "D2": 73, "D#2": 78, "E2": 82, "F2": 87,
"F#2": 93, "G2": 98, "G#2": 104, "A2": 110, "A#2": 117, "B2": 123, "C3": 131, "C#3": 139,
"D3": 147, "D#3": 156, "E3": 165, "F3": 175, "F#3": 185, "G3": 196, "G#3": 208, "A3": 220,
"A#3": 233, "B3": 247, "C4": 262, "C#4": 277, "D4": 294, "D#4": 311, "E4": 330, "F4": 349,
"F#4": 370, "G4": 392, "G#4": 415, "A4": 440, "A#4": 466, "B4": 494, "C5": 523, "C#5": 554,
"D5": 587, "D#5": 622, "E5": 659, "F5": 698, "F#5": 740, "G5": 784, "G#5": 831, "A5": 880,
"A#5": 932, "B5": 988, "C6": 1047, "C#6": 1109, "D6": 1175, "D#6": 1245, "E6": 1319,
"F6": 1397, "F#6": 1480, "G6": 1568, "G#6": 1661, "A6": 1760, "A#6": 1865, "B6": 1976,
"C7": 2093, "C#7": 2217, "D7": 2349, "D#7": 2489, "E7": 2637, "F7": 2794, "F#7": 2960,
"G7": 3136, "G#7": 3322, "A7": 3520, "A#7": 3729, "B7": 3951,
"P": 0 # Pause
}
def __init__(self, pin, bpm=60):
"""
pin = Pin(…) Objekt
bpm = Beats per minute (60 bedeutet 1/4 Note = 1 Sekunde)
"""
self.pwm = PWM(pin)
self.pwm.duty_u16(0)
self.velocity = bpm
def tone(self, note):
"""Spielt eine einzelne Note ('A4', 0.25)"""
name, duration = note
f = self.freq.get(name, 0)
if f == 0: # Pause
self.pwm.duty_u16(0)
else:
self.pwm.freq(f)
self.pwm.duty_u16(32768) # 50% Duty Cycle
sleep(duration * 60 / self.velocity)
self.noTone()
sleep(0.05)
def noTone(self):
"""Ton ausschalten"""
self.pwm.duty_u16(0)
def play(self, melody):
"""Spielt eine Liste von Noten ab"""
for n in melody:
self.tone(n)
self.noTone()
'''
Beipiel-Programm:
from machine import Pin
from music import Music
ls = Music(Pin(12), 60)
lied = [
("C4", 0.25), ("D4", 0.25), ("E4", 0.25),
("F4", 0.25), ("G4", 0.25), ("G4", 0.25), ("P", 0.25)
]
ls.play(lied)
'''
"""
Was sich verbessert hat:
1. PWM-Kompatibilität
alt: evtl. duty() Fehler
PWM.duty() ist veraltet auf neueren ESP32-MicroPython-Versionen. Viele ESP32-Firmwares benutzen jetzt duty_u16() statt duty().
(Zu erkennen an einer Fehlermeldung bekommst wie: AttributeError: 'PWM' object has no attribute 'duty')
neu: immer duty_u16()
2. Pausen
alt: Ton an/aus unzuverlässig
neu: klare Pause‐Erzeugung
3. API
alt: tone() nur einzeln
neu: play() für ganze Lieder
4. Stabilität
alt: manchmal Rauschen am Ende
neu: immer noTone()
"""
"""
ChatGPT schlägt auch eine Library für Zweiklänge vor:
Mehrstimmige Polyphonie über zwei PWM-Kanäle
Polyphonie bedeutet, dass mehrere Töne gleichzeitig gespielt werden (wie in einem Akkord auf dem Klavier).
Auf dem ESP32 kannst du mehrere PWM-Kanäle verwenden, also z. B. zwei Buzzer-Pins gleichzeitig ansteuern:
Kanal 1 → spielt C4
Kanal 2 → spielt E4
→ zusammen hört man C4+E4 als Akkord
Damit könntest du Akkorde, Harmonien oder komplexere Melodien erzeugen – nicht nur einzelne Töne nacheinander.
"""