Tears of Rainbow.
Video clips on youtube, arduino is running simple demo application.
Tears of Rainbow BarGraph HD movie " href="//www.youtube.com/watch?v=30ELYwyy4JQ&feature=youtu.be]" target="_blank">BarGraph movie.

It’s time to release new updates for my first (ever) project with Arduino, “Color Light Music”. From artistic perspective, VU BarGraph style (IMHO) is the best one for spectral dynamic representation, and not much could be improved on this side. But this time, it cross my mind an another idea “Tears of Rainbow”. This blog about how successively (or awfully) the idea was brought to life. And of course, VU visual effects still there, updated with nice peak indicators, color adjustment flexibility (this time triple color LEDs), and PWM-ed brightness settings luxury. So, this is design requirements, I was following:
- make it as big as possible, GIGANTIC size !;
- Lego style, or many blocks / modules, which could be re-arranged in different pattern;
- extend-able, easy to add up more blocks later on;
- low price on hardware, no special display driver IC.


Now software part.
There are on-line libraries available, to drive 74HC595 by arduino. Only some of them not using hardware “build-in” SPI interface , and really slow in communication with peripheral IC’s (don’t forget, that LED display only second part of the project, the first one, FFT, is very time consuming). The others libraries, nicely written and perfectly optimized for speed, have too much functionality, that I don’t need in my project, plus they are memory demanding. On the other hand, I need low resolution animation function – sliding down colorful tears, that I have to create on my own. Now I ‘d like to represent a code, very fast SPI subroutines, completely written in C ! Function shift out 9 bytes ( for 9 shift registers in this project ) approximately in less than 36 usec, or 0.5 usec per one PWM channel. One bit-set in the unrolled loop is about 4.5 cycles.
static uint8_t brightn;
brightn++;
if(( brightn % QUANTUMS ) == 0)
{
bitClear(PORTB,LATCH_PB);
SPDR = 0;uint8_t * srP = &brightns[PIN_NBRS];
uint8_t cmp_level = brightn;for (int8_t iSR = 0, curBt = 0; iSR < IC_COUNT ; iSR++, curBt = 0){
if ((* –srP) > cmp_level)
curBt |= 0b00000001;
if ((* –srP) > cmp_level)
curBt |= 0b00000010;
if ((* –srP) > cmp_level)
curBt |= 0b00000100;
if ((* –srP) > cmp_level)
curBt |= 0b00001000;
if ((* –srP) > cmp_level)
curBt |= 0b00010000;
if ((* –srP) > cmp_level)
curBt |= 0b00100000;
if ((* –srP) > cmp_level)
curBt |= 0b01000000;
if ((* –srP) > cmp_level)
curBt |= 0b10000000;loop_until_bit_is_set(SPSR, SPIF);
SPDR = curBt; // Start the transmission
}
loop_until_bit_is_set(SPSR, SPIF);
bitSet(PORTB,LATCH_PB);
}
FFT part of the code completely “copy / pasted” form my “Radix-4″ blog. Here an advise, if you wish to explore the code, look there for “pure” form of function. What is new in this publication, is magnitude calculation subroutine, without slow SQRT.
Bar Graphs “set position” sub-function, or mapping height of lighted area of a plate to integral sum of the bins, brought into this project with mild modification from first project.
Continue moving from LED’s display to audio input, I should say couple words on a sampling. There are two functions in the project, that have to be triggered periodically with a timer, “display refresh” posted above and “take ADC sample”. It looks logically, instead of having two timers and have a lot of troubles with collision / racing between them, to scale both function to the same time frame, and execute them at once. “Display refresh” rate equals to minimum rate just to avoid flickering (60/70 Hz) multiplied by the numbers of brightness level. For example, setting brightness step number to 256 ( which provides excellent 256 x 256 x 256 = 16 M colors ) would require periodicity 60 x 256 = 15360 Hz. See, where I’m driving at? Exactly, 15 kHz is nice frequency to sample audio input!. Well, it’s not 44.1 kHz as default settings Hi-Fi audio standard would recommend, but I ‘m not using all sound data in this project, as I only interested in lower 2 kHz part of the spectrum. And BTW, it’s almost 4x times higher than bear minimum prescribed by sampling theorem (Whittaker–Shannon–Kotelnikov). I’ve made my choice at 15.625 kHz, to simplify math of binary compare to 64. ( 1/64 usec = 15.6 kHz) If there is no big difference, why not pick up “lucky” binary number, and help a Timer to do his job?
Initially, I thought that I would just re-use sampling sub-function from “Pitch Shifting” project, slightly adjusting it from 8.0 to 15.6 kHz. I was surprised to discover, that TIMER2 and SPI don’t want to work together! Have I missed something in a data sheet? Could be, sometimes it’s so hard to comprehend, that I’d be still experimenting with “Blinking Led”, if not help from this (must to have) masterpiece:
O’K, there is TIMER1 available. As project already have been heavily “over-loaded” on software side, I decided to take TimerOne library and not bother myself this time with a bunch of registers, interruptions, masks, etc, leaving this out of the scope, as not related to subject.
FFT size =128 provides extra fine resolution for Color Music performance. BTW, may be it not obvious, but bigger size of FFT has LOWER CPU workload per sample. And last, after everything was melted in one (BIG) sketch nothing happened. No, my arduino can’t catch up at 15.6 kHz. Shifting 9 bytes via SPI, as I mention earlier, takes 36 microseconds. It’s leaving 64 – 36 = 28 microseconds per sample for everything else, or 28 x 128 = 3 584 per frame. Radix-4 (size = 128) takes 4.2 milliseconds, as I posted here. Alright, hell with it, who need 16 M colors on 8 x 3 led display, by the way? So, I bring quantity of brightness steps down to: 256 / 4 = 64, which is more than enough -> 262 144 color combinations! QUANTUMS definition sets coefficient 4 in SPI sub-function. The same time frame rate equals to 122 Hz, which is 2x times higher, than 60 Hz I started my calculation with.
Default color map, or bin’s assignment to a specific plate, is shown above. This time I implemented a command in CLI to make adjustment in this map on the fly, according to music style, equalizing all three bars more or less proportionally. Automatic Gain Control loop implemented in first project, doesn’t work so great with bigger display size ( first project uses 4 lines per color ). Plus, AGC bringing noise in the visual performance in pauses between two songs and in quite fragments of the music. Starting bin position for each RGB plate could not be changed using CLI ( you still can do this modifying the scetch), but quantity of bins accumulated per plate could be adjusted simply sending “dr” for red, “dg” – for green, and “db” - for blue, where d is a digit 0..9. Bands could over-lap, which is not desirable, in this case red is limited too 0..3, green 0..6, and blue 0..9.
More on the audio input hardware and sampling software subroutine, I post in separate blog, as this part follows w/o much modification thorough a few previous blogs, and doesn’t need to be re-stated here.
*Note: in software G.VU is not implemented yet.
Link to download a sketch: Tears_of_Rainbow.
