Facebook
From Wet Duck, 4 Years ago, written in C.
Embed
Download Paste or View Raw
Hits: 251
  1. // A fun sketch to demonstrate the use of the tone() function written by Brett Hagman.
  2.  
  3. // This plays RTTTL (RingTone Text Transfer Language) songs using the
  4. // now built-in tone() command in Wiring and Arduino.
  5. // Written by Brett Hagman
  6. // http://www.roguerobotics.com/
  7.  
  8. // To play the output on a small speaker (i.e. 8 Ohms or higher), simply use
  9. // a 1K Ohm resistor from the output pin to the speaker, and connect the other
  10. // side of the speaker to ground.
  11.  
  12. // You can get more RTTTL songs from
  13. // http://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
  14.  
  15. const int tonePin = 12;  // for rEDI board
  16. //const int tonePin = 13;  // arbitrary for arduino boards, set this to whatever you want
  17.  
  18. #define OCTAVE_OFFSET 0
  19.  
  20. // These values can also be found as constants in the Tone library (Tone.h)
  21. int notes[] = { 0,
  22. 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
  23. 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
  24. 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976,
  25. 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951
  26. };
  27.  
  28. const char songa[] PROGMEM = "The Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8c6,c6";
  29. const char songb[] PROGMEM = "Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6";
  30. const char songc[] PROGMEM = "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";
  31. const char songd[] PROGMEM = "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";
  32. const char songe[] PROGMEM = "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";
  33. const char songf[] PROGMEM = "Xfiles:d=4,o=5,b=125:e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,g6,f#6,e6,d6,e6,2b.,1p,g6,f#6,e6,d6,f#6,2b.,1p,e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,e6,2b.";
  34. const char songg[] PROGMEM = "Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6,8d6,8a,8c6,8g,8a#,8a,8f";
  35. const char songh[] PROGMEM = "20thCenFox:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,32p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4p,8e,8g#,8b,1c#6,8f#,8a,8c#6,1e6,8a,8c#6,8e6,1e6,8b,8g#,8a,2b";
  36. const char songi[] PROGMEM = "Bond:d=4,o=5,b=80:32p,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d#6,16d#6,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d6,16c#6,16c#7,c.7,16g#6,16f#6,g#.6";
  37. const char songj[] PROGMEM = "MASH:d=8,o=5,b=140:4a,4g,f#,g,p,f#,p,g,p,f#,p,2e.,p,f#,e,4f#,e,f#,p,e,p,4d.,p,f#,4e,d,e,p,d,p,e,p,d,p,2c#.,p,d,c#,4d,c#,d,p,e,p,4f#,p,a,p,4b,a,b,p,a,p,b,p,2a.,4p,a,b,a,4b,a,b,p,2a.,a,4f#,a,b,p,d6,p,4e.6,d6,b,p,a,p,2b";
  38. const char songk[] PROGMEM = "StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6";
  39. const char songl[] PROGMEM = "GoodBad:d=4,o=5,b=56:32p,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,d#,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,c#6,32a#,32d#6,32a#,32d#6,8a#.,16f#.,32f.,32d#.,c#,32a#,32d#6,32a#,32d#6,8a#.,16g#.,d#";
  40. const char songm[] PROGMEM = "TopGun:d=4,o=4,b=31:32p,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,16f,d#,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,g#";
  41. const char songn[] PROGMEM = "A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
  42. const char songo[] PROGMEM = "Flinstones:d=4,o=5,b=40:32p,16f6,16a#,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,d6,16f6,16a#.,16a#6,32g6,16f6,16a#.,32f6,32f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,a#,16a6,16d.6,16a#6,32a6,32a6,32g6,32f#6,32a6,8g6,16g6,16c.6,32a6,32a6,32g6,32g6,32f6,32e6,32g6,8f6,16f6,16a#.,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#6,16c7,8a#.6";
  43. const char songp[] PROGMEM = "Jeopardy:d=4,o=6,b=125:c,f,c,f5,c,f,2c,c,f,c,f,a.,8g,8f,8e,8d,8c#,c,f,c,f5,c,f,2c,f.,8d,c,a#5,a5,g5,f5,p,d#,g#,d#,g#5,d#,g#,2d#,d#,g#,d#,g#,c.7,8a#,8g#,8g,8f,8e,d#,g#,d#,g#5,d#,g#,2d#,g#.,8f,d#,c#,c,p,a#5,p,g#.5,d#,g#";
  44. const char songq[] PROGMEM = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
  45. const char songr[] PROGMEM = "Smurfs:d=32,o=5,b=200:4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8f#,p,8a#,p,4g#,4p,g#,p,a#,p,b,p,c6,p,4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8b,p,8f,p,4f#";
  46. const char songs[] PROGMEM = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
  47. const char songt[] PROGMEM = "LeisureSuit:d=16,o=6,b=56:f.5,f#.5,g.5,g#5,32a#5,f5,g#.5,a#.5,32f5,g#5,32a#5,g#5,8c#.,a#5,32c#,a5,a#.5,c#.,32a5,a#5,32c#,d#,8e,c#.,f.,f.,f.,f.,f,32e,d#,8d,a#.5,e,32f,e,32f,c#,d#.,c#";
  48. const char songu[] PROGMEM = "MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d";
  49.  
  50.  
  51. const char *allsongs[] = {songa,
  52.                     songb,
  53.                     songc,
  54.                     songd,
  55.                     songe,
  56.                     songf,
  57.                     songg,
  58.                     songh,
  59.                     songi,
  60.                     songj,
  61.                     songk,
  62.                     songl,
  63.                     songm,
  64.                     songn,
  65.                     songo,
  66.                     songp,
  67.                     songq,
  68.                     songr,
  69.                     songs,
  70.                     songt,
  71.                     songu
  72.                     };
  73.  
  74. void setup(void)
  75. {
  76.   Serial.begin(9600);
  77. }
  78.  
  79. #define isdigit(n) (n >= '0' && n <= '9')
  80.  
  81. void play_rtttl(const char *signMessage)
  82. {
  83.   // Absolutely no error checking in here
  84.  
  85.   byte default_dur = 4;
  86.   byte default_oct = 6;
  87.   int bpm = 63;
  88.   int num;
  89.   long wholenote;
  90.   long duration;
  91.   byte note;
  92.   byte scale;
  93.  
  94.   int pauses = 2;
  95.  
  96.   int p = 0;
  97.  
  98.   // format: d=N,o=N,b=NNN:
  99.   // find the start (skip name, etc)
  100.  
  101.   while(pgm_read_byte_near(signMessage + p) != ':') p++;    // ignore name
  102.   p++;                     // skip ':'
  103.  
  104.   // get default duration
  105.   if(pgm_read_byte_near(signMessage + p) == 'd')
  106.   {
  107.     p++; p++;              // skip "d="
  108.     num = 0;
  109.     while(isdigit(pgm_read_byte_near(signMessage + p)))
  110.     {
  111.       num = (num * 10) + (pgm_read_byte_near(signMessage + p++) - '0');
  112.     }
  113.     if(num > 0) default_dur = num;
  114.     p++;                   // skip comma
  115.   }
  116.  
  117.   Serial.print("ddur: "); Serial.println(default_dur, 10);
  118.  
  119.   // get default octave
  120.   if(pgm_read_byte_near(signMessage + p) == 'o')
  121.   {
  122.     p++; p++;              // skip "o="
  123.     num = pgm_read_byte_near(signMessage + p++) - '0';
  124.     if(num >= 3 && num <=7) default_oct = num;
  125.     p++;                   // skip comma
  126.   }
  127.  
  128.   Serial.print("doct: "); Serial.println(default_oct, 10);
  129.  
  130.   // get BPM
  131.   if(pgm_read_byte_near(signMessage + p) == 'b')
  132.   {
  133.     p++; p++;              // skip "b="
  134.     num = 0;
  135.     while(isdigit(pgm_read_byte_near(signMessage + p)))
  136.     {
  137.       num = (num * 10) + (pgm_read_byte_near(signMessage + p++) - '0');
  138.     }
  139.     bpm = num;
  140.     p++;                   // skip colon
  141.   }
  142.  
  143.   Serial.print("bpm: "); Serial.println(bpm, 10);
  144.  
  145.   // BPM usually expresses the number of quarter notes per minute
  146.   wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)
  147.  
  148.   Serial.print("wn: "); Serial.println(wholenote, 10);
  149.  
  150.  
  151.   // now begin note loop
  152.   while(pgm_read_byte_near(signMessage + p))
  153.   {
  154.     // first, get note duration, if available
  155.     num = 0;
  156.     while(isdigit(pgm_read_byte_near(signMessage + p)))
  157.     {
  158.       num = (num * 10) + (pgm_read_byte_near(signMessage + p++) - '0');
  159.     }
  160.    
  161.     if(num) duration = wholenote / num;
  162.     else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after
  163.  
  164.     // now get the note
  165.     note = 0;
  166.  
  167.     switch(pgm_read_byte_near(signMessage + p))
  168.     {
  169.       case 'c':
  170.         note = 1;
  171.         break;
  172.       case 'd':
  173.         note = 3;
  174.         break;
  175.       case 'e':
  176.         note = 5;
  177.         break;
  178.       case 'f':
  179.         note = 6;
  180.         break;
  181.       case 'g':
  182.         note = 8;
  183.         break;
  184.       case 'a':
  185.         note = 10;
  186.         break;
  187.       case 'b':
  188.         note = 12;
  189.         break;
  190.       case 'p':
  191.       default:
  192.         note = 0;
  193.     }
  194.     p++;
  195.  
  196.     // now, get optional '#' sharp
  197.     if(pgm_read_byte_near(signMessage + p) == '#')
  198.     {
  199.       note++;
  200.       p++;
  201.     }
  202.  
  203.     // now, get optional '.' dotted note
  204.     if(pgm_read_byte_near(signMessage + p) == '.')
  205.     {
  206.       duration += duration/2;
  207.       p++;
  208.     }
  209.  
  210.     // now, get scale
  211.     if(isdigit(pgm_read_byte_near(signMessage + p)))
  212.     {
  213.       scale = pgm_read_byte_near(signMessage + p) - '0';
  214.       p++;
  215.     }
  216.     else
  217.     {
  218.       scale = default_oct;
  219.     }
  220.  
  221.     scale += OCTAVE_OFFSET;
  222.  
  223.     if(pgm_read_byte_near(signMessage + p) == ',')
  224.       p++;       // skip comma for next note (or we may be at the end)
  225.  
  226.     // now play the note
  227.  
  228.     if(note)
  229.     {
  230.       Serial.print("Playing: ");
  231.       Serial.print(scale, 10); Serial.print(' ');
  232.       Serial.print(note, 10); Serial.print(" (");
  233.       Serial.print(notes[(scale - 4) * 12 + note], 10);
  234.       Serial.print(") ");
  235.       Serial.println(duration, 10);
  236.       tone(tonePin, notes[(scale - 4) * 12 + note]);
  237.       delay(duration);
  238.       noTone(tonePin);
  239.     }
  240.     else
  241.     {
  242.       Serial.print("Pausing: ");
  243.       Serial.println(duration, 10);
  244.       delay(duration);
  245.       if(!pauses && duration) return;
  246.       if(duration > 950) pauses--;
  247.     }
  248.   }
  249. }
  250.  
  251. char c;
  252. void loop(void)
  253. {
  254.   if(Serial.available())
  255.   {
  256.     c = Serial.read();
  257.     while(Serial.available()) Serial.read();
  258.     play_rtttl(allsongs[c-'a']);
  259.     Serial.println("Done.");
  260.   }
  261.  
  262. }
  263.