RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Discuss development of drivers for external hardware and components, such as LCD screens, sensors, motor drivers, etc.
Target audience: Users and developers of drivers.
Post Reply
User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by dhylands » Sun Jul 24, 2016 5:54 am

I've put together an RTTTL parser and a sample which drives a piezo speaker.

The RTTTL parser can be found here: https://github.com/dhylands/upy-rtttl
I put together a quick video (so you can hear it playing a tune): https://www.youtube.com/watch?v=TadV2AEvfww

The pyb_test.py file has the function which plays a single tone, and rttlt.py has the RTTTL parser.

User avatar
mcauser
Posts: 507
Joined: Mon Jun 15, 2015 8:03 am

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by mcauser » Thu May 31, 2018 12:01 am

Works great with my pyboard + Seeed Grove buzzer!
There's millions of RTTTL examples a short Google search away.

You can even play them online:
https://adamonsoon.github.io/rtttl-play/

I used this tool to help figure out the frequencies I wanted to play:
http://www.szynalski.com/tone-generator/

Trapsis
Posts: 2
Joined: Fri Jan 11, 2019 10:15 pm

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by Trapsis » Tue Feb 19, 2019 12:30 pm

Very cool! Just what I'm looking for. I'm trying to adapt your code to work on an ESP32 board using the machine.PWM library. I'm still debugging it but there is not much that needed to change. It doesn't get through a whole song before failing. Here is the code if you are curious:

from rtttl import RTTTL
import songs
import time
from machine import Pin, PWM

speaker_pin = 14 # Speaker is connected to this DIGITAL pin

# Initialize input/output pins
tone = PWM(Pin(speaker_pin, Pin.OUT), freq=0, duty=512)

def play_tone(freq, msec):
#print('freq = {:6.1f} msec = {:6.1f}'.format(freq, msec))
if freq > 0:
tone = PWM(Pin(speaker_pin, Pin.OUT), freq=int(freq), duty=512)
time.sleep(msec*0.001) # Play for a number of msec
tone.deinit() # Stop playing
time.sleep(0.05) # Delay 50 ms between notes

tune = RTTTL(songs.find('Super Mario - Main Theme'))

for freq, msec in tune.notes():
play_tone(freq, msec)

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by dhylands » Tue Feb 19, 2019 5:01 pm

You probably don't want this line:

Code: Select all

tone = PWM(Pin(speaker_pin, Pin.OUT), freq=int(freq), duty=512)
inside the play_tone function.

You should initialize the PWM object once (outside the function) and only change the frequency inside the play_tone function.

Trapsis
Posts: 2
Joined: Fri Jan 11, 2019 10:15 pm

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by Trapsis » Thu Feb 21, 2019 2:41 pm

Thanks for the advice. This works better and will get through the tune ok, but the timing seems off. I think it is the rests (pauses) that are not working well (sorry, code block not formatted. still noob here I guess :) )

Code: Select all

from rtttl import RTTTL
import songs
import time
from machine import Pin, PWM

speaker_pin   = 14  # Speaker is connected to this DIGITAL pin

# Initialize input/output pins
tone = PWM(Pin(speaker_pin, Pin.OUT), freq=0, duty=0)

def play_tone(freq, msec):
    print('freq = {:6.1f} msec = {:6.1f}'.format(freq, msec))
    if freq > 0:
        tone.duty(10)
        tone.freq(int(freq))
	time.sleep(msec*0.001)  # Play for a number of msec
    tone.duty(0)            # Stop playing
    time.sleep(0.01)        # Delay 50 ms between notes

tune = RTTTL(songs.find('Super Mario - Main Theme'))

for freq, msec in tune.notes():
    play_tone(freq, msec)

tone.deinit() 

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by dhylands » Thu Feb 21, 2019 3:19 pm

You have the time.sleep(msec*0.001) inside the if. Try unindenting that line.

User avatar
scruss
Posts: 360
Joined: Sat Aug 12, 2017 2:27 pm
Location: Toronto, Canada
Contact:

Re: RTTTL - Ring Tone Text Transfer Language driving a Piezo Speaker

Post by scruss » Mon Feb 22, 2021 8:29 pm

I've added an example for running on the Raspberry Pi Pico, and entered a pull request. It's slightly different from all of the other variants.

Code: Select all

# Raspberry Pi Pico RTTTL example
# scruss - 2021-02: sorry, not sorry ...

from rtttl import RTTTL
from time import sleep_ms
from machine import Pin, PWM

# nicked from https://gist.github.com/mhungerford/0af269ee46c0d44a813c
NvrGonna = 'NvrGonna:d=4,o=5,b=200:8g,8a,8c6,8a,e6,8p,e6,8p,d6.,p,8p,8g,8a,8c6,8a,d6,8p,d6,8p,c6,8b,a.,8g,8a,8c6,8a,2c6,d6,b,a,g.,8p,g,2d6,2c6.,p,8g,8a,8c6,8a,e6,8p,e6,8p,d6.,p,8p,8g,8a,8c6,8a,2g6,b,c6.,8b,a,8g,8a,8c6,8a,2c6,d6,b,a,g.,8p,g,2d6,2c6.'

# pin 26 - GP20; just the right distance from GND at pin 23
#  to use one of those PC beepers with the 4-pin headers
pwm = PWM(Pin(20))


def play_tone(freq, msec):
    # print('freq = {:6.1f} msec = {:6.1f}'.format(freq, msec))
    if freq > 0:
        pwm.freq(int(freq))       # Set frequency
        pwm.duty_u16(32767)       # 50% duty cycle
    sleep_ms(int(0.9 * msec))     # Play for a number of msec
    pwm.duty_u16(0)               # Stop playing for gap between notes
    sleep_ms(int(0.1 * msec))     # Pause for a number of msec


tune = RTTTL(NvrGonna)
for freq, msec in tune.notes():
    play_tone(freq, msec)

Post Reply