Let's be honest, last week post about USB Christmas tree was a bit lame. It was fun to blink all these color leds, but that was a lot of Yocto-Color devices to connect for a result very similar to a $10 ornament you would buy from the nearest hardware store. So we decided to improve the concept.
We will not modify the tree. The goal of the improvement is to play music and make the tree illuminate itself according to the music. Usually, to do such a thing, we would have to capture the music stream and compute a Fourier transform on it. This is not the kind of stuff that you can do in a matter of minutes. So we have chosen a different approach: we will leverage Winamp. Winamp is a media-player like many others, but it's quite easy to create visualization plug-ins for it.
Let's improve the USB Christmas tree concept...
We will create this plug-in using Delphi, starting from Jan Horn's work. He wrote a nice tutorial explaining how to create a visualization plug-in for Winamp with Delphi. To make it simple: while playing music, Winamp computes the Fourier transform and sends amplitude values for each frequency band to the plug-in on a regular basis. The plug-in only has to use this data to refresh its window. In our case, in addition of to refreshing the window, we will drive the Yocto-Color leds according to the data sent by Winamp. Each frequency band will be given a color and a few RGB leds.
Once again the code specific to the Yoctopuce hardware is quite short. There are 2 important parts: the first one is related to the plug-in initialization: we need to make the inventory of connected RGB leds.
function InitYoctoLeds() :boolean;
// init yoctopuce API
if (yRegisterHub('usb', errmsg)<>YAPI_SUCCESS) then
MessageBox(0,pchar(errmsg), 'Error', MB_OK or MB_ICONERROR);
yDisableExceptions(); // no exceptions, thank you
// enumerate all leds, we store all leds objects in a list
led := yFirstColorLed();
while (led<>nil) do
And when Winamp calls us for an UI refresh, we compute colors and set the leds, that's it.
colors are computed and stored in the array color[0..ColorsCount];
UI is refreshed, lets handle the leds.
for j:=0 to 1 do
i:=j; // first even indexes then odd ones
while (i<leds.count) do
TYcolorLed(leds[i]).set_HslColor( color [i mod ColorsCount] );
There is one subtlety however. When a command is sent to a Yoctopuce device, it will stay busy for a few milliseconds. It is still possible to send new commands to it, but following calls will be blocking until the module is idle again. Since there are two leds per module, the command for the second led will have to wait until the first one is processed. For most applications this is not an issue, but in our case we want to go as fast as possible to synchronize all leds. So we will set leds with an even index first, then the ones with an odd index. This interleaves calls and avoids wasting time waiting. In this way, we can refresh the 22 leds on our Christmas tree within 30ms approximately.
Ok, this is not the prettiest UI, but that was not the point.
And here is a video of the result. Better than a $10 ornament, isn't it?