Jump to content
43oh

RTTTL (Ring Tone Text Transfer Language) Player


Recommended Posts

Plays ringtones in the RTTTL format. That is a text string for simple monophonic music.

 

The parser is very simple and does not attempt strict compliance with the specification. It should properly play strings that are written to spec.

 

The output is a sine wave constructed using 48 kHz PWM on P1.6 that should be low pass filtered by a simple R/C filter.

 

Code was tested on G2553 - not sure if this will fit in the 2K chips - it should work if it fits.

 

 

#include 
#include 

//
// RTTTL spec: http://www.mobilefish.com/tutorials/rtttl/rtttl_quickguide_specification.html
//

static const long int phase_limit = 48048 * 1000;   // Phase accumulator limit, sample rate * 1/resolution
static volatile long int pi = 0;                    // Phase increment (frequency in millihertz)
static volatile unsigned note_timer = 0;            // Note timer, decrements 48048 times per second


static int isnote(char c)                           // Get note index, or 128 for pause
{                                                   //
   //                               A  B   C  D  E  F  G  H(
   static const int note_map[8] = { 9, 11, 0, 2, 4, 5, 7, 11 }; // MIDI note value
   if(c >= 'a' && c <= 'h') return note_map[c - 'a']; // Lower case note
   if(c >= 'A' && c <= 'H') return note_map[c - 'A']; // Upper case note
   if(c == 'p' || c == 'P') return 128;            // Pause
   return -1;                                      // Invalid, return -1
}

static void play_note(unsigned n, unsigned d)       // Play note
{                                                   // n: MIDI note value
                                                   // d: duration in units of 1/48048 second
                                                   //
   static const unsigned note_spacing = 480;       // 10 ms between notes
   static const unsigned long midi_notes[12] = {   // MIDI upper 12 notes
        6644875L,                                  // 116 G# 9
        7040000L,                                  // 117 A  9
        7458620L,                                  // 118 A# 9
        7902133L,                                  // 119 B  9
        8372018L,                                  // 120 C  10
        8869844L,                                  // 121 C# 10
        9397273L,                                  // 122 D  10
        9956063L,                                  // 123 D# 10
       10548082L,                                  // 124 E  10
       11175303L,                                  // 125 F  10
       11839822L,                                  // 126 F# 10
       12543854L                                   // 127 G  10
   };                                              //
   long f;                                         //
   if(n > 127) {                                   // Invalid note value is pause
       f = 0;                                      // Frequency = 0
   } else {                                        //
       unsigned o = 10; n += 4;                    // Init octave, adjust note
       while(n >= 12) n -= 12, --o;                // Normalize note, adjust octave
       f = midi_notes[n];                          // Get frequency
       while(o) f >>= 1, --o;                      // Adjust frequency for octave
   }                                               //
   while(note_timer);                              // Wait for current note to finish
                                                   //
   pi = 0;                                         // Silence between notes
   note_timer = note_spacing;                      //
   while(note_timer);                              //
                                                   //
   if(d > note_spacing) d -= note_spacing;         // Adjust note duration for note spacing
   note_timer = d;                                 // Setup note time
   pi = f - phase_limit;                           // Play note
}

void play(const char *s)                            // Play RTTTL string
{                                                   //
   unsigned state = 0;                             // Initial state
   char c, d;                                      // Char from string, default specifier
   unsigned bpm = 63;                              // Beats (quarter notes) per minute
   unsigned default_duration = 4;                  // Default note duration (fraction of a whole note)
   unsigned default_octave = 5;                    // Default octave
   long unsigned dot;                              // Numerator for note clock count calculation, adjusted for dot notation
   unsigned duration = 0;                          // Note duration
   int note;                                       // Note index 0 to 11
   int octave;                                     // Octave 0 to 9
                                                   //
   do {                                            //
       c = *s++;                                   // Get a char from RTTTL string
       if(c > 0 && c <= 32) continue;              // Ingore whitespace and control chars
       switch(state) {                             //
           case 0:                                 // - Skip name
               if(c == ':') ++state;               // Toss chars until ':'
               break;                              //
           case 1:                                 // - Parse defaults
   state1:                                         //
               if(c == ':') {                      // End of default section, begin parsing notes
                   state = 4;                      //
               } else if(isalpha(c)) {             // Default designator - allow any alpha
                   d = c;                          // Save it
                   state = 2;                      // Verify assignment character
               } else {                            //
                   state = 1;                      // Invalid char, stay in this state
               }                                   //
               break;                              //
           case 2:                                 // - Default assignment char, must be '='
               if(c == '=') {                      //
                   note = 0;                       // Init default
                   ++state;                        // Parse default value
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 3:                                 // - Parse and assign default value
               if(isdigit(c)) {                    // Update default
                   note = note * 10 + (c - '0');   //
               } else if(c == ',' || c == ':') {   // End of default, assign to variable
                   switch(d) {                     //
                       case 'b':                   // Default BPM
                       case 'B':                   //
                           bpm = note;             //
                           break;                  //
                       case 'o':                   // Default octave
                       case 'O':                   //
                           default_octave = note;  //
                           break;                  //
                       case 'd':                   // Default note duration
                       case 'D':                   //
                           default_duration = note;//
                           break;                  //
                   }                               //
                   state = (c == ':') ? 4 : 1;     // Get next default or begin parsing notes
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 4:                                 // - Parse note
               dot = 48048L * 60 * 4;              // Setup defaults for this note
               duration = default_duration;        //
               octave = default_octave;            //
               note = 0;                           //
               if(isdigit(c)) {                    // May begin with duration
                   duration = c - '0';             // Init duration
                   ++state;                        // May be more than one digit, continue in next state
               } else if((note = isnote(c)) >= 0) {// May begin with note
                   state = 6;                      // Got note, parse modifiers and octave
               }                                   //
               break;                              //
           case 5:                                 // - Parse duration
               if(isdigit(c)) {                    // Numeric digit, update duration
                   duration = duration * 10 + (c -'0');
               } else if((note = isnote(c)) >= 0) {// Got note, parse modifiers and octave
                   ++state;                        //
               } else {                            // Invlid char, start over 
                   state = 4;                      //
               }                                   //
               break;                              //
           case 6:                                 // - Parse modifiers and octave
               if(c == ',' || c == 0) {            // End of note, play it
                   play_note((octave + 1) * 12 + note, dot / (duration * bpm));
                   state = 4;                      // Next note
               } else if(c == '#') {               // Sharp, increment note value
                   ++note;                         //
               } else if(c == 'b') {               // Flat, decrement note value
                   --note;                         //
               } else if(c == '.') {               // Dotted note, extend length by 50%
                   dot += (dot >> 1);              //
               } else if(isdigit(c)) {             // Octave, 0 to 9 allowed, should be 4 to 7
                   octave = c - '0';               //
               }                                   //
               break;                              //
                                                   //
       }                                           //
   } while(c);                                     // End of string
   while(note_timer);                              // Wait for last note to finish
   pi = 0;                                         // Silence
}

static const signed char sine[734] = {              // 8 bit signed sine wave samples
   0,      1,      2,      3,      4,      5,      7,      8,  
   9,      10,     11,     12,     13,     14,     15,     16, 
   17,     18,     20,     21,     22,     23,     24,     25, 
   26,     27,     28,     29,     30,     31,     32,     33, 
   34,     35,     36,     38,     39,     40,     41,     42, 
   43,     44,     45,     46,     47,     48,     49,     50, 
   51,     52,     53,     54,     55,     56,     57,     58, 
   59,     60,     61,     62,     62,     63,     64,     65, 
   66,     67,     68,     69,     70,     71,     72,     73, 
   73,     74,     75,     76,     77,     78,     79,     80, 
   80,     81,     82,     83,     84,     85,     85,     86, 
   87,     88,     89,     89,     90,     91,     92,     92, 
   93,     94,     95,     95,     96,     97,     97,     98, 
   99,     99,     100,    101,    101,    102,    103,    103,    
   104,    105,    105,    106,    106,    107,    108,    108,    
   109,    109,    110,    110,    111,    111,    112,    113,    
   113,    114,    114,    114,    115,    115,    116,    116,    
   117,    117,    118,    118,    118,    119,    119,    120,    
   120,    120,    121,    121,    121,    122,    122,    122,    
   122,    123,    123,    123,    124,    124,    124,    124,    
   124,    125,    125,    125,    125,    125,    126,    126,    
   126,    126,    126,    126,    126,    127,    127,    127,    
   127,    127,    127,    127,    127,    127,    127,    127,    
   127,    127,    127,    127,    127,    127,    127,    127,    
   127,    127,    126,    126,    126,    126,    126,    126,    
   126,    126,    125,    125,    125,    125,    125,    124,    
   124,    124,    124,    123,    123,    123,    123,    122,    
   122,    122,    121,    121,    121,    120,    120,    120,    
   119,    119,    119,    118,    118,    117,    117,    117,    
   116,    116,    115,    115,    114,    114,    113,    113,    
   112,    112,    111,    111,    110,    110,    109,    109,    
   108,    107,    107,    106,    106,    105,    104,    104,    
   103,    102,    102,    101,    101,    100,    99,     99, 
   98,     97,     96,     96,     95,     94,     94,     93, 
   92,     91,     91,     90,     89,     88,     87,     87, 
   86,     85,     84,     83,     83,     82,     81,     80, 
   79,     78,     77,     77,     76,     75,     74,     73, 
   72,     71,     70,     70,     69,     68,     67,     66, 
   65,     64,     63,     62,     61,     60,     59,     58, 
   57,     56,     55,     54,     53,     52,     51,     50, 
   49,     48,     47,     46,     45,     44,     43,     42, 
   41,     40,     39,     38,     37,     36,     35,     34, 
   33,     32,     31,     30,     29,     28,     27,     25, 
   24,     23,     22,     21,     20,     19,     18,     17, 
   16,     15,     14,     13,     11,     10,     9,      8,  
   7,      6,      5,      4,      3,      2,      1,      0,  
   -2,     -3,     -4,     -5,     -6,     -7,     -8,     -9, 
   -10,    -11,    -12,    -13,    -15,    -16,    -17,    -18,    
   -19,    -20,    -21,    -22,    -23,    -24,    -25,    -26,    
   -27,    -29,    -30,    -31,    -32,    -33,    -34,    -35,    
   -36,    -37,    -38,    -39,    -40,    -41,    -42,    -43,    
   -44,    -45,    -46,    -47,    -48,    -49,    -50,    -51,    
   -52,    -53,    -54,    -55,    -56,    -57,    -58,    -59,    
   -60,    -61,    -62,    -63,    -64,    -65,    -66,    -67,    
   -68,    -68,    -69,    -70,    -71,    -72,    -73,    -74,    
   -75,    -76,    -76,    -77,    -78,    -79,    -80,    -81,    
   -82,    -82,    -83,    -84,    -85,    -86,    -86,    -87,    
   -88,    -89,    -90,    -90,    -91,    -92,    -93,    -93,    
   -94,    -95,    -96,    -96,    -97,    -98,    -98,    -99,    
   -100,   -100,   -101,   -102,   -102,   -103,   -104,   -104,   
   -105,   -106,   -106,   -107,   -107,   -108,   -108,   -109,   
   -110,   -110,   -111,   -111,   -112,   -112,   -113,   -113,   
   -114,   -114,   -115,   -115,   -116,   -116,   -116,   -117,   
   -117,   -118,   -118,   -119,   -119,   -119,   -120,   -120,   
   -120,   -121,   -121,   -121,   -122,   -122,   -122,   -123,   
   -123,   -123,   -123,   -124,   -124,   -124,   -124,   -125,   
   -125,   -125,   -125,   -125,   -126,   -126,   -126,   -126,   
   -126,   -126,   -126,   -126,   -127,   -127,   -127,   -127,   
   -127,   -127,   -127,   -127,   -127,   -127,   -127,   -127,   
   -127,   -127,   -127,   -127,   -127,   -127,   -127,   -127,   
   -127,   -126,   -126,   -126,   -126,   -126,   -126,   -126,   
   -125,   -125,   -125,   -125,   -125,   -125,   -124,   -124,   
   -124,   -124,   -123,   -123,   -123,   -123,   -122,   -122,   
   -122,   -121,   -121,   -121,   -120,   -120,   -120,   -119,   
   -119,   -118,   -118,   -118,   -117,   -117,   -116,   -116,   
   -115,   -115,   -115,   -114,   -114,   -113,   -113,   -112,   
   -112,   -111,   -111,   -110,   -109,   -109,   -108,   -108,   
   -107,   -107,   -106,   -105,   -105,   -104,   -103,   -103,   
   -102,   -102,   -101,   -100,   -100,   -99,    -98,    -98,    
   -97,    -96,    -95,    -95,    -94,    -93,    -92,    -92,    
   -91,    -90,    -89,    -89,    -88,    -87,    -86,    -85,    
   -85,    -84,    -83,    -82,    -81,    -81,    -80,    -79,    
   -78,    -77,    -76,    -75,    -75,    -74,    -73,    -72,    
   -71,    -70,    -69,    -68,    -67,    -66,    -65,    -64,    
   -64,    -63,    -62,    -61,    -60,    -59,    -58,    -57,    
   -56,    -55,    -54,    -53,    -52,    -51,    -50,    -49,    
   -48,    -47,    -46,    -45,    -44,    -43,    -42,    -41,    
   -40,    -39,    -38,    -37,    -36,    -35,    -34,    -32,    
   -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,    
   -23,    -22,    -21,    -20,    -19,    -18,    -16,    -15,    
   -14,    -13,    -12,    -11,    -10,    -9,     -8,     -7, 
   -6,     -5,     -3,     -2,     -1,     0   
};

#pragma vector = TIMER0_A1_VECTOR                   // Timer A0 Overflow interrupt
__interrupt void timer0_a1_isr(void)                //
{                                                   //
   static long int pa = 0;                         // Phase accumulator
   static unsigned sample = 200;                   // PWM sample
                                                   //
   TACCR1 = sample;                                // Output previous PWM sample
                                                   //
   volatile unsigned z = TAIV;                     // Clear interrupt flag
                                                   //
   sample = 200 - sine[pa >> 16];                  // Get next PWM value
                                                   //
   if((pa += pi) < 0) pa += phase_limit;           // Update phase accumulator
                                                   //
   if(note_timer) --note_timer;                    // Decrement note timer
}                                                   //

static const char * const tunes[] = {
   "StWars:d=4,o=5,b=180: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,p,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",
   "axelf:d=4,o=5,b=160:f#,8a.,8f#,16f#,8a#,8f#,8e,f#,8c.6,8f#,16f#,8d6,8c#6,8a,8f#,8c#6,8f#6,16f#,8e,16e,8c#,8g#,f#.",
   	"Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c",

"Mission:d=4,o=6,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16a#,16g,2d,32p,16a#,16g,2c#,32p,16a#,16g,2c,16p,16a#5,16c",
   "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5",
   "Greensleaves:d=4,o=5,b=140:g,2a#,c6,d.6,8d#6,d6,2c6,a,f.,8g,a,2a#,g,g.,8f,g,2a,f,2d,g,2a#,c6,d.6,8e6,d6,2c6,a,f.,8g,a,a#.,8a,g,f#.,8e,f#,2g",
   0
};

void main(void)
{
   WDTCTL = WDTPW | WDTHOLD;                       // Disable watchdog reset
   DCOCTL = 0;                                     // Run at 16 MHz
   BCSCTL1 = CALBC1_16MHZ;                         //
   DCOCTL = CALDCO_16MHZ;                          //
                                                   //
   P1DIR = BIT6;                                   // Enable PWM output on P1.6
   P1SEL = BIT6;                                   //
                                                   //                                                  
   TACTL = TASSEL_2 | MC_1 | TAIE;                 // Timer A config: SMCLK, count up, ovrflow int enabled
   TACCR0 = 332;                                   // Setup Timer A period for 48.048 kHz
   TACCR1  = 200;                                  // Setup Timer A compare to "DAC" zero value
   TACCTL1 = OUTMOD_7;                             // Setup Timer A reset/set output mode
                                                   //
   _EINT();                                        // Enable interrupts
                                                   //
   const char * const *t;                          //
   for(; for(t = tunes; *t; ++t) {               // Iterate all ring tones
       play(*t);                                   // Play it
       note_timer = 48048;                         // Wait a second before next
       while(note_timer);                          //
   }                                               //
}

Link to post
Share on other sites

The PWM frequency is 48 kHz, that is essentially the sample rate. So the cutoff frequency should be less than half that.

The highest frequency the code can generate is aprox 12.5 kHz, so the cutoff frequency should be above that.

The output current of the MSP430 IO pin should be less than 5 mA, so the resistor should be no less than 820 ohms.

The output impedance should not be too high, so the resistor should be 10k or less.

 

So cutoff frequency of 15 to 20 kHz and resistance of 820 ohm to 10 k.

Fc = 1 / (2 * Pi * R * C)

 

Some common values that will work well...

820 12n ~16.2 kHz

1k0 10n ~15.9 kHz

2k2 4n7 ~15.4 kHz

3k3 3n3 ~14.6 kHz

4k7 2n2 ~15.4 kHz

6k8 1n5 ~15.6 kHz

8k2 1n2 ~16.2 kHz

10k 1n0 ~15.9 kHz

Link to post
Share on other sites

Updated with 256 step envelope

 

 

#include 
#include 

//
// RTTTL spec: http://www.mobilefish.com/tutorials/rtttl/rtttl_quickguide_specification.html
//

static const long int phase_limit = 48048 * 1000;   // Phase accumulator limit, sample rate * 1/resolution
static volatile long int pi = 0;                    // Phase increment (frequency in millihertz)
static volatile unsigned note_env = 0;              // Note envelope, increments 48048 times per second
static volatile unsigned long note_timer = 0;       // Note timer, decrements 48048 times per second


static int isnote(char c)                           // Get note index, or 128 for pause
{                                                   //
   //                               A  B   C  D  E  F  G  H(
   static const int note_map[8] = { 9, 11, 0, 2, 4, 5, 7, 11 }; // MIDI note value
   if(c >= 'a' && c <= 'h') return note_map[c - 'a']; // Lower case note
   if(c >= 'A' && c <= 'H') return note_map[c - 'A']; // Upper case note
   if(c == 'p' || c == 'P') return 128;            // Pause
   return -1;                                      // Invalid, return -1
}

static void play_note(unsigned n, unsigned long d)  // Play note
{                                                   // n: MIDI note value
                                                   // d: duration in units of 1/48048 second
                                                   //
   //static const unsigned note_spacing = 480;     // 10 ms between notes
   static const unsigned note_spacing = 0;
   static const unsigned long midi_notes[12] = {   // MIDI upper 12 notes
        6644875L,                                  // 116 G# 9
        7040000L,                                  // 117 A  9
        7458620L,                                  // 118 A# 9
        7902133L,                                  // 119 B  9
        8372018L,                                  // 120 C  10
        8869844L,                                  // 121 C# 10
        9397273L,                                  // 122 D  10
        9956063L,                                  // 123 D# 10
       10548082L,                                  // 124 E  10
       11175303L,                                  // 125 F  10
       11839822L,                                  // 126 F# 10
       12543854L                                   // 127 G  10
   };                                              //
   long f;                                         //
   if(n > 127) {                                   // Invalid note value is pause
       f = 0;                                      // Frequency = 0
   } else {                                        //
       unsigned o = 10; n += 4;                    // Init octave, adjust note
       while(n >= 12) n -= 12, --o;                // Normalize note, adjust octave
       f = midi_notes[n];                          // Get frequency
       while(o) f >>= 1, --o;                      // Adjust frequency for octave
   }                                               //
   while(note_timer);                              // Wait for current note to finish
                                                   //
   if(note_spacing) {                              // Silence between notes                                                    
       pi = 0;                                     //
       note_timer = note_spacing;                  //
       while(note_timer);                          //
   }                                               //
                                                   //
   if(d > note_spacing) d -= note_spacing;         // Adjust note duration for note spacing
   note_timer = d;                                 // Setup note time
   if(f) note_env = 0;                             // Setup envelope
   pi = f - phase_limit;                           // Play note
}

void play(const char *s)                            // Play RTTTL string
{                                                   //
   unsigned state = 0;                             // Initial state
   char c, d;                                      // Char from string, default specifier
   unsigned bpm = 63;                              // Beats (quarter notes) per minute
   unsigned default_duration = 4;                  // Default note duration (fraction of a whole note)
   unsigned default_octave = 5;                    // Default octave
   long unsigned dot;                              // Numerator for note clock count calculation, adjusted for dot notation
   unsigned duration = 0;                          // Note duration
   int note;                                       // Note index 0 to 11
   int octave;                                     // Octave 0 to 9
                                                   //
   do {                                            //
       c = *s++;                                   // Get a char from RTTTL string
       if(c > 0 && c <= 32) continue;              // Ingore whitespace and control chars
       switch(state) {                             //
           case 0:                                 // - Skip name
               if(c == ':') ++state;               // Toss chars until ':'
               break;                              //
           case 1:                                 // - Parse defaults
   state1:                                         //
               if(c == ':') {                      // End of default section, begin parsing notes
                   state = 4;                      //
               } else if(isalpha(c)) {             // Default designator - allow any alpha
                   d = c;                          // Save it
                   state = 2;                      // Verify assignment character
               } else {                            //
                   state = 1;                      // Invalid char, stay in this state
               }                                   //
               break;                              //
           case 2:                                 // - Default assignment char, must be '='
               if(c == '=') {                      //
                   note = 0;                       // Init default
                   ++state;                        // Parse default value
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 3:                                 // - Parse and assign default value
               if(isdigit(c)) {                    // Update default
                   note = note * 10 + (c - '0');   //
               } else if(c == ',' || c == ':') {   // End of default, assign to variable
                   switch(d) {                     //
                       case 'b':                   // Default BPM
                       case 'B':                   //
                           bpm = note;             //
                           break;                  //
                       case 'o':                   // Default octave
                       case 'O':                   //
                           default_octave = note;  //
                           break;                  //
                       case 'd':                   // Default note duration
                       case 'D':                   //
                           default_duration = note;//
                           break;                  //
                   }                               //
                   state = (c == ':') ? 4 : 1;     // Get next default or begin parsing notes
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 4:                                 // - Parse note
               dot = 48048L * 60 * 4;              // Setup defaults for this note
               duration = default_duration;        //
               octave = default_octave;            //
               note = 0;                           //
               if(isdigit(c)) {                    // May begin with duration
                   duration = c - '0';             // Init duration
                   ++state;                        // May be more than one digit, continue in next state
               } else if((note = isnote(c)) >= 0) {// May begin with note
                   state = 6;                      // Got note, parse modifiers and octave
               }                                   //
               break;                              //
           case 5:                                 // - Parse duration
               if(isdigit(c)) {                    // Numeric digit, update duration
                   duration = duration * 10 + (c -'0');
               } else if((note = isnote(c)) >= 0) {// Got note, parse modifiers and octave
                   ++state;                        //
               } else {                            // Invlid char, start over 
                   state = 4;                      //
               }                                   //
               break;                              //
           case 6:                                 // - Parse modifiers and octave
               if(c == ',' || c == 0) {            // End of note, play it
                   play_note((octave + 1) * 12 + note, dot / (duration * bpm));
                   state = 4;                      // Next note
               } else if(c == '#') {               // Sharp, increment note value
                   ++note;                         //
               } else if(c == 'b') {               // Flat, decrement note value
                   --note;                         //
               } else if(c == '.') {               // Dotted note, extend length by 50%
                   dot += (dot >> 1);              //
               } else if(isdigit(c)) {             // Octave, 0 to 9 allowed, should be 4 to 7
                   octave = c - '0';               //
               }                                   //
               break;                              //
                                                   //
       }                                           //
   } while(c);                                     // End of string
   while(note_timer);                              // Wait for last note to finish
   pi = 0;                                         // Silence
}

static const signed char sine[734] = {              // 8 bit signed sine wave samples
   0,      1,      2,      3,      4,      5,      7,      8,  
   9,      10,     11,     12,     13,     14,     15,     16, 
   17,     18,     20,     21,     22,     23,     24,     25, 
   26,     27,     28,     29,     30,     31,     32,     33, 
   34,     35,     36,     38,     39,     40,     41,     42, 
   43,     44,     45,     46,     47,     48,     49,     50, 
   51,     52,     53,     54,     55,     56,     57,     58, 
   59,     60,     61,     62,     62,     63,     64,     65, 
   66,     67,     68,     69,     70,     71,     72,     73, 
   73,     74,     75,     76,     77,     78,     79,     80, 
   80,     81,     82,     83,     84,     85,     85,     86, 
   87,     88,     89,     89,     90,     91,     92,     92, 
   93,     94,     95,     95,     96,     97,     97,     98, 
   99,     99,     100,    101,    101,    102,    103,    103,    
   104,    105,    105,    106,    106,    107,    108,    108,    
   109,    109,    110,    110,    111,    111,    112,    113,    
   113,    114,    114,    114,    115,    115,    116,    116,    
   117,    117,    118,    118,    118,    119,    119,    120,    
   120,    120,    121,    121,    121,    122,    122,    122,    
   122,    123,    123,    123,    124,    124,    124,    124,    
   124,    125,    125,    125,    125,    125,    126,    126,    
   126,    126,    126,    126,    126,    127,    127,    127,    
   127,    127,    127,    127,    127,    127,    127,    127,    
   127,    127,    127,    127,    127,    127,    127,    127,    
   127,    127,    126,    126,    126,    126,    126,    126,    
   126,    126,    125,    125,    125,    125,    125,    124,    
   124,    124,    124,    123,    123,    123,    123,    122,    
   122,    122,    121,    121,    121,    120,    120,    120,    
   119,    119,    119,    118,    118,    117,    117,    117,    
   116,    116,    115,    115,    114,    114,    113,    113,    
   112,    112,    111,    111,    110,    110,    109,    109,    
   108,    107,    107,    106,    106,    105,    104,    104,    
   103,    102,    102,    101,    101,    100,    99,     99, 
   98,     97,     96,     96,     95,     94,     94,     93, 
   92,     91,     91,     90,     89,     88,     87,     87, 
   86,     85,     84,     83,     83,     82,     81,     80, 
   79,     78,     77,     77,     76,     75,     74,     73, 
   72,     71,     70,     70,     69,     68,     67,     66, 
   65,     64,     63,     62,     61,     60,     59,     58, 
   57,     56,     55,     54,     53,     52,     51,     50, 
   49,     48,     47,     46,     45,     44,     43,     42, 
   41,     40,     39,     38,     37,     36,     35,     34, 
   33,     32,     31,     30,     29,     28,     27,     25, 
   24,     23,     22,     21,     20,     19,     18,     17, 
   16,     15,     14,     13,     11,     10,     9,      8,  
   7,      6,      5,      4,      3,      2,      1,      0,  
   -2,     -3,     -4,     -5,     -6,     -7,     -8,     -9, 
   -10,    -11,    -12,    -13,    -15,    -16,    -17,    -18,    
   -19,    -20,    -21,    -22,    -23,    -24,    -25,    -26,    
   -27,    -29,    -30,    -31,    -32,    -33,    -34,    -35,    
   -36,    -37,    -38,    -39,    -40,    -41,    -42,    -43,    
   -44,    -45,    -46,    -47,    -48,    -49,    -50,    -51,    
   -52,    -53,    -54,    -55,    -56,    -57,    -58,    -59,    
   -60,    -61,    -62,    -63,    -64,    -65,    -66,    -67,    
   -68,    -68,    -69,    -70,    -71,    -72,    -73,    -74,    
   -75,    -76,    -76,    -77,    -78,    -79,    -80,    -81,    
   -82,    -82,    -83,    -84,    -85,    -86,    -86,    -87,    
   -88,    -89,    -90,    -90,    -91,    -92,    -93,    -93,    
   -94,    -95,    -96,    -96,    -97,    -98,    -98,    -99,    
   -100,   -100,   -101,   -102,   -102,   -103,   -104,   -104,   
   -105,   -106,   -106,   -107,   -107,   -108,   -108,   -109,   
   -110,   -110,   -111,   -111,   -112,   -112,   -113,   -113,   
   -114,   -114,   -115,   -115,   -116,   -116,   -116,   -117,   
   -117,   -118,   -118,   -119,   -119,   -119,   -120,   -120,   
   -120,   -121,   -121,   -121,   -122,   -122,   -122,   -123,   
   -123,   -123,   -123,   -124,   -124,   -124,   -124,   -125,   
   -125,   -125,   -125,   -125,   -126,   -126,   -126,   -126,   
   -126,   -126,   -126,   -126,   -127,   -127,   -127,   -127,   
   -127,   -127,   -127,   -127,   -127,   -127,   -127,   -127,   
   -127,   -127,   -127,   -127,   -127,   -127,   -127,   -127,   
   -127,   -126,   -126,   -126,   -126,   -126,   -126,   -126,   
   -125,   -125,   -125,   -125,   -125,   -125,   -124,   -124,   
   -124,   -124,   -123,   -123,   -123,   -123,   -122,   -122,   
   -122,   -121,   -121,   -121,   -120,   -120,   -120,   -119,   
   -119,   -118,   -118,   -118,   -117,   -117,   -116,   -116,   
   -115,   -115,   -115,   -114,   -114,   -113,   -113,   -112,   
   -112,   -111,   -111,   -110,   -109,   -109,   -108,   -108,   
   -107,   -107,   -106,   -105,   -105,   -104,   -103,   -103,   
   -102,   -102,   -101,   -100,   -100,   -99,    -98,    -98,    
   -97,    -96,    -95,    -95,    -94,    -93,    -92,    -92,    
   -91,    -90,    -89,    -89,    -88,    -87,    -86,    -85,    
   -85,    -84,    -83,    -82,    -81,    -81,    -80,    -79,    
   -78,    -77,    -76,    -75,    -75,    -74,    -73,    -72,    
   -71,    -70,    -69,    -68,    -67,    -66,    -65,    -64,    
   -64,    -63,    -62,    -61,    -60,    -59,    -58,    -57,    
   -56,    -55,    -54,    -53,    -52,    -51,    -50,    -49,    
   -48,    -47,    -46,    -45,    -44,    -43,    -42,    -41,    
   -40,    -39,    -38,    -37,    -36,    -35,    -34,    -32,    
   -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,    
   -23,    -22,    -21,    -20,    -19,    -18,    -16,    -15,    
   -14,    -13,    -12,    -11,    -10,    -9,     -8,     -7, 
   -6,     -5,     -3,     -2,     -1,     0   
};

const unsigned char envelope[256] = {       // 5.33 ms per entry
#if 0   // Linear
   255,    254,    253,    252,    251,    250,    249,    248,
   247,    246,    245,    244,    243,    242,    241,    240,
   239,    238,    237,    236,    235,    234,    233,    232,
   231,    230,    229,    228,    227,    226,    225,    224,
   223,    222,    221,    220,    219,    218,    217,    216,
   215,    214,    213,    212,    211,    210,    209,    208,
   207,    206,    205,    204,    203,    202,    201,    200,
   199,    198,    197,    196,    195,    194,    193,    192,
   191,    190,    189,    188,    187,    186,    185,    184,
   183,    182,    181,    180,    179,    178,    177,    176,
   175,    174,    173,    172,    171,    170,    169,    168,
   167,    166,    165,    164,    163,    162,    161,    160,
   159,    158,    157,    156,    155,    154,    153,    152,
   151,    150,    149,    148,    147,    146,    145,    144,
   143,    142,    141,    140,    139,    138,    137,    136,
   135,    134,    133,    132,    131,    130,    129,    128,
   127,    126,    125,    124,    123,    122,    121,    120,
   119,    118,    117,    116,    115,    114,    113,    112,
   111,    110,    109,    108,    107,    106,    105,    104,
   103,    102,    101,    100,     99,     98,     97,     96,
    95,     94,     93,     92,     91,     90,     89,     88,
    87,     86,     85,     84,     83,     82,     81,     80,
    79,     78,     77,     76,     75,     74,     73,     72,
    71,     70,     69,     68,     67,     66,     65,     64,
    63,     62,     61,     60,     59,     58,     57,     56,
    55,     54,     53,     52,     51,     50,     49,     48,
    47,     46,     45,     44,     43,     42,     41,     40,
    39,     38,     37,     36,     35,     34,     33,     32,
    31,     30,     29,     28,     27,     26,     25,     24,
    23,     22,     21,     20,     19,     18,     17,     16,
    15,     14,     13,     12,     11,     10,      9,      8,
     7,      6,      5,      4,      3,      2,      1,      0
#endif
#if 0   // Log 0.99
   255,    252,    249,    247,    244,    242,    240,    237,
   235,    232,    230,    228,    226,    223,    221,    219,
   217,    214,    212,    210,    208,    206,    204,    202,
   200,    198,    196,    194,    192,    190,    188,    186,
   184,    183,    181,    179,    177,    175,    174,    172,
   170,    168,    167,    165,    163,    162,    160,    158,
   157,    155,    154,    152,    151,    149,    148,    146,
   145,    143,    142,    140,    139,    138,    136,    135,
   134,    132,    131,    130,    128,    127,    126,    124,
   123,    122,    121,    119,    118,    117,    116,    115,
   114,    112,    111,    110,    109,    108,    107,    106,
   105,    104,    103,    102,    101,    100,     99,     98,
    97,     96,     95,     94,     93,     92,     91,     90,
    89,     88,     87,     86,     86,     85,     84,     83,
    82,     81,     81,     80,     79,     78,     77,     77,
    76,     75,     74,     74,     73,     72,     71,     71,
    70,     69,     69,     68,     67,     66,     66,     65,
    65,     64,     63,     63,     62,     61,     61,     60,
    59,     59,     58,     58,     57,     57,     56,     55,
    55,     54,     54,     53,     53,     52,     52,     51,
    51,     50,     50,     49,     49,     48,     48,     47,
    47,     46,     46,     45,     45,     44,     44,     43,
    43,     43,     42,     42,     41,     41,     40,     40,
    40,     39,     39,     38,     38,     38,     37,     37,
    37,     36,     36,     35,     35,     35,     34,     34,
    34,     33,     33,     33,     32,     32,     32,     31,
    31,     31,     30,     30,     30,     29,     29,     29,
    29,     28,     28,     28,     27,     27,     27,     27,
    26,     26,     26,     26,     25,     25,     25,     25,
    24,     24,     24,     24,     23,     23,     23,     23,
    22,     22,     22,     22,     21,     21,     21,     21,
    21,     20,     20,     20,     20,     20,     10,      0
#endif
#if 1   // Log 0.98
   255,    249,    244,    240,    235,    230,    225,    221,
   216,    212,    208,    204,    200,    196,    192,    188,
   184,    180,    177,    173,    170,    166,    163,    160,
   157,    153,    150,    147,    144,    141,    139,    136,
   133,    130,    128,    125,    123,    120,    118,    115,
   113,    111,    109,    106,    104,    102,    100,     98,
    96,     94,     92,     91,     89,     87,     85,     83,
    82,     80,     79,     77,     75,     74,     72,     71,
    69,     68,     67,     65,     64,     63,     61,     60,
    59,     58,     57,     56,     54,     53,     52,     51,
    50,     49,     48,     47,     46,     45,     44,     43,
    43,     42,     41,     40,     39,     38,     38,     37,
    36,     35,     35,     34,     33,     33,     32,     31,
    31,     30,     29,     29,     28,     28,     27,     27,
    26,     26,     25,     24,     24,     23,     23,     23,
    22,     22,     21,     21,     20,     20,     19,     19,
    19,     18,     18,     18,     17,     17,     17,     16,
    16,     16,     15,     15,     15,     14,     14,     14,
    13,     13,     13,     13,     12,     12,     12,     12,
    11,     11,     11,     11,     10,     10,     10,     10,
    10,      9,      9,      9,      9,      9,      8,      8,
     8,      8,      8,      8,      7,      7,      7,      7,
     7,      7,      6,      6,      6,      6,      6,      6,
     6,      6,      5,      5,      5,      5,      5,      5,
     5,      5,      5,      4,      4,      4,      4,      4,
     4,      4,      4,      4,      4,      4,      3,      3,
     3,      3,      3,      3,      3,      3,      3,      3,
     3,      3,      3,      3,      2,      2,      2,      2,
     2,      2,      2,      2,      2,      2,      2,      2,
     2,      2,      2,      2,      2,      2,      2,      2,
     1,      1,      1,      1,      1,      1,      1,      1,
     1,      1,      1,      1,      1,      1,      1,      1,
#endif    
};

#pragma vector = TIMER0_A1_VECTOR                   // Timer A0 Overflow interrupt
__interrupt void timer0_a1_isr(void)                //
{                                                   //
   static long int pa = 0;                         // Phase accumulator
   static unsigned sample = 200;                   // PWM sample
                                                   //
   TACCR1 = sample;                                // Output previous PWM sample
                                                   //
   volatile unsigned z = TAIV;                     // Clear interrupt flag
                                                   //
                                                   // Get next PWM value
   sample = 200 - ((envelope[note_env >> 8] * sine[pa >> 16]) >> 8);
                                                   //
   if((pa += pi) < 0) pa += phase_limit;           // Update phase accumulator
                                                   //
   if(note_env != 0xFFFF) ++note_env;              // Increment envelope if not at maximum
                                                   //                                                  
   if(note_timer) --note_timer;                    // Decrement note timer
}                                                   //

static const char * const tunes[] = {
   "Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6",
   "Popcorn:d=4,o=5,b=160:8c6,8a#,8c6,8g,8d#,8g,c,8c6,8a#,8c6,8g,8d#,8g,c,8c6,8d6,8d#6,16c6,8d#6,16c6,8d#6,8d6,16a#,8d6,16a#,8d6,8c6,8a#,8g,8a#,c6",
   "peanuts:d=4,o=5,b=160:f,8g,a,8a,8g,f,2g,f,p,f,8g,a,1a,2p,f,8g,a,8a,8g,f,2g,2f,2f,8g,1g",
   "PinkPanther:d=4,o=5,b=160:8d#,8e,2p,8f#,8g,2p,8d#,8e,16p,8f#,8g,16p,8c6,8b,16p,8d#,8e,16p,8b,2a#,2p,16a,16g,16e,16d,2e",
   "aadams:d=4,o=5,b=160:8c,f,8a,f,8c,b4,2g,8f,e,8g,e,8e4,a4,2f,8c,f,8a,f,8c,b4,2g,8f,e,8c,d,8e,1f,8c,8d,8e,8f,1p,8d,8e,8f#,8g,1p,8d,8e,8f#,8g,p,8d,8e,8f#,8g,p,8c,8d,8e,8f",
   "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c",
   //"StWars:d=4,o=5,b=180: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,p,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",
   //"Mission:d=4,o=6,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16a#,16g,2d,32p,16a#,16g,2c#,32p,16a#,16g,2c,16p,16a#5,16c",
   0
};

void main(void)
{
   WDTCTL = WDTPW | WDTHOLD;                       // Disable watchdog reset
   DCOCTL = 0;                                     // Run at 16 MHz
   BCSCTL1 = CALBC1_16MHZ;                         //
   DCOCTL = CALDCO_16MHZ;                          //
                                                   //
   P1DIR = BIT6;                                   // Enable PWM output on P1.6
   P1SEL = BIT6;                                   //
                                                   //                                                  
   TACTL = TASSEL_2 | MC_1 | TAIE;                 // Timer A config: SMCLK, count up, ovrflow int enabled
   TACCR0 = 332;                                   // Setup Timer A period for 48.048 kHz
   TACCR1  = 200;                                  // Setup Timer A compare to "DAC" zero value
   TACCTL1 = OUTMOD_7;                             // Setup Timer A reset/set output mode
                                                   //
   _EINT();                                        // Enable interrupts
                                                   //
   const char * const *t;                          //
   for(; for(t = tunes; *t; ++t) {               // Iterate all ring tones
       play(*t);                                   // Play it
       note_timer = 48048;                         // Wait a second before next
       while(note_timer);                          //
   }                                               //
}

Link to post
Share on other sites

Square wave version. Changes TimerA period, does not use DDS. Can not go below octave 4 (withing spec, but parser allows lower octaves).

 

#include 
#include 

//
// RTTTL spec: http://www.mobilefish.com/tutorials/rtttl/rtttl_quickguide_specification.html
//

static volatile unsigned long note_timer = 0;       // Note timer, decrements at note frequency


static int isnote(char c)                           // Get note index, or 128 for pause
{                                                   //
   //                               A  B   C  D  E  F  G  H(
   static const int note_map[8] = { 9, 11, 0, 2, 4, 5, 7, 11 }; // MIDI note value
   if(c >= 'a' && c <= 'h') return note_map[c - 'a']; // Lower case note
   if(c >= 'A' && c <= 'H') return note_map[c - 'A']; // Upper case note
   if(c == 'p' || c == 'P') return 128;            // Pause
   return -1;                                      // Invalid, return -1
}

static void play_note(unsigned n, unsigned long d)  // Play note
{                                                   // n: MIDI note value
                                                   // d: duration in units of 1/16000000 second
                                                   //
   static const unsigned note_spacing = 10;        // 10 ms between notes
   static const unsigned long midi_notes[12] = {   // MIDI upper 12 notes
        664488L,                                   // 116 G# 9
        704000L,                                   // 117 A  9
        745862L,                                   // 118 A# 9
        790213L,                                   // 119 B  9
        837202L,                                   // 120 C  10
        886984L,                                   // 121 C# 10
        939727L,                                   // 122 D  10
        995606L,                                   // 123 D# 10
       1054808L,                                   // 124 E  10
       1117530L,                                   // 125 F  10
       1183982L,                                   // 126 F# 10
       1254385L                                    // 127 G  10
   };                                              //
   unsigned long f;                                //
   if(n > 127) {                                   // Invalid note value is pause
       f = 0;                                      // Frequency = 0
   } else {                                        //
       unsigned o = 10; n += 4;                    // Init octave, adjust note
       while(n >= 12) n -= 12, --o;                // Normalize note, adjust octave
       f = midi_notes[n];                          // Get frequency
       while(o) f >>= 1, --o;                      // Adjust frequency for octave
   }                                               //
   const unsigned c = f ? (16000000UL * 100) / f : 16000; // TimerA period
   const unsigned t = d / c;                       // Note cycles 
                                                   //   
   while(note_timer);                              // Wait for current note to finish
                                                   //
   if(note_spacing) {                              // Silence between notes
       TACCTL1 = OUTMOD_0;                         // PWM off 
       TACCR0 = 16000 - 1 ;                        // 1 ms period
       note_timer = note_spacing;                  //
       while(note_timer);                          //
   }                                               //
                                                   //
   note_timer = t;                                 // Setup note time
   TACCR0 = c - 1;                                 //
   TACCR1 = TACCR0 >> 1;                           //
   TACCTL1 = f ? OUTMOD_7 : OUTMOD_0;              // PWM on for tone, off for pause 
}

void play(const char *s)                            // Play RTTTL string
{                                                   //
   unsigned state = 0;                             // Initial state
   char c, d;                                      // Char from string, default specifier
   unsigned bpm = 63;                              // Beats (quarter notes) per minute
   unsigned default_duration = 4;                  // Default note duration (fraction of a whole note)
   unsigned default_octave = 5;                    // Default octave
   long unsigned dot;                              // Numerator for note clock count calculation, adjusted for dot notation
   unsigned duration = 0;                          // Note duration
   int note;                                       // Note index 0 to 11
   int octave;                                     // Octave 0 to 9
                                                   //
   do {                                            //
       c = *s++;                                   // Get a char from RTTTL string
       if(c > 0 && c <= 32) continue;              // Ingore whitespace and control chars
       switch(state) {                             //
           case 0:                                 // - Skip name
               if(c == ':') ++state;               // Toss chars until ':'
               break;                              //
           case 1:                                 // - Parse defaults
   state1:                                         //
               if(c == ':') {                      // End of default section, begin parsing notes
                   state = 4;                      //
               } else if(isalpha(c)) {             // Default designator - allow any alpha
                   d = c;                          // Save it
                   state = 2;                      // Verify assignment character
               } else {                            //
                   state = 1;                      // Invalid char, stay in this state
               }                                   //
               break;                              //
           case 2:                                 // - Default assignment char, must be '='
               if(c == '=') {                      //
                   note = 0;                       // Init default
                   ++state;                        // Parse default value
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 3:                                 // - Parse and assign default value
               if(isdigit(c)) {                    // Update default
                   note = note * 10 + (c - '0');   //
               } else if(c == ',' || c == ':') {   // End of default, assign to variable
                   switch(d) {                     //
                       case 'b':                   // Default BPM
                       case 'B':                   //
                           bpm = note;             //
                           break;                  //
                       case 'o':                   // Default octave
                       case 'O':                   //
                           default_octave = note;  //
                           break;                  //
                       case 'd':                   // Default note duration
                       case 'D':                   //
                           default_duration = note;//
                           break;                  //
                   }                               //
                   state = (c == ':') ? 4 : 1;     // Get next default or begin parsing notes
               } else goto state1;                 // Invalid char, start over
               break;                              //
           case 4:                                 // - Parse note
               dot = 16000000UL * 60 * 4;          // Setup defaults for this note
               duration = default_duration;        //
               octave = default_octave;            //
               note = 0;                           //
               if(isdigit(c)) {                    // May begin with duration
                   duration = c - '0';             // Init duration
                   ++state;                        // May be more than one digit, continue in next state
               } else if((note = isnote(c)) >= 0) {// May begin with note
                   state = 6;                      // Got note, parse modifiers and octave
               }                                   //
               break;                              //
           case 5:                                 // - Parse duration
               if(isdigit(c)) {                    // Numeric digit, update duration
                   duration = duration * 10 + (c -'0');
               } else if((note = isnote(c)) >= 0) {// Got note, parse modifiers and octave
                   ++state;                        //
               } else {                            // Invlid char, start over 
                   state = 4;                      //
               }                                   //
               break;                              //
           case 6:                                 // - Parse modifiers and octave
               if(c == ',' || c == 0) {            // End of note, play it
                   play_note((octave + 1) * 12 + note, dot / (duration * bpm));
                   state = 4;                      // Next note
               } else if(c == '#') {               // Sharp, increment note value
                   ++note;                         //
               } else if(c == 'b') {               // Flat, decrement note value
                   --note;                         //
               } else if(c == '.') {               // Dotted note, extend length by 50%
                   dot += (dot >> 1);              //
               } else if(isdigit(c)) {             // Octave, 0 to 9 allowed, should be 4 to 7
                   octave = c - '0';               //
               }                                   //
               break;                              //
                                                   //
       }                                           //
   } while(c);                                     // End of string
   while(note_timer);                              // Wait for last note to finish
   TACCTL1 = OUTMOD_0;                             // PWM off 
   TACCR0 = 16000 - 1 ;                            // 1 ms period
}

#pragma vector = TIMER0_A1_VECTOR                   // Timer A0 Overflow interrupt
__interrupt void timer0_a1_isr(void)                //
{                                                   //
   volatile unsigned z = TAIV;                     // Clear interrupt flag
   if(note_timer) --note_timer;                    // Decrement note timer
}                                                   //

static const char * const tunes[] = {
   "Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6",
   "Popcorn:d=4,o=5,b=160:8c6,8a#,8c6,8g,8d#,8g,c,8c6,8a#,8c6,8g,8d#,8g,c,8c6,8d6,8d#6,16c6,8d#6,16c6,8d#6,8d6,16a#,8d6,16a#,8d6,8c6,8a#,8g,8a#,c6",
   "peanuts:d=4,o=5,b=160:f,8g,a,8a,8g,f,2g,f,p,f,8g,a,1a,2p,f,8g,a,8a,8g,f,2g,2f,2f,8g,1g",
   "PinkPanther:d=4,o=5,b=160:8d#,8e,2p,8f#,8g,2p,8d#,8e,16p,8f#,8g,16p,8c6,8b,16p,8d#,8e,16p,8b,2a#,2p,16a,16g,16e,16d,2e",
   "aadams:d=4,o=5,b=160:8c,f,8a,f,8c,b4,2g,8f,e,8g,e,8e4,a4,2f,8c,f,8a,f,8c,b4,2g,8f,e,8c,d,8e,1f,8c,8d,8e,8f,1p,8d,8e,8f#,8g,1p,8d,8e,8f#,8g,p,8d,8e,8f#,8g,p,8c,8d,8e,8f",
   "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c",
   "StWars:d=4,o=5,b=180: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,p,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",
   "Mission:d=4,o=6,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16a#,16g,2d,32p,16a#,16g,2c#,32p,16a#,16g,2c,16p,16a#5,16c",
   0
};

void main(void)
{
   WDTCTL = WDTPW | WDTHOLD;                       // Disable watchdog reset
   DCOCTL = 0;                                     // Run at 16 MHz
   BCSCTL1 = CALBC1_16MHZ;                         //
   DCOCTL = CALDCO_16MHZ;                          //
                                                   //
   P1DIR = BIT6;                                   // Enable PWM output on P1.6
   P1SEL = BIT6;                                   //
                                                   //                                                  
   TACTL = TASSEL_2 | MC_1 | TAIE;                 // Timer A config: SMCLK, count up, ovrflow int enabled
   TACCR0 = 16000 - 1 ;                            // 1 ms period
                                                   //
   _EINT();                                        // Enable interrupts
                                                   //
   const char * const *t;                          //
   for(; for(t = tunes; *t; ++t) {               // Iterate all ring tones
       play(*t);                                   // Play it
       note_timer = 1000;                          // Wait a second before next
       while(note_timer);                          //
   }                                               //
}

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...