##
# \Buzzer_10_play_rttt.py
#
# RTTTL Player per Raspberry Pi Pico - Implementazione MicroPython
# Questo programma riproduce melodie in formato RTTTL (Ring Tone Text Transfer Language)
# su un buzzer collegato al Raspberry Pi Pico.
#
# https://wokwi.com/projects/426041520669602817
# https://github.com/filippo-bilardo/ROBOTICA/tree/main/Buzzer
#
# @author Filippo Bilardo
# @version 1.0 21/03/25 - Versione iniziale
import machine
import time
import math
# Definizione delle note e frequenze
NOTE_MAP = {
'c': 0, 'c#': 1, 'd': 2, 'd#': 3, 'e': 4, 'f': 5, 'f#': 6,
'g': 7, 'g#': 8, 'a': 9, 'a#': 10, 'b': 11, 'h': 11, 'p': -1
}
# Pin per il buzzer - modifica in base al tuo collegamento
buzzer_pin = machine.Pin(15) # GP15 come esempio
buzzer = machine.PWM(buzzer_pin)
buzzer.duty_u16(0) # Inizialmente spento
def play_tone(frequency, duration_ms):
"""Riproduce un tono alla frequenza specificata per la durata indicata."""
if frequency <= 0:
buzzer.duty_u16(0) # Pausa - nessun suono
time.sleep_ms(int(duration_ms)) # Converti a intero
else:
# Calcola il periodo e imposta la frequenza
buzzer.freq(int(frequency))
buzzer.duty_u16(32767) # 50% duty cycle
time.sleep_ms(int(duration_ms * 0.9)) # 90% della durata per separare le note
buzzer.duty_u16(0) # Spegni il buzzer
time.sleep_ms(int(duration_ms * 0.1)) # Pausa del 10%
def get_frequency(note, octave):
"""Calcola la frequenza di una nota in base all'ottava."""
if note == 'p': # Pausa
return 0
# Nota di base C4 = 261.63 Hz
# Ogni semitono è 2^(1/12) volte la frequenza precedente
base_c4 = 261.63
semitone_ratio = math.pow(2, 1/12)
# Calcola la distanza in semitoni da C4
note_index = NOTE_MAP[note.lower()]
octave_diff = octave - 4
semitones_from_c4 = note_index + (octave_diff * 12)
# Calcola la frequenza
return base_c4 * math.pow(semitone_ratio, semitones_from_c4)
def parse_rtttl(rtttl_string):
"""Analizza una stringa RTTTL e la converte in una sequenza di note."""
parts = rtttl_string.split(':')
if len(parts) != 3:
print("Formato RTTTL non valido!")
return None, None
name = parts[0].strip()
defaults = parts[1].strip().split(',')
notes = parts[2].strip().split(',')
# Impostazioni predefinite
default_duration = 4
default_octave = 6
default_bpm = 63
# Analizza le impostazioni predefinite
for setting in defaults:
if '=' not in setting:
continue
key, value = setting.split('=')
if key == 'd':
default_duration = int(value)
elif key == 'o':
default_octave = int(value)
elif key == 'b':
default_bpm = int(value)
# Calcola il tempo di base per una quarto (in millisecondi)
quarter_note_duration = int(60000 / default_bpm)
# Note parsate (nota, ottava, durata in millisecondi)
parsed_notes = []
# Analizza ogni nota
for note_str in notes:
note_str = note_str.strip()
if not note_str:
continue
# Durata
duration = default_duration
i = 0
while i < len(note_str) and note_str[i].isdigit():
duration_str = ''
while i < len(note_str) and note_str[i].isdigit():
duration_str += note_str[i]
i += 1
if duration_str:
duration = int(duration_str)
# Calcola la durata in millisecondi
duration_ms = quarter_note_duration * (4 / duration)
# Nota
if i < len(note_str):
note = note_str[i]
i += 1
# Diesis
if i < len(note_str) and note_str[i] == '#':
note += '#'
i += 1
# Ottava
octave = default_octave
if i < len(note_str) and note_str[i].isdigit():
octave = int(note_str[i])
i += 1
# Nota puntata
if i < len(note_str) and note_str[i] == '.':
duration_ms *= 1.5
i += 1
# Aggiungi la nota parsata
parsed_notes.append((note.lower(), octave, duration_ms))
return name, parsed_notes
def play_rtttl(rtttl_string):
"""Riproduce una melodia in formato RTTTL."""
name, notes = parse_rtttl(rtttl_string)
if not notes:
return
print(f"Riproduzione di '{name}'...")
for note, octave, duration_ms in notes:
frequency = get_frequency(note, octave)
play_tone(frequency, duration_ms)
# Assicurati che il buzzer sia spento alla fine
buzzer.duty_u16(0)
print("Riproduzione completata")
# Esempio di melodie RTTTL
star_wars = "StarWars:d=4,o=5,b=120:8f,8f,8f,2a#.,2f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8d#6,2c6"
mario = "Super Mario:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b,16p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b"
tetris = "Tetris:d=4,o=5,b=160:e6,8b,8c6,8d6,16e6,16d6,8c6,8b,a,8a,8c6,e6,8d6,8c6,b,8b,8c6,d6,e6,c6,a,2a,8p,d6,8f6,a6,8g6,8f6,e6,8e6,8c6,e6,8d6,8c6,b,8b,8c6,d6,e6,c6,a,a"
# Funzione principale
def main():
print("RTTTL Player per Raspberry Pi Pico")
print("Collegare il buzzer al pin GP15")
print("Avvio riproduzione...")
play_rtttl(mario)
time.sleep(1)
play_rtttl(star_wars)
time.sleep(1)
play_rtttl(tetris)
if __name__ == "__main__":
main()