Animated Musical Holiday Light Show - Version 2.0

Sign in to queue


 Create an animated holiday light show for indoor or outdoor use using some Phidget Interface Kits, extension cords, and .NET.

Difficulty: Intermediate
Time Required: 3-6 hours
Cost: $100-$200
Software: Visual Basic or Visual C# 2008 Express Editions, Phidgets .NET libraries
Hardware: Phidget Interface Kit 0/0/4, extension cords, wire nuts, spare wire
Download: Download

Welcome to version 2.0 of the software and article!  I have rewritten the key points of this article to address the new features in the latest version of the software.  Read on for a full explanation...

New Features for 2.0

  • MIDI support
    • Load a MIDI file and a sequence will be automatically created based on the data contained in the file.  You can automatically create your own show with barely any effort at all!
  • Playlists
    • Load up several sequences and have them play in order to create a multi-song show!
  • More accurate timing
    • The timing algorithm used in the last version was very worked, but it wasn't perfect.  The new version uses a method which gives millisecond precision timing
  • Cut/Copy/Paste
    • One can now cut/copy/paste cells on the grid...makes it easy to repeat chunks of sequences without having to tap out the rhythm by hand over and over again
  • Edit existing sequences
    • After loading a sequence created by someone else (or yourself), you can now re-assign Phidget boards, serial numbers, output ports, etc. to get them to run on your setup.

Note that any sequences created with the old version will continue to play just fine, but editing them could be troublesome due to the new timing method.

And now back to the article with updates.  The hardware section remains the same, but the software discussion below is updated with new information.

I'm sure by now everyone with a computer has seen the videos of holiday light shows timed to holiday music such as this one.  For this holiday season, I decided to create my own indoor show using some off-the-shelf components and .NET.



WARNING:  The hardware portion of this project uses standard 120V AC current.  As you are likely aware, this is enough voltage to seriously hurt or kill you.  Please be careful and follow the instructions closely.

What You Will Need

  • Phidget Interface Kit 0/0/4 – a USB-controlled board with 4 relays.  I used 2 kits for a total of 8 channels.  Any number can be used.
  • 5 6' (or longer/shorter for your needs) indoor or outdoor 2-prong extension cords for each Phidget board used.  I was able to find these at the local home improvement store for about $1 each.  If you will be creating an outdoor show, be sure to purchase extension cords that are meant for outdoor use.

Generic Episode Image

  • Some 14-16 gauge wire.  If in doubt, simply buy one additional extension cord to use for the additional wire.
  • 2 wire nuts that can handle the wire gauge selected above for each Phidget board used.

Generic Episode Image 

  • A project box large enough to hold one or many Phidget boards and associated wiring.  I chose a 7"L x 5"W x 3"H enclosure from Radio Shack which provides ample room to hold 2 Phidget Interface Kits and wiring.
  • Some holiday lights
  • External speakers (or possibly an FM transmitter for an outdoor show)
  • Phidgets .NET libraries
  • Microsoft Visual Basic or Visual C# Express Editions

Building the Hardware

The hardware we are going to build will allow for one Phidget board to be plugged into a single AC outlet and provide 4 output outlets that can be switched off and on by the Phidget board's relays.  By building two of these and placing them in a project box, I have a neat and tidy control box with 2 USB inputs, 2 AC male plugs for the wall, and 8 AC female plugs for my lights.  The following description will be for building a single unit.

Let's start by preparing the extension cords.  Cut the female end off of one extension cord.  Split the cord up the center and strip the insulation off each of the wires to expose the ends.  Twist the ends with your fingers to create a neat, twisted wire as shown:

Generic Episode Image

Next, take the remaining four extension cords and cut the male ends off each.  As before, split the cord up the center a small bit, strip off some insulation, and twist the exposed ends as shown:

Generic Episode Image

Now, cut 4 equal lengths of your 14-16 gauge wire.  These should be no longer than 2-4 inches in length.  Strip some insulation off each end and twist up any loose wires.

Generic Episode Image

For the next part, you will need to pay close attention.  Each extension cord should have two different types of insulation around the wires.  One side should have a ribbed edge, and one side should have a smooth edge shown below:

Generic Episode Image Generic Episode Image

The ribbed side should be in line with the "fat" prong/receptacle (the neutral side) and the smooth side should be in line with the smaller prong/receptacle (the active/"hot" side).  It is important that the next steps be followed carefully, noting which wires I am referring to.  Using the wrong wire can lead to a short, blown fuses, kicked circuit breakers, or even worse things.

Take the 4 short wires you cut earlier and twist them all together along with the ribbed/neutral wire from the extension cord with the male end still attached.

Generic Episode Image

Twist a wire nut over the exposed ends to keep them together and covered.

Generic Episode Image

Next, twist together the smooth/"hot" wire from the four extension cords with the female ends still attached along with the smooth/"hot" wire from the extension cord with the male end attached (i.e. the other wire from the male cord used above).

Generic Episode Image

Again, twist on a wire nut to keep things covered and safe.

Generic Episode Image

You should now be left with the opposite ends of the 4 cut wires exposed, and the 4 ribbed/neutral wires of the female extension exposed.  These will all be put into the screw terminals of the Phidget Interface Kit.

The Phidget Interface Kit board has 4 groups of screw terminals.  Each group contains 3 items:  NO, XC, and NC, where X is the relay number in question.  These stand for "Normally Open", "Common", and "Normally Closed".  For this project, the lights should normally be off and switched on via the software, so the NO (Normally Open) and XC (Common) ports will be used.

Place one wire from each exposed bundle into each NO and XC port.  Note that it does not matter which wire you plug into which terminal of each group, just that each group has only one short wire and only one extension cord wire.

In the end, there will be one each of the 4 short wires in each group on the board, and one each of the extension cord wires in each group on the board as pictured:

Generic Episode Image

Below is a very simple schematic of the wiring of a single board:

Generic Episode Image

I decided to keep things neat and tidy and mount the Phidget boards into a project box.  Since I have 2 boards to manage, I placed both inside a single, large box.  I drilled holes in the short sides to expose the boards' USB ports.  I then notched out some spaces on the top edge and lid for the extension cords to pass through.  I mounted the boards inside the box with some carefully placed two-sided foam tape.

The finished product can be seen below:

Generic Episode Image Generic Episode Image

And that's it!  If this box will be placed outside, take the time to properly weatherproof the box so the elements cannot damage anything inside.

A Word on Amperages

Your individual light strings will be plugged into each extension cord outlet.  An average strand of mini-lights draws about .3 amps. An average string of larger bulbs will draw 1-2 amps.  The relays on the Phidget board are rated at 10 amps.  Additionally, a standard house circuit will allow up to 15-20 amps before overloading.  Check the circuit breaker in your home on which the outlet you'll be using lives for the allowed amperage.  Also, keep in mind that any other devices that are plugged into that circuit elsewhere in the house will be drawing power, so you may not be able to draw a full 15 amps from it.  So, be sure to not draw more than 10A per channel, nor more than 15-20A in total, including all additional devices plugged into that circuit.  Keep this in mind as you string your lights together on each channel.

Writing the Software

Ensure the Phidgets libraries for .NET are installed on the development machine.  To compile the source code, Visual Basic and/or Visual C# Express 2005 will also be need to be installed and working.

The Light Sequencer application uses a grid-style interface to show the list of channels and when each channel is switched on and off.


Squares can be toggled on or off by highlighting them, right-clicking with the mouse and selecting On or Off from the context menu.  They can also be toggled by pressing the O (for on) or F (for off) keys on the keyboard.

Additionally, sequences can be "recorded" by pressing the Record button in the toolbar.  This will start the music and allow the user to tap out the rhythm for each channel by pressing the number key on the keyboard corresponding to the channel.

Sequences can be saved at any time and reloaded for editing or play with the Phidgets devices connected.

When I first started the software for this project, the first problem I ran into was the fact that the DataGridView control does no support multiple headers.  As is shown in the screenshot above, the grid is broken down into seconds and then milliseconds.  For display purposes. it is easier to break the header down into two segments, one showing the labeled second markers, and one showing the subdivisions per second.

To accomplish this, I created two DataGridViews:  one for the header, which contains no data and is only as tall as the header row, and one for the sub-header and the data below it.  This works great except for scrolling.  To accomplish this, I simply listen for the Scroll event on the main grid and apply the scrolling offset to the header grid:

Visual C#

private void dgvMain_Scroll(object sender, ScrollEventArgs e)
dgvHeader.HorizontalScrollingOffset = e.NewValue;

Visual Basic

Private Sub dgvMain_Scroll(ByVal sender As Object, ByVal e As ScrollEventArgs) Handles dgvMain.Scroll
dgvHeader.HorizontalScrollingOffset = e.NewValue
End Sub

Additionally, I ran into some performance issues drawing the grid.  At first, drawing a grid with so many columns was quite slow.  By setting the grid's Visible property to false before adding the rows and columns and then returning the Visible property to true, the grid now draws quite quickly.

The next issue tackled was starting and stopping a music file.  In version 2, the software supports sampled music (MP3, WAV, etc.) as well as MIDI files.  As I was attempting to write a MIDI file parser and player (so I could have access to the internal data for auto-generating a sequence) I found a fantastic MIDI library written by Leslie Sanford.  This library is used by the Light Sequencer application.

With two playback libraries in place, I created an interface which contains Start, Stop, Load, etc. methods so that the front-end could use any playback engine interchangeably.  The MCIPlayback engine uses standard MCI commands for playing sampled music.  Commands are executed by passing them to the mciSendString function exported by winmm.dll.  In order to use this function from .NET, we must import the method and setup its signature as follows:

Visual C#

static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);

Visual Basic

Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal command As String, _
ByVal buffer As StringBuilder, ByVal bufferSize As Int32, _
ByVal hwndCallback As IntPtr) As Int32

To open a music file, the open command is used as follows:

open "<path to file>" type mpegvideo alias MediaFile

This opens the file and creates an alias named MediaFile which can be used to refer to the file for all future commands.  Send the above command using the mciSendString method would look as follows:

Visual C#

string cmd = "open \"" + _musicFile + "\" type mpegvideo alias MediaFile";
mciSendString(cmd, null, 0, IntPtr.Zero);

Visual Basic

Dim cmd As String = "open """ + file + """ type mpegvideo alias MediaFile"
mciSendString(cmd, Nothing, 0, IntPtr.Zero)

The remaining commands we will need are:

  • play MediaFile from 0 -- Play loaded file from beginning
  • stop MediaFile -- Stop playing current file
  • close MediaFile -- Close the file

Next, the Phidget boards behavior needed to be implemented.  Talking to the Phidget board is very easy.  After creating an instance of the InterfaceKit object, a specific device can be opened by calling the open method, passing in the serial number of the device to be opened.

The serial numbers for each attached Phidget device can be determined by creating an instance of the Phidgets.Manager class, setting up the Attach event handler, and listening for the attach events as follows:

Visual C#

Phidgets.Manager phidgetsManager = new Phidgets.Manager();
phidgetsManager.Attach += new AttachEventHandler(phidgetsManager_Attach);;

void phidgetsManager_Attach(object sender, AttachEventArgs e)
Debug.WriteLine(e.Device.Name + " - " + e.Device.SerialNumber)

Visual Basic

Dim phidgetsManager as New Phidgets.Manager
AddHandler phidgetsManager.Attach, AddressOf Me.phidgetsManager_Attach

Private Sub phidgetsManager_Attach(ByVal sender As Object, ByVal e As AttachEventArgs)
Debug.WriteLine(e.Device.Name & " - " & e.device.SerialNumber)
End Sub

Setting the relay state is as easy as indexing into the outputs array of the InterfaceKit object and setting the indexed output to true or false.

In code, all of this would look like:

Visual C#

InterfaceKit ik = new InterfaceKit();;
ik.outputs[0] = true;

Visual Basic

Dim ik as New InterfaceKit
ik.outputs(0) = True

In order to maintain precise timing, the Stopwatch class from the System.Diagnostics namespace is used.  This internally uses the QueryPerformanceCounter Win32 API method to give extremely precise time values.

When it is time to playback a sequence, a thread is started which starts the music using the appropriate playback engine, and then sits in a loop, waiting for the number of milliseconds to pass specified in the sequence (50ms as default).  When that amount of time has elapsed, we send the channel states of the current tick to the relays connected.

Recording a sequence with the keyboard works in a similar fashion.  A thread is started and the music is played.  While the music is playing, KeyDown and KeyUp events are listened for.  After translating the KeyCode of the pressed key to the channel number, an internal array of which keys are "on and off" are maintained.  When the number of milliseconds elapsed hits the appropriate mark, every channel is updated with the current value of that array.  That is, which keys are up and down.

When the user stops playback, or the song ends, the channel data is returned to the main form and displayed in the main grid.

If a MIDI file is selected, sequence data is automatically generated based on the MIDI data.  A MIDI file contains a series of tracks or channels with a series of commands.  These commands tell the MIDI hardware what note to turn on, when, and for how long (among other things).  When the MIDI file is loaded, every command from every channel is enumerated and its time values are converted into milliseconds.  Once all the commands are gathered and organized, they are placed into this application's channel structure and displayed on the grid.  This allows the lights to flash in precise time to the MIDI file being played.

Using the Software

Ensure that the Phidget devices you will be using are attached to the PC.  Start by creating a new sequence from the File menu or by clicking the New Sequence button.  In the dialog that appears, locate a music file to play back and enter the length of time that the sequence should run.  Be sure to note which Phidget devices are attached and which channels they map to on the grid.  Click OK when complete.

The screen will redraw and present the grid interface for the length of time specified.  At this point, cells can be turned on and off by highlighting a cell and right-clicking, or by pressing the "O" key to turn the cell On, and the "F" key to turn the cell off.  Multiple cells can be selected and changed at once.

To use the recording interface, click the Record Sequence button or choose Record Sequence from the Sequence menu.  Be sure to select the correct choice of "Overwrite channel data" or "Append channel data."  As you record additional channels, you will almost always want to append and not overwrite.

Click the start button and a brief countdown will begin.  When the countdown reaches 0, the music will begin.  A channel can be recorded by pressing the keyboard key of the channel number.  For example, to tap out the rhythm of channel 1, press the 1 key at the appropriate times.

When complete, press the Escape key, or click the Stop button.  When the Record window is closed, the main grid will be updated with the sequence recorded.

Creating a sequence is certainly a time consuming task since each channel needs to be recorded.  While the rhythm interface allows one to record many channels simultaneously, I think it would be impossible for anyone to type out an entire sequence for all channels in one go.  In my opinion, it is easiest to record one or two channels at a time and append the data as you go.  In the end, you can use the grid interface to tweak the values and clean up any mistakes.

The sequence can be played back at any time. Simply press the Play button and watch your holiday lights play back to the timing you created.  Press the Stop button to end the current playback.

Sequences can be saved at any time by selecting Save from the file menu.

To test the channels by hand, select "Test Channels" from the "Tools" menu.  As with the recording screen, press the number keys associated with the channel to turn on or off to test that channel.

I found it was much easier to also have the lights plugged into the appropriate channels as I created my sequence.  That way I could see the results of my recordings immediately.

To create a playlist of many sequences, select New Playlist from the File menu.  Add your existing sequence files, order them as you wish, and save the playlist.  From this screen you can also play the playlist, set it up to repeat, advance tracks, etc.


To edit data on an existing sequence (Phidget serial numbers, mapped MIDI channels, etc.) select Edit Sequence Properties from the Sequence menu.  This will display the New Sequence dialog box and allow you to edit the existing setup.

Setting It All Up

So now that you have hardware, music and an animated sequence, it's time to hook it all up!  If you are doing an indoor show, a set of external speakers should be more than ample for playing the music for your light show.  For an outdoor show, you may wish to purchase an FM transmitter to output the music over a very low-powered FM frequency so that visitors can listen to the music on their car radios.  I personally have not gone this route, however you can find a variety of FM transmitters for sale around the 'net.  In a quick search, I found Ramsey Electronics which sells a variety of FM transmission hardware that is more than appropriate depending on your budget.  I am certain there are plenty of other devices that fit the bill as well.

To fire up the show, just plug in your USB Phidget devices, plug the lights into the appropriate channels, load the Light Sequencer application, and press the Play button!


And there we have it!  Holiday lights timed to your favorite holiday song.  Take your time in creating a sequence and show us what you've created!

I plan on maintaining and updating this article as we get closer and closer to the holidays, so please check back often for updates.  I will note updates at the top of the article.  Additionally, please send me any and all feedback, bug reports, feature requests, or anything else you have to say!  You can find my contact info in the readme.txt file located in the source code download linked above, or visit my website.


Special thanks to Michelle Leavitt for help setting up lights and sequence ideas, and my dad for advice on wiring up the relays.

Thanks to Leslie Sanford for the incredible MIDI Toolkit.

And, a big thank you to the beta testers for version 2: Allen Leno, Steve Runion, Steve Trueman, Corey Emmert.


Brian is a Microsoft C# MVP and a recognized .NET expert with over 6 years experience developing .NET solutions, and over 9 years of professional experience architecting and developing solutions using Microsoft technologies and platforms, although he has been "coding for fun" for as long as he can remember.  Outside the world of .NET and business applications, Brian enjoys developing both hardware and software projects in the areas of gaming, robotics, and whatever else strikes his fancy for the next ten minutes. He rarely passes up an opportunity to dive into a C/C++ or assembly language project.  You can reach Brian via his blog at

The Discussion

  • User profile image

    After stepping through the code the software does recognize that my phidget is attached however the table on the new sequence form does not populate with my phidget info. Please advise.

  • User profile image

    Where Can i find the phidget Board In america because all the places that have them are outside of north america

  • User profile image

    I seem to have a problem with the code. After stepping through the code I can decipher it enough to tell that it does recognize that my phidget is attached. However, no device shows up on the new sequence form and I get a channels index out of range error at the first if statement of the Timer_Tick event in the record form. Your assistance with this matter would be appreciated.

  • User profile image

    @Chris, you can get them at Trossen Robotics, the link at the top of the page is actually linking to them.

  • User profile image

    it is very good. i think if it can combine with our LED cherry tree light, it will be perfect.

  • User profile image
    Dan Henne

    Latest phidget libraries (including the necessary .net libraries) can be found at:

    Just need the Phidget21.msi

  • User profile image

    what web site to computeriz your lights

  • User profile image

    Do you khow if they have any programs to make light shows that are MAC compatable? I am a true PC user but my PC is way older than my MAC and cannot support the program. I am really enthusiastic about trying to build a light show but I havent found a program for MAC. Thanks!

  • User profile image
    Denis Bittencourt Muniz

    Great!! .Net Merry Christmas!


  • User profile image

    Tressa:  phidgets has libraries for Mac OSX, but you'd need to roll your own program.

    Brain, in your notes about amperages, you have a minor error.  the 10A rating at at 240V, so for a 120V application you actually have a 20A limit, but you are correct that you will need to watch that you don't overload the house circuit.  Also some houses have outdoor and garage circuits rated for up to 25A, so if you are lucky you can run a hell of a lot on this.

    And as far as the 0/16/16 board, you would need relays for 120VAC lights, but not if you found some 12VDC lights.  However, a 0/16/16 board and a handful of relays is much cheaper than 4 0/0/4 boards if you don't mind the extra wiring and the extra DC power source to power the relays, plus you'd be able to tap into the digital inputs and do fun things like trigger the sequence from motion detection.

  • User profile image

    Is the source code still available?

  • User profile image

    Here is a list of my current Coding4Fun articles: WiiEarthVR Animated Musical Holiday Light Show - Version

  • User profile image

    @Jeff30161 The source is at the top of the paged under the "Download" link

  • User profile image

    Can i apply the same wiring method with LED lights?

    I tried 2 LED strings (35 light each) & caused a power down.

    then i bypassed the controller connected the 2 strings (by sharing the same extend cord) still black down.

    i did sth wrong?


  • User profile image

    Here's an example of what you can do. It's pretty cool for the money...around $140 plus lights.

  • User profile image

    Wonderful work, I have some year 13 students working on this as a project, we have all the equipemnt, one thing that we are finding is that the program stops every so often, especially if you turn the lights on and off quickly.

  • User profile image

    I know this was posted a while ago, but the MIDI files aren't filling.  It looks like it has something to do with the length of the song that being calculated when the MIDI is loaded.  Anyone else have this issue, or a solution?

  • User profile image

    @Jeff I contacted Brian but we've run into the issue of a large sum of time has past since we released this.

    From Brian:

    I know some MIDI’s just aren’t really supported by my code…there are a handful of different of formats inside the format itself…perhaps he’s playing one of the weird ones that I didn’t code for.

  • User profile image

    @Don There was only ever one, Brian asked for people to submit them, and received 0 over the past…4 (?) years. is the link to the one and only.

  • User profile image

    Are there any sample .seq files anywhere for download?

  • User profile image

    Total Bummer!

    I noticed that the one he posted could not be edited, so I tried to copy and paste into the new format and it runs at a different time sequence.  I think I try recoding it from scratch and past the one minute mark.

    Wish me luck.

    Awesome stuff by the way!  Many props!

  • User profile image

    @Don That is AWESOME!  Email me and I'll upload it to the c4f CDN so others can check it out.

  • User profile image

    Ok, I did a seq file for Linus and Lucy from the "A Boy Named Charlie Brown" album (had to use the mp3 from Walmart, an Amazon mp3 gave me issues).  

    Where can I upload the seq file for others?  

    You can see my grainy video here:

    I also changed the code a bit to have labels at the bottom of the form that light up with the relays.  This helped me do day time coding of the seq file.

  • User profile image

    @PleasantDemise that looks sweet!

  • User profile image

    Modified the code to support other (cheaper? Smiley hardware:

  • User profile image

    Hi all,

    Please share you sequence files with everyone. It will make a much better experience for all of us!

    PleasantDemise, would you be willing to share your sequence file/code?

Add Your 2 Cents