Ring Tone Text Transfer Language (RTTTL) was developed by Nokia in the 1980’s as a format and mechanism to manage ringtones on cell phones. As Nokia was leader brand at the time, this method was quickly adopted by many other manufacturers and became the de-facto standard for ringtones.
As cell phone hardware became more capable, the use of RTTTL has diminished in favour of more advanced sound production – today most ringtones are simply ordinary sound files. RTTTL files, however, are still useful in may applications.
Why would we bother with monophonic RTTL melodies when more sophisticated devices are now available?
When dealing with embedded controllers (like Arduino) there are usually very finite resources to achieve a task, so the simplicity of implementing monophonic RTTTL melodies or sounds as a background task is a useful feature.
RTTTL melodies are also very compact, as they simply encode a ‘score’ that will be interpreted by the player. The melody is encoded as legible ASCII characters that can be very easily modified or replaced. This simplicity and portability makes it easy to adapt the sound output to disparate sound generation hardware.
Additionally, there are libraries of literally tens of thousands of RTTTL files on the internet (see here for a good starting point), covering short tunes to sound effects. And if that is not enough, composing or converting a musical score to RTTTL is a straightforward process, which is why it was developed in the first instance.
RTTTL notation is similar to the Music Macro Language found in BASIC implementations present on many early microcomputers.
An RTTTL melody is a string of characters that divided into three sections (Title or melody name, defaults, melody data or notes) separated using a colon (‘:’). An example of RTTTL is given below:
1. Title section
The melody title can be no more than 10 characters. In the example above this is “Looney”.
2. Defaults section
The defaults section is a set of values separated by commas, where each value contains a key and a value separated by an equal (‘=’) character describing global defaults for this melody. In practice the defaults are the limited to the three listed in the table below. If any are omitted there is an explicit standard default for the missing values, also given in the table below.
|d||Note duration (fraction of full note, see below)||4|
|o||Octave or scale||6|
|b||Beat or Tempo (beats per minute)||63|
The duration parameter is specified as a fraction of a full note duration, which is in turn defined by the beats per minute. Valid durations are identified as the divisor value of the full note – 1 (full note), 2, 4, 8, 16 and 32 (thirty second of full note).
The RTTTL specification allows octaves starting from the A below middle C and going up four octaves. These octaves are numbered from 4 (note A is 220 Hz) to 7 (1760 Hz). This restriction seems to have roots in the limitations of the early sound production hardware – small speakers give higher pitch. Today there is no real need to limit the octaves range but it persists.
BPM determines how much time each note or pause can take, and is the number of quarter notes in a minute. The BPM value can be one of
25, 28, 31, 35, 40, 45, 50, 56, 63, 70, 80, 90, 100, 112, 125, 140,
160, 180, 200, 225, 250, 285, 320, 355, 400, 450, 500, 565, 635, 715,
800 and 900.
3. Notes section
The last section of the string contains the song data as a sequence of note specifications separated by a comma. A note is encoded by:
Special-duration represents dotted rhythm patterns, formed by appending a period (‘.’) character to the end of a duration-note-octave tuple. This increases the duration of the note to 1.5 times its normal duration. Many RTTTL strings swap the special-duration and scale fields (ie, the scale value comes after the dot notation).
When the optional values duration and/or scale are omitted, the values given in the default section of the RTTTL string are used. The scale parameter is unused if a rest or pause is specified.
The notes in an RTTTL string are the standard notes in an octave – C, C#, D, D#, E, F, F#, G, G#, A, A#, B. Additionally P is used to denote a pause, and H is used as an equivalent for B.
Although not part of the original specification, some RTTTL strings also contain an extension for ‘flat’ notes which have defined equivalents – B_ or H_ (A#), C_ (B), D_ (C#), E_ (D#), F_ (E), G_ (F#), A_ (G#).
A more formal specification for the RTTL string is given by:
<RTTTL> := <title> ":" [<control-section>] ":" <tone-commands> <title> := <string:10> <control-section> := <def-note-duration> "," <def-note-scale> "," <def-beats> <def-duration> := "d=" <duration> <def-scale> := "o=" <scale> <def-beats> := "b=" <beats-per-minute> ; if not specified, defaults are ; duration=4, scale=6, beats-per-minute=63 <tone-commands> := <note> ["," <tone-commands>] <note> := [<duration>] <note> [<scale>] [<special-duration>] <duration> := "1"|"2"|"4"|"8"|"16"|"32" <scale> := "5"|"6"|"7"|"8" <beats-per-minute> := "5"|"28"|"31"|"35"|"40"|"45"|"50"|"56"|"63"| "70"|"80"|"90"|"100"|"112"|"125"|"140"|"160"| "180"|"200"|"225"|"250"|"285"|"20"|"355"|"400"| "450"|"500"|"565"|"635"|"715"|"800"|"900" <note> := "P"|"C"|"C#"|"D"|"D#"|"E"|"F"|"F#"|"G"|"G#"|"A"|"A#"|"B"|"H" <special-duration> := "."
The RTTTL parser class
The class discussed here is the MD_RTTTL Parser Arduino library.
The library is designed to fulfill 3 specific use cases:
- Library fully controls the playback of RTTTL tunes.
- The application controls the playback of RTTTL tunes.
- The application parses the RTTTL data for information without playback.
A note on sound output
To keep the parser library generic, sound output must be implemented in the application, as the type of hardware used will dictate how the sound is produced.
The parser will translate the information from the RTTTL string into parameters that the application can use:
- octave – generally in the range required by the RTTTL specification, but no checking is done in the parser to enforce this.
- note identifier – the notes are numbered according to the ISO standard numbering (C=0, C#=1, …, B=11) and can be used directly with the MD_MusicTable library to obtain note frequency or midi note numbers. The RTTTL class will also translate the non-standard flat notes into the correct equivalent. Pause values are encoded as note -1 and need to be explicitly checked.
- duration – the playing tempo and type of note, including dot notation, is converted into the number of milliseconds for the note or pause.
Library managed playback
The RTTLParser_Cback example demonstrates this use of the library.
In this mode the application provides the library with a callback that implements sound production. The library will manage duration timing for pauses (ie, the application is not aware of these) and will provide the callback with note on and note off events for the application to process.
The simplified flow for the application is:
- setCallback() is used to register the callback function (can be done in setup()).
- setTune() is used initialize the library for the specified RTTTL string.
- run() is invoked every time through main program loop. This will run a Finite State Machine that manages the sequencing and timing of notes, and invokes the callback when required.
- run() returns true when the end of the RTTTL string has been reached.
Application managed playback
The RTTLParser_Manual example demonstrates this use of the library.
In this mode the application has complete control over how the RTTTL file is processed.
A simplified flow for the application is:
- setTune() is used initialize the library for the specified RTTTL string.
- nextNote() is used to retrieve the next note in the sequence. In the case of a playable note, the application invokes the sound generation hardware.
- The application implements the logic required for the note or pause timing before processing the next note.
- nextNote() returns true when the end of the RTTTL string is reached. Alternatively, the isEoln() method can be used to test for end of line being reached.
Parsing without playback
Parsing without playback is identical to an application managed playback without ‘playing’ the notes. The entire string can be scanned very quickly when the note durations and pauses are ignored. Once the string has been parsed, it needs to be reset using setTune().
Parsing an RTTTL string is useful to gather information about the string, such as what octaves are being used, the range of notes, etc. These can then be used to modify subsequent playback to suit a particular sound output device (for example, shifting the octave range) .
RTTTL files have been around a long time but they still have a place in the world of embedded systems. Standardising the file parsing into a flexible class allows the main user application to use these as an easy ‘service’ for sound output with minimal effort.