diff --git a/embeddedout.c b/embeddedout.c new file mode 100644 index 0000000..807b57b --- /dev/null +++ b/embeddedout.c @@ -0,0 +1,236 @@ +#include "embeddedout.h" + +//uint8_t ledArray[NUM_LIN_LEDS]; //Points to which notes correspond to these LEDs +uint8_t ledOut[NUM_LIN_LEDS*3]; + +void UpdateLinear() +{ + //Source material: + /* + extern uint8_t note_peak_freqs[]; + extern uint16_t note_peak_amps[]; //[MAXNOTES] + extern uint16_t note_peak_amps2[]; //[MAXNOTES] (Responds quicker) + extern uint8_t note_jumped_to[]; //[MAXNOTES] When a note combines into another one, + */ + + //Goal: Make splotches of light that are porportional to the strength of notes. + //Color them according to value in note_peak_amps2. + + uint8_t i; + uint16_t j; + uint32_t total_size_all_notes = 0; + uint16_t porpamps[MAXNOTES]; //LEDs for each corresponding note. + + for( i = 0; i < MAXNOTES; i++ ) + { + porpamps[i] = 0; + if( note_peak_freqs[i] == 255 ) continue; + total_size_all_notes += note_peak_amps[i]; + } + + uint32_t porportional = (total_size_for_all_notes << 8) / NUM_LIN_LEDS; + + uint16_t total_accounted_leds = 0; + + for( i = 0; i < MAXNOTES; i++ ) + { + if( note_peak_freqs[i] == 255 ) continue; + porpamps[i] = (note_peak_amps[i] * porportional) >> 8; + total_accounted_leds += porpamps[i]; + } + + uint16_t total_unaccounted_leds = NUM_LIN_LEDS - total_accounted_leds; + + for( i = 0; i < MAXNOTES, total_unaccounted_leds; i++ ) + { + if( note_peak_freqs[i] == 255 ) continue; + porpamps[i]++; + } + + //Now, we use porpamps to march through the LEDs, coloring them. + j = 0; + for( i = 0; i < MAXNOTES; i++ ) + { + while( porpamps[i] ) + { + uint16_t amp = note_peak_amps2[i]; + if( amp > 255 ) amp = 255; + uint32_t color = ECCtoHEX( note_peak_freqs[i], 255, amp ); + ledOut[i*3+0] = ( color >> 0 ) & 0xff; + ledOut[i*3+1] = ( color >> 8 ) & 0xff; + ledOut[i*3+2] = ( color >>16 ) & 0xff; + j++; + porpamps[i]--; + } + } +} + + +uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val ) +{ + uint16_t hue = 0; + uint8_t third = 65535/3; + uint16_t scalednote = note + uint16_t renote = ((uint32_t)note * 65535) / NOTERANGE; + + //Note is expected to be a vale from 0..(NOTERANGE-1) + //renote goes from 0 to the next one under 65536. + + if( renote < third ) + { + //Yellow to Red. + hue = (third - renote) >> 1; + } + else if( note < (third>>1) ) + { + //Red to Blue + hue = (third-renote); + } + else + { + hue = (((65535-renote) * third) >> 1) + (third>>1); + } + + hue >>= 8; + return EHSVtoHEX( hue, sat, val ); +} + +uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val ) +{ +#define SIXTH1 43 +#define SIXTH2 85 +#define SIXTH3 128 +#define SIXTH4 171 +#define SIXTH5 213 + + uint16_t or = 0, og = 0, ob = 0; + + hue += SIXTH2; //Off by 60 degrees. + + //TODO: There are colors that overlap here, consider + //tweaking this to make the best use of the colorspace. + + if( hue < SIXTH1 ) //Ok: Yellow->Red. + { + or = 255; + og = 255 - ((uint16_t)hue * 255) / (SIXTH1); + } + else if( hue < SIXTH2 ) //Ok: Red->Purple + { + or = 255; + ob = (uint16_t)hue*255 / SIXTH1 - 255; + } + else if( hue < SIXTH3 ) //Ok: Purple->Blue + { + ob = 255; + or = ((SIXTH3-hue) * 255) / (SIXTH1); + } + else if( hue < SIXTH4 ) //Ok: Blue->Cyan + { + ob = 255; + og = (hue - SIXTH3)*255 / SIXTH1; + } + else if( hue < SIXTH5 ) //Ok: Cyan->Green. + { + og = 255; + ob = ((SIXTH5-hue)*255) / SIXTH1; + } + else //Green->Yellow + { + og = 255; + or = (hue - SIXTH5) * 255 / SIXTH1; + } + + uint16_t rv = val; + if( rv > 128 ) rv++; + uint16_t rs = sat; + if( rs > 128 ) rs++; + + //or, og, ob range from 0...255 now. + //Need to apply saturation and value. + + or = (or * val)>>8; + og = (og * val)>>8; + ob = (ob * val)>>8; + + //OR..OB == 0..65025 + or = or * rs + 255 * (256-rs); + or = or * rs + 255 * (256-rs); + or = or * rs + 255 * (256-rs); + + or >>= 8; + og >>= 8; + ob >>= 8; + return or | (og<<8) | (ob<<16); +} + +uint32_t HSVtoHEX( float hue, float sat, float value ) +{ + + float pr = 0; + float pg = 0; + float pb = 0; + + short ora = 0; + short og = 0; + short ob = 0; + + float ro = fmod( hue * 6, 6. ); + + float avg = 0; + + ro = fmod( ro + 6 + 1, 6 ); //Hue was 60* off... + + if( ro < 1 ) //yellow->red + { + pr = 1; + pg = 1. - ro; + } else if( ro < 2 ) + { + pr = 1; + pb = ro - 1.; + } else if( ro < 3 ) + { + pr = 3. - ro; + pb = 1; + } else if( ro < 4 ) + { + pb = 1; + pg = ro - 3; + } else if( ro < 5 ) + { + pb = 5 - ro; + pg = 1; + } else + { + pg = 1; + pr = ro - 5; + } + + //Actually, above math is backwards, oops! + pr *= value; + pg *= value; + pb *= value; + + avg += pr; + avg += pg; + avg += pb; + + pr = pr * sat + avg * (1.-sat); + pg = pg * sat + avg * (1.-sat); + pb = pb * sat + avg * (1.-sat); + + ora = pr * 255; + og = pb * 255; + ob = pg * 255; + + if( ora < 0 ) ora = 0; + if( ora > 255 ) ora = 255; + if( og < 0 ) og = 0; + if( og > 255 ) og = 255; + if( ob < 0 ) ob = 0; + if( ob > 255 ) ob = 255; + + return (ob<<16) | (og<<8) | ora; +} + diff --git a/embeddedout.h b/embeddedout.h new file mode 100644 index 0000000..54d1050 --- /dev/null +++ b/embeddedout.h @@ -0,0 +1,19 @@ +#ifndef _EMBEDDEDOUT_H +#define _EMBEDDEDOUT_H + +#include "embeddednf.h" + +#define NUM_LIN_LEDS 296 + +#define LIN_WRAPAROUND 0 //Whether the output lights wrap around. (TODO) + +extern uint8_t ledArray[]; +extern uint8_t ledOut[]; //[NUM_LIN_LEDS*3] +void UpdateLinear(); + +uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val ); +uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val ); //hue = 0..255 // TODO: TEST ME!!! + + +#endif +