Pluralsight blog Where devs, IT admins & creative pros go for news, tips, videos and more.
Pluralsight + Digital-Tutors - 3,000 tech & creative courses - starting at $29/month Get it now →
December 23, 2013

Holiday fun, programmer-style: Refactoring Jingle Bells with Arduino

By jinglebells

As I sat down one day to play with my Arduino, the holiday spirit overcame me. What better way to celebrate the season than by making something geeky?

What’s so cool about Arduino is that it’s the perfect combination of hardware and software, and it’s easy to program for anyone who knows any C variant language (e.g. Java, C#, JavaScript, etc.).

The hardware part allows you to send either digital or analog signals to a large number of physical devices. With the Internet of Things (IOT) becoming more and more mainstream, besides bringing hours of fun, the Arduino’s ability to allow you to quickly and easily create hardware prototypes is nothing short of amazing.

So I decided to create an Arduino project to play Jingle Bells. Now, an Arduino project that just does one thing isn’t very interesting, so I added flashing LEDs.

I already had some code lying around, so I went to work.

Here’s where the Code Ghosts of Holidays Past came to haunt me.

I don’t know about you, but every time I open an old piece of code (something written more than six months ago), I cringe because my first thought is, “What horrible developer wrote this code?!”

Of course I quickly come to the embarrassing realization that I am the horrible developer.

I grabbed an eggnog to sooth my bruised ego, and when to work refactoring.

The code I had written looked like this:

digitalWrite(13,HIGH);
tone(speaker, NOTE_CS4,eigth);
delay(eigth);
digitalWrite(13,LOW);

digitalWrite(12,HIGH);
tone(speaker, NOTE_E4,eigth);
delay(eigth);
digitalWrite(12,LOW);

digitalWrite(11,HIGH);
tone(speaker, NOTE_CS4,eigth);
delay(eigth);
digitalWrite(11,LOW);

digitalWrite(10,HIGH);
tone(speaker, NOTE_B3,dottedquarter);
delay(dottedquarter);
digitalWrite(10,LOW);
delay(quarter);

The call to digitalWrite sends a either a 5v (HIGH) or 0v (LOW) signal to the attached device, which in this case is a simple LED. When it gets the HIGH signal, the LED flashes on. When it gets the low SINGLE, it flashes off.

The call to tone sends a square wave of the specified frequency (and 50 percent duty cycle)  to a specific pin. I’ve got a number of #defines in my code that set the values for different musical notes. Then I’ve got a set of global constants in my program to represent temp. Passing the pin, the note and the length to the tone function allows me to hook up a simple speaker to a pin on my Arduino and get it to play “music.”

After the note plays, I delay so the sound has a chance to finish, and then to turn off the corresponding LED.

Hopefully you can see what’s wrong with this embarrassing code. Its structure is very repetitive, which calls for refactoring this code into a function.

Arduino totally supports functions, so I have no excuse for not refactoring when I wrote this code the first time (since I was not drinking eggnog at the time).

The LED turning on and off is also hardcoded, and I’d like the ability to have more than one LED play with a corresponding note.

void playNoteAndLight(int note,int length)
{
int ledNum = leds[led];
digitalWrite(ledNum,HIGH);
tone(speaker, note,length);
delay(length);
digitalWrite(ledNum,LOW);
led++;
if(led>num){
led = 0;
}
}

So there is my refactored function, which takes the note and then length. It plays the note for that length, and at the same time uses an array of LED pin values (leds) to switch between N leds.

Once I re-wrote the code in my loop it was much cleaner. (I still think there is more refactoring to do. Maybe you gentle readers can suggest some?)

void loop()
{
/* jingle bells */

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,half);

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,half);

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_G4,quarter);
playNoteAndLight(NOTE_C4,dottedquarter);
playNoteAndLight(NOTE_D4,eighth);

playNoteAndLight(NOTE_E4,whole);

playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);

playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,half);

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_D4,quarter);
playNoteAndLight(NOTE_D4,quarter);
playNoteAndLight(NOTE_E4,quarter);

playNoteAndLight(NOTE_D4,half);
playNoteAndLight(NOTE_G4,half);

/* second verse */
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,half);

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,half);

playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_G4,quarter);
playNoteAndLight(NOTE_C4,dottedquarter);
playNoteAndLight(NOTE_D4,eighth);

playNoteAndLight(NOTE_E4,whole);

playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_F4,quarter);

playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,quarter);
playNoteAndLight(NOTE_E4,eighth);
playNoteAndLight(NOTE_E4,eighth);

playNoteAndLight(NOTE_G4,quarter);
playNoteAndLight(NOTE_G4,quarter);
playNoteAndLight(NOTE_F4,quarter);
playNoteAndLight(NOTE_D4,quarter);

playNoteAndLight(NOTE_C4,whole);

}

Once I played this, I realized the tempo was much too slow. That’s because in another non-genius part of the original code I had also hardcoded the tempo of each note:

int eighth = 250;
int quarter = 500;
int dottedquarter = 750;
int half = 1000;
int whole = 2000;

An eighth note was hardcoded to a quarter of a second, and then other notes a multiplier of that note. I ended up changing the global values to be the multipliers rather than the actual values.

int eighth = 0;
int quarter = 2;
int dottedquarter = 3;
int half = 4;
int whole = 8;

Then I added a function to set the tempo.

void setuptempo(int starter)
{
eighth = starter;
quarter = quarter*starter;
dottedquarter = dottedquarter*starter;
half = half*starter;
whole = whole*starter;
}

You can watch the action here. Note: I used holiday colors for the jump wires connecting my Arduino to the breadboard. I feel so festive!

The whole source can be found here: jinglebells.ino

I hope you have hours of holiday fun watching a video of my Arduino masterpiece!

About the Author

is most at home spelunking, trying to figure out how things work from the inside out. Jon is the author of RESTful.NET from O'Reilly, as well as Essential ASP for Addison-Wesley, and was a co-author of Mastering Visual Studio.NET for O'Reilly. Jon's current major interest is helping people to understand the advantages of REST.


Discussion