# mario_intro_rp2040.py
# MicroPython for RP2040 (Raspberry Pi Pico)
# Plays a Mario-like intro melody via PWM on a buzzer/speaker.
from machine import Pin, PWM
import time
# --- User settings ---
BUZZER_PIN = 22 # change to the GPIO you wired the buzzer to
VOLUME = 30000 # 0..65535 (u16 duty). Lower = quieter
TEMPO = 150 # BPM (beats per minute)
# ----------------------
# Frequency table (Hz) for common notes (rounded)
NOTES = {
'C4': 261.63, 'C#4': 277.18, 'D4': 293.66, 'D#4': 311.13, 'E4': 329.63,
'F4': 349.23, 'F#4': 369.99, 'G4': 392.00, 'G#4': 415.30, 'A4': 440.00,
'A#4': 466.16, 'B4': 493.88,
'C5': 523.25, 'C#5': 554.37, 'D5': 587.33, 'D#5': 622.25, 'E5': 659.26,
'F5': 698.46, 'F#5': 739.99, 'G5': 783.99, 'G#5': 830.61, 'A5': 880.00,
'A#5': 932.33, 'B5': 987.77
}
# Helper: play one note (freq in Hz) for ms milliseconds
class Buzzer:
def __init__(self, pin_num, volume_u16=30000):
self.pwm = PWM(Pin(pin_num))
self.pwm.duty_u16(0)
self.volume = max(0, min(65535, int(volume_u16)))
def play_freq(self, freq, duration_ms):
if freq <= 0:
time.sleep_ms(int(duration_ms))
return
# set PWM frequency and duty
# PWM.freq expects int, duty_u16 expects 0..65535
self.pwm.freq(int(freq))
self.pwm.duty_u16(self.volume)
time.sleep_ms(int(duration_ms))
# short gap between notes
self.pwm.duty_u16(0)
def silent(self):
self.pwm.duty_u16(0)
def deinit(self):
self.pwm.deinit()
# Mario-like intro melody (note, beats)
# Beat unit: quarter-note = 1 beat. Use fractional beats (0.5 = 8th note)
MELODY = [
('E5', 0.5), ('E5', 0.5), ('', 0.25), ('E5', 0.5), ('', 0.25),
('C5', 0.5), ('E5', 0.5), ('G5', 1.0), ('', 0.5),
('G4', 1.0), ('', 0.5),
# second phrase (shortened for intro)
('C5', 1.0), ('', 0.25), ('G4', 0.75),
('E4', 1.0), ('A4', 0.5), ('B4', 0.5),
('A#4', 0.5), ('A4', 0.5),
('G5', 1.0), ('E5', 0.5), ('C5', 0.5),
('D5', 0.5), ('B4', 0.75), ('', 0.25)
]
def play_melody(buzzer, melody, tempo_bpm):
# quarter note duration in ms
beat_ms = 60000 / tempo_bpm
for note, beats in melody:
dur = beat_ms * beats # ms
# small staccato: play 90% of note, then short silence
play_ms = dur * 0.90
silence_ms = dur - play_ms
if note == '' or note is None:
# rest
time.sleep_ms(int(dur))
else:
freq = NOTES.get(note, 0)
if freq <= 0:
time.sleep_ms(int(dur))
else:
buzzer.play_freq(freq, int(play_ms))
if silence_ms > 0:
time.sleep_ms(int(silence_ms))
# Main
if __name__ == '__main__':
buz = Buzzer(BUZZER_PIN, volume_u16=VOLUME)
try:
# play twice like the recognizable intro loop
for _ in range(2):
play_melody(buz, MELODY, TEMPO)
time.sleep_ms(300) # small pause between repeats
finally:
buz.deinit()