Copyright (c) 2005 Javier Martinez. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

Here is a funny project, a RingTone player. The main purpose is to read the songs stored in a serial eeprom and play them with the help of a piezo-speaker. Useful to to put it inside a Christmas box to delight us with hundreds of short songs.
A RingTone it's a musical score developed by Nokia, it's called NokRing tones or RTTTL (RingTone Text Transfer Language) tones. A song it's written in this way:
Simpsons:d=4,o=5,b=160:32p,c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g
The RTTTL format specifications can be found in the web, a plain text of this specs can be found here (local copy). In order to clarify concepts I'll try to explain quickly the RTTTL format. The song name it's anything before the first “:” character. The next section after first “:” and before the second “:” it's the control field; in this field it's defined the song defaults:
“d=4” - Default note duration. A “whole
note”
have a 1/1 duration (4 beats), and a “quater note”
have a ¼ duration (1 beat). In RTTTL syntax the “whole
note” have a value “1” and the “quater note” have a value
“4”. In above Simpsons song, unless specified, default
note duration will be “4” (a quarter note).

“o=5” - Default octave. An octave in music (as same in electronics), it's an interval between a frequency and another that have half or double frequency. RTTTL can handle octaves 4, 5, 6, and 7. In above Simpsons song, unless specified, default octave is “5” (A = 880 Hz).
Scientific Pitch Notation, ISO 16:1975 standard
|
Natural |
C |
|
D |
|
E |
F |
|
G |
|
A |
|
B |
|
Sharp |
|
C# |
|
D# |
|
|
F# |
|
G# |
|
A# |
|
|
Italian |
Do |
|
Re |
|
Mi |
Fa |
|
Sol |
|
La |
|
Si |
|
Octave 4 |
261,6 |
277,2 |
293,7 |
311,1 |
329,6 |
349,2 |
370,0 |
392,0 |
415,3 |
440,0 |
466,2 |
493.9 |
|
Octave 5 |
523.3 |
554.4 |
587.3 |
622.3 |
659.3 |
698.5 |
740 |
784 |
830.6 |
880 |
932.3 |
987.8 |
|
Octave 6 |
1047 |
1109 |
1175 |
1245 |
1319 |
1397 |
1480 |
1568 |
1661 |
1760 |
1865 |
1976 |
|
Octave 7 |
2093 |
2217 |
2349 |
2489 |
2637 |
2794 |
2960 |
3136 |
3322 |
3520 |
3729 |
3951 |
“b=160” - Default Tempo. In music, Tempo means “beats per minute”, and a “whole note” have 4 beats duration. In above Simpsons song the Tempo of the song is 160 (= 2.666 beats per second) and the “whole note” duration is 1.5 seconds. The available Tempo values in this project are: 25, 28, 31, 35, 40, 45, 50, 56, 63, 70, 80, 90, 100, 112, 125, 140, 160, 180, 200, 225, 250, 285, 320 and 355.
Anything after the second “:” utill the end of the song are the song notes. In our Simpsons song (d=4,o=5,b=160) a single note “... , g , ...” will be played with some defaults values, as is was written like “... , 4g5 , ...”. The letter “p” is a special note with no sound, and the special character “.” increase the note duration x1.5.
Here I'll try to write some words about how the note's sounds are generated by the PIC16F628. Basically, the frequency note it's generated by PWM module over pin_b3, the note duration it's controlled by TMR1 interrupts, and waveform envelope it's controlled by a couple of resistors.

Frequency note
On each note the PIC will configure the PWM module to make the note with the desired frequency. Based on some constants (fosc, TMR2 prescaler, etc.) the wave period it's managed by PR2 register and the Duty Cycle by the CCPR1 register.

PR2 = Int ( fosc / ( 4 * TMR2presc * fnote ) )
|
Note |
Frequency (Hz) |
PR2 (O4) |
TMR2 (ms) |
|
C |
261,6 |
238 |
3,824 |
|
C# |
277,2 |
225 |
3,616 |
|
D |
293,7 |
212 |
3,408 |
|
D# |
311,1 |
200 |
3,216 |
|
E |
329,6 |
189 |
3,040 |
|
F |
349,2 |
178 |
2,864 |
|
F# |
370,0 |
168 |
2,704 |
|
G |
392,0 |
159 |
2,560 |
|
G# |
415,3 |
150 |
2,416 |
|
A |
440,0 |
142 |
2,288 |
|
A# |
466,2 |
134 |
2,160 |
|
B |
493,9 |
126 |
2,032 |
As you can see, only notes of Octave 4 are in this table. Octaves 5, 6 and 7 double the frequency from previous octave, so PR2 value will be the half value in each step. As a first aproach, CCPR1 value will be half the PR2 value in order to have a duty cycle of 50%.
Note duration
This is done by TMR1 module, using interrupts to get the desired note duration control as close to real time. To get a fine management of note duration, I've splitted each “beat” into 32 “tics”, this will help us to manage notes with short duration (like 1/32 ones). TMR1 interrupt is programmed to loop each “tic”, here's a couple of tables with the neccesary init values:
|
Note duration |
Beats |
Tics |
|---|---|---|
|
1 / 1 |
4 / 1 |
128 |
|
1 / 2 |
4 / 2 |
64 |
|
1 / 4 |
4 / 4 |
32 |
|
1 / 8 |
4 / 8 |
16 |
|
1 / 16 |
4 / 16 |
8 |
|
1 / 32 |
4 / 32 |
4 |
Init_TMR1 = int ( 65536 - ( 60 * fosc / ( bpm * tics * 4 * TMR1presc ) ) )
|
bpm |
Init_TMR1 |
Init_TMR1_H |
Init_TMR1_L |
TMR1 (ms) |
|
25 |
28036 |
109 |
132 |
75,000 |
|
28 |
32053 |
125 |
53 |
66,966 |
|
31 |
35294 |
137 |
222 |
60,484 |
|
35 |
38750 |
151 |
94 |
53,572 |
|
40 |
42098 |
164 |
114 |
46,876 |
|
45 |
44702 |
174 |
158 |
41,668 |
|
50 |
46786 |
182 |
194 |
37,500 |
|
56 |
48794 |
190 |
154 |
33,484 |
|
63 |
50655 |
197 |
223 |
29,762 |
|
70 |
52143 |
203 |
175 |
26,786 |
|
80 |
53817 |
210 |
57 |
23,438 |
|
90 |
55119 |
215 |
79 |
20,834 |
|
100 |
56161 |
219 |
97 |
18,750 |
|
112 |
57165 |
223 |
77 |
16,742 |
|
125 |
58036 |
226 |
180 |
15,000 |
|
140 |
58839 |
229 |
215 |
13,394 |
|
160 |
59676 |
233 |
28 |
11,720 |
|
180 |
60327 |
235 |
167 |
10,418 |
|
200 |
60848 |
237 |
176 |
9,376 |
|
225 |
61369 |
239 |
185 |
8,334 |
|
250 |
61786 |
241 |
90 |
7,500 |
|
280 |
62187 |
242 |
235 |
6,698 |
|
310 |
62511 |
244 |
47 |
6,050 |
|
355 |
62895 |
245 |
175 |
5,282 |
Waveform envelope
Aplying all I've expained above we can play songs, perhaps not the best but it works. Certainly it songs like whistles. In a first aproach a couple of resistors will give “some” amplitude control. The basic idea is to implement de amplitude decay of a piano note; that is, once a piano key is pressed the sound goes down in a few seconds.


The decay of the note it's fixed by the “fail & success” method, currently values are: 150 msecs for 66% amplitude and 300 msecs for 33% amplitude. The values (in tics) to be computed in TMR1 interrupt are:
|
bpm |
66% |
33% |
|
25 |
2 |
4 |
|
28 |
2 |
4 |
|
31 |
2 |
4 |
|
35 |
2 |
5 |
|
40 |
3 |
6 |
|
45 |
3 |
7 |
|
50 |
4 |
8 |
|
56 |
4 |
8 |
|
63 |
5 |
10 |
|
70 |
5 |
11 |
|
80 |
6 |
12 |
|
90 |
7 |
14 |
|
100 |
8 |
16 |
|
112 |
8 |
17 |
|
125 |
10 |
20 |
|
140 |
11 |
22 |
|
160 |
12 |
25 |
|
180 |
14 |
28 |
|
200 |
15 |
31 |
|
225 |
17 |
35 |
|
250 |
20 |
40 |
|
280 |
22 |
44 |
|
310 |
24 |
49 |
|
355 |
28 |
56 |
A final modification will set the Duty Cycle at 12.5%, this will add more armonics to wave and will sound better. Here're some audio examples in MP3 format:
Score:
Bach_Badinerie:d=16,o=6,b=125:8b,d7,b,8f#,b,f#,8d,f#,d,4b5,f#5,b5,d,b5,c#,b5,c#,
a#5,c#,e,c#,8d,8b5,8b,d7,b,8f#,b,f#,8d,f#,d,4b5,8d,8d,8d,8d,8b,8d,32d,32c#,b5,32d,32c#,
8c#,8f#,8f#,8f#,8f#,8d7,8f#,32f#,32f,32f#,32f,8f,c#,f#,a,f#,g#,f#,g#,f#,f,g#,b,g#,a,
g#,a,g#,f#,a,f#,f,f#,b,f#,f,f#,c#7,f#,f,f#,d7,f#,f,f#,d7,c#7,b,c#7,a,g#,f#,8a,8g#,4f#,1p
PWM output, DC 50%, No envelope: bach_badinerie_1.mp3
PWM output, DC 50%, Envelope control: bach_badinerie_2.mp3
PWM output, DC 12.5%, Envelope control: bach_badinerie_3.mp3
Note: These sound files were recorded through a
microphone close to the piezo-speaker, my apologies about the
sorround noise.
Once you've collected some songs to store them in the EEPROM, you must build a text file with all of them. You can use the already supplied file to see how to do it. Anyway here's some tips to build it succesfully:
Test the songs previously with a online web player, some of them are not worth to save into EEPROM.
Take off all spaces, many songs found in the web have them.
Ensure that notes are delimited by commas “,”. Don't place a comma “,” as a last character of a song.
Ensure that Tempo is below or equal to 355 in all songs.
Put a song in a hole line, any character below 0x20 (CR, LF, Bell, TAB, etc.) will be decoded as end of song.
Insert a space “p” (no sound) at the end of each song. This will give you a gap between songs. I suggest you to insert at least “4p” for Tempo <= 60, “2p” for Tempo > 60 and Tempo < 240 and “1p” for Tempo >= 240. See the supplied file, it have them.
At the end of your text file, place a “/”. Don't put it in a new line, just as the last character of last song; this will loop the EEPROM endlessly.
In order to store songs in EEPROM you'll need an external serial adapter circuit (like a MAX232). The circuit have a 5 pin header to do this. Close the jumper before anything else, configure your serial teminal as “300,8,n,1” (yes, 300 bauds) and power up the circuit. You'll see a short message “RTP” in the terminal window. Now send a text file with all your songs, the size of the file must be limited to the size of the EEPROM.
When the text file is already transfered, power off the circuit and open the jumper. That's all!
Note: other way to program the EEPROM is using an external programmer. Use a socket to take off the EEPROM from the circuit.
A Christmas “box” for the RTTTL player:

Circuit ready to put it in:

Where to find RingTones:
Online RTTTL player (you'll need a MIDI player in your system):
... to build your own PCB circuit are here.
Source code written in JAL to program the PIC are here.
HEX files.
A sample sound text file to program the EEPROM, take it here.
The source code of this project is GNU GPL
This file, graphics and photographs are GNU FDL
The Eagle circuit was done using the freeware version.
(c)2005 Javier Martínez.