ECE 476 Final Project: TV/Keypad Interface for Winamp
Barry Rafkind
Jamie Schnapp
Craig Kiczek
Program Design
This program was written for the Atmel Mega 32 microcontroller. There is a regular mode for viewing track information and an equilizer mode for changing equilizer levels. Each mode is displayed on a different screen.
The code has three main tasks:
Task 1. Translate keypad presses into characters sent to a WinAmp DLL module.
Task 2. Accept information from the WinAmp module through the serial port.
Task 3. Display a GUI on a television

Program Operation

On power-up, our program requests the playlist length from WinAmp and the first five tracks. Information about these tracks are displayed on a formatted screen with a separate area to display the volume, the track time, PLAY/PAUSE/STOP, and SHUFFLE/REPEAT/MUTE. The first track is selected and is seen scrolling from right to left in the top position.

A keypad function polls the keypad to detect user input. Each button is mapped to a specific command in each mode. A command consists of a character which is sent back through the UART register to WinAmp. Certain commands (i.e. forward/backward and page up/down) request a movement up or down in the playlist. Changes in the playlist ellicit transmissions from WinAmp with new track information. Our UART interrupt function handles this serial communication and stores the incoming data into string arrays.

We start in regular mode. In equilizer mode, preamp and frequency bands can be incremented (no shift) or decremented (in shift mode). The shift mode we implemented to allow for both up and down movement of all equilizer levels since we only have 16 keypad buttons.

Helper subfunctions were created to modularize the code. They are:


All commands are communicated by sending characters to the WinAmp module. Each command has a unique character associated with it. All strings and information passed back from WinAmp are terminated with a return carriage. We use this fact to determine when a transmission has ended.

One complex feature of our MCU program involve the ability to scroll up and down through the playlist. This is accomplished by sending a batch request for a particular track number. The WinAmp module then sends back info for five consecutive tracks starting with the one four tracks ahead of that which was requested and ending with the requested track. This reverse ordering means that we do not need to store the track info for each track as the last string sent is the one for the selected track. By changing which track we request, we can either scroll the playlist back/ahead by one or page up, page down. Since we display only five tracks at a time, a "page" consists of five tracks.

We used Land's video code as a template for our MCU software. To maximize video write speed and to fit more text on screen, we strictly used the small bitmap characters. We attempted writing our own lower case characters, but they looked like crap, so we mapped all lower case characters back to upper case. Furthermore, a complete screen cannot be written in one pass; both the equalizer and playlist screens require three full cycles.

We found we could clear the screen easily by zeroing out the screen[ ] array.

We optimized the line drawing function by creating two separate functions, one for horizontal lines, one for vertical lines. Each function only has to alter one Cartesian coordinate.

With more time, we would have our program detect when a song finishes playing so that it would update the playlist on the tv. Also, we would remove the video display functions from the UART interrupt so that they would occur only when the timer1 interrupt was done drawing the screen. Hopefully, this change would eliminate the blip associated with changing tracks on the playlist.

WinAmp Plug-In

Our DLL code performs a large array of functions, and the DLL actually allows for greater functionality than the MCU takes advantage of. This makes our DLL flexible and will expedite any improvements we want to make to the MCU code.

Our code contains logic to check the readiness of COM1. For example, if there is no COM1 available, winamp will alert the user with a message box and take no further action.

The main routine is checkPorts() which is invoked every 20ms through a windows API mechanism. checkPorts() watches COM1 to see if the MCU needs anything. It also checks to see if the song has changed. Whenever the song changes, it grabs the title and track length then relays this information to the MCU. checkPorts() recognizes an extraordinary number of commands that can be sent from the MCU. These include:

These commands are each represented by a unique character, which the DLL receives over the UART.

The checkPorts() function knows not to apply the commands if they are not applicable. For example, it won't try to increase the volume if it is already at 100%. Some of the functions interface with code that was incorrectly documented in the winamp SDK. This was very painful for us. For example, it is not correctly documented that winamp internally keeps track of equalizer boosts on a scale from 63 to 0, where zero is max (+12dB) and 31 represents "no boost." Equally odd schemes are used for panning and volume, and were also incorrectly documented in the winamp SDK.

The biggest difficulty was simply getting the 2001 project to work-let alone build upon it. Winamp originally refused to interface with the plugin at all. This was the cumulative affect of technology changes (compiler, winamp) since 2001. Here is a sampling of our issues:

A number of our variables and data structures were being overwritten for no apparent reason. We'd set a variable, and it would change itself. Even more peculiar was that debug mode did not produce the error. The reason was that Visual C++ .NET allocates memory differently than older versions of the compiler and it was wiping out a lot of things it shouldn't have. Creative use of typecasting, a windows API memory allocation function, [and a CS major] solved the problem.

The compiler refused to honor the syntax used by the Spring 2001 group to schedule the main task to run every 21ms. We had to research the windows API extensively to figure out how to rewrite the main procedure so it would run.

The initialization function would not run in the original code. We had to add code to "automatically register DllMain, DllRegisterServer and DllUnregisterServer." We believe this is peculiar to the newest version of Visual C++.

It was undocumented that winamp loads plugins differently if they follow certain naming conventions. It took a lot of time to figure out why our plugin sometimes affected winamp's skin selection, etc.

Another big problem: upon careful inspection of the code, you'll notice that there are extensive provisions for visualization features, even though they don't appear on the TV. The vis.h header file is included, and there is code to relay spectrum data to the MCU every so many ms. For a reason we have yet to discover, though, winamp does not recognize the object which provides these features. We imagine it is a compiler / winamp version issue, since our visualization code is similar to that of other plugins. There were many other small problems. What is listed above is merely a sampling. However, the code works quite well now except for the visualization issue. It even implements additional functions not used by the MCU-including all of those listed in the "functionality" section above.