337 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			337 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "embeddedout.h"
 | 
						|
 | 
						|
//uint8_t ledArray[NUM_LIN_LEDS]; //Points to which notes correspond to these LEDs
 | 
						|
uint8_t ledOut[NUM_LIN_LEDS*3];
 | 
						|
 | 
						|
uint16_t ledSpin;
 | 
						|
uint16_t ledAmpOut[NUM_LIN_LEDS];
 | 
						|
uint8_t ledFreqOut[NUM_LIN_LEDS];
 | 
						|
uint8_t ledFreqOutOld[NUM_LIN_LEDS];
 | 
						|
 | 
						|
uint8_t RootNoteOffset;
 | 
						|
 | 
						|
void UpdateLinearLEDs()
 | 
						|
{
 | 
						|
	//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;
 | 
						|
	int8_t k;
 | 
						|
	uint16_t j, l;
 | 
						|
	uint32_t total_size_all_notes = 0;
 | 
						|
	int32_t porpamps[MAXNOTES]; //LEDs for each corresponding note.
 | 
						|
	uint8_t sorted_note_map[MAXNOTES]; //mapping from which note into the array of notes from the rest of the system.
 | 
						|
	uint8_t sorted_map_count = 0;
 | 
						|
	uint32_t note_nerf_a = 0;
 | 
						|
 | 
						|
	for( i = 0; i < MAXNOTES; i++ )
 | 
						|
	{
 | 
						|
		if( note_peak_freqs[i] == 255 ) continue;
 | 
						|
		note_nerf_a += note_peak_amps[i];
 | 
						|
	}
 | 
						|
 | 
						|
	note_nerf_a = ((note_nerf_a * NERF_NOTE_PORP)>>8);
 | 
						|
 | 
						|
 | 
						|
	for( i = 0; i < MAXNOTES; i++ )
 | 
						|
	{
 | 
						|
		uint16_t ist = note_peak_amps[i];
 | 
						|
		uint8_t nff = note_peak_freqs[i];
 | 
						|
		if( nff == 255 )
 | 
						|
		{
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if( ist < note_nerf_a )
 | 
						|
		{
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
#if SORT_NOTES
 | 
						|
		for( j = 0; j < sorted_map_count; j++ )
 | 
						|
		{
 | 
						|
			if( note_peak_freqs[ sorted_note_map[j] ] > nff )
 | 
						|
			{
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		for( k = sorted_map_count; k > j; k-- )
 | 
						|
		{
 | 
						|
			sorted_note_map[k] = sorted_note_map[k-1];
 | 
						|
		}
 | 
						|
		sorted_note_map[j] = i;
 | 
						|
#else
 | 
						|
#endif
 | 
						|
		sorted_note_map[sorted_map_count] = i;
 | 
						|
		sorted_map_count++;
 | 
						|
	}
 | 
						|
 | 
						|
#if 0
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		printf( "%d: %d: %d /", sorted_note_map[i],  note_peak_freqs[sorted_note_map[i]], note_peak_amps[sorted_note_map[i]] );
 | 
						|
	}
 | 
						|
	printf( "\n" );
 | 
						|
#endif
 | 
						|
 | 
						|
	uint16_t local_peak_amps[MAXNOTES];
 | 
						|
	uint16_t local_peak_amps2[MAXNOTES];
 | 
						|
	uint8_t  local_peak_freq[MAXNOTES];
 | 
						|
 | 
						|
	//Make a copy of all of the variables into local ones so we don't have to keep double-dereferencing.
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		//printf( "%5d ", local_peak_amps[i] );
 | 
						|
		local_peak_amps[i] = note_peak_amps[sorted_note_map[i]] - note_nerf_a;
 | 
						|
		local_peak_amps2[i] = note_peak_amps2[sorted_note_map[i]];
 | 
						|
		local_peak_freq[i] = note_peak_freqs[sorted_note_map[i]];
 | 
						|
//		printf( "%5d ", local_peak_amps[i] );
 | 
						|
	}
 | 
						|
//	printf( "\n" );
 | 
						|
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		uint16_t ist = local_peak_amps[i];
 | 
						|
		porpamps[i] = 0;
 | 
						|
		total_size_all_notes += local_peak_amps[i];
 | 
						|
	}
 | 
						|
 | 
						|
	if( total_size_all_notes == 0 )
 | 
						|
	{
 | 
						|
		for( j = 0; j < NUM_LIN_LEDS * 3; j++ )
 | 
						|
		{
 | 
						|
			ledOut[j] = 0;
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	uint32_t porportional = (uint32_t)(NUM_LIN_LEDS<<16)/((uint32_t)total_size_all_notes);
 | 
						|
 | 
						|
	uint16_t total_accounted_leds = 0;
 | 
						|
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		porpamps[i] = (local_peak_amps[i] * porportional) >> 16;
 | 
						|
		total_accounted_leds += porpamps[i];
 | 
						|
	}
 | 
						|
 | 
						|
	int16_t total_unaccounted_leds = NUM_LIN_LEDS - total_accounted_leds;
 | 
						|
 | 
						|
	int addedlast = 1;
 | 
						|
	do
 | 
						|
	{
 | 
						|
		for( i = 0; i < sorted_map_count && total_unaccounted_leds; i++ )
 | 
						|
		{
 | 
						|
			porpamps[i]++; total_unaccounted_leds--;
 | 
						|
			addedlast = 1;
 | 
						|
		}
 | 
						|
	} while( addedlast && total_unaccounted_leds );
 | 
						|
 | 
						|
	//Put the frequencies on a ring.
 | 
						|
	j = 0;
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		while( porpamps[i] > 0 )
 | 
						|
		{
 | 
						|
			ledFreqOut[j] = local_peak_freq[i];
 | 
						|
			ledAmpOut[j] = (local_peak_amps2[i]*NOTE_FINAL_AMP)>>8;
 | 
						|
			j++;
 | 
						|
			porpamps[i]--;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	//This part totally can't run on an embedded system.
 | 
						|
#if LIN_WRAPAROUND
 | 
						|
	uint16_t midx = 0;
 | 
						|
	uint32_t mqty = 100000000;
 | 
						|
	for( j = 0; j < NUM_LIN_LEDS; j++ )
 | 
						|
	{
 | 
						|
		uint32_t dqty;
 | 
						|
		uint16_t localj;
 | 
						|
 | 
						|
		dqty = 0;
 | 
						|
		localj = j;
 | 
						|
		for( l = 0; l < NUM_LIN_LEDS; l++ )
 | 
						|
		{
 | 
						|
			int32_t d = (int32_t)ledFreqOut[localj] - (int32_t)ledFreqOutOld[l];
 | 
						|
			if( d < 0 ) d *= -1;
 | 
						|
			if( d > (NOTERANGE>>1) ) { d = NOTERANGE - d + 1; }
 | 
						|
			dqty += ( d * d );
 | 
						|
 | 
						|
			localj++;
 | 
						|
			if( localj == NUM_LIN_LEDS ) localj = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		if( dqty < mqty )
 | 
						|
		{
 | 
						|
			mqty = dqty;
 | 
						|
			midx = j;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ledSpin = midx;
 | 
						|
 | 
						|
#else
 | 
						|
	ledSpin = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
	j = ledSpin;
 | 
						|
	for( l = 0; l < NUM_LIN_LEDS; l++, j++ )
 | 
						|
	{
 | 
						|
		if( j >= NUM_LIN_LEDS ) j = 0;
 | 
						|
		ledFreqOutOld[l] = ledFreqOut[j];
 | 
						|
 | 
						|
		uint16_t amp = ledAmpOut[j];
 | 
						|
		if( amp > 255 ) amp = 255;
 | 
						|
		uint32_t color = ECCtoHEX( (ledFreqOut[j]+RootNoteOffset)%NOTERANGE, 255, amp );
 | 
						|
		ledOut[l*3+0] = ( color >> 0 ) & 0xff;
 | 
						|
		ledOut[l*3+1] = ( color >> 8 ) & 0xff;
 | 
						|
		ledOut[l*3+2] = ( color >>16 ) & 0xff;
 | 
						|
	}
 | 
						|
/*	j = ledSpin;
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		while( porpamps[i] > 0 )
 | 
						|
		{
 | 
						|
			uint16_t amp = ((uint32_t)local_peak_amps2[i] * NOTE_FINAL_AMP) >> 8;
 | 
						|
			if( amp > 255 ) amp = 255;
 | 
						|
			uint32_t color = ECCtoHEX( local_peak_freq[i], 255, amp );
 | 
						|
			ledOut[j*3+0] = ( color >> 0 ) & 0xff;
 | 
						|
			ledOut[j*3+1] = ( color >> 8 ) & 0xff;
 | 
						|
			ledOut[j*3+2] = ( color >>16 ) & 0xff;
 | 
						|
 | 
						|
			j++;
 | 
						|
			if( j == NUM_LIN_LEDS ) j = 0;
 | 
						|
			porpamps[i]--;
 | 
						|
		}
 | 
						|
	}*/
 | 
						|
 | 
						|
	//Now, we use porpamps to march through the LEDs, coloring them.
 | 
						|
/*	j = 0;
 | 
						|
	for( i = 0; i < sorted_map_count; i++ )
 | 
						|
	{
 | 
						|
		while( porpamps[i] > 0 )
 | 
						|
		{
 | 
						|
			uint16_t amp = ((uint32_t)local_peak_amps2[i] * NOTE_FINAL_AMP) >> 8;
 | 
						|
			if( amp > 255 ) amp = 255;
 | 
						|
			uint32_t color = ECCtoHEX( local_peak_freq[i], 255, amp );
 | 
						|
			ledOut[j*3+0] = ( color >> 0 ) & 0xff;
 | 
						|
			ledOut[j*3+1] = ( color >> 8 ) & 0xff;
 | 
						|
			ledOut[j*3+2] = ( color >>16 ) & 0xff;
 | 
						|
 | 
						|
			j++;
 | 
						|
			porpamps[i]--;
 | 
						|
		}
 | 
						|
	}*/
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val )
 | 
						|
{
 | 
						|
	uint16_t hue = 0;
 | 
						|
	uint16_t third = 65535/3;
 | 
						|
	uint16_t scalednote = note;
 | 
						|
	uint32_t renote = ((uint32_t)note * 65536) / 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( renote < (third<<1) )
 | 
						|
	{
 | 
						|
		//Red to Blue
 | 
						|
		hue = (third-renote);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		//hue = ((((65535-renote)>>8) * (uint32_t)(third>>8)) >> 1) + (third<<1);
 | 
						|
		hue = (uint16_t)(((uint32_t)(65536-renote)<<16) / (third<<1)) + (third>>1); // ((((65535-renote)>>8) * (uint32_t)(third>>8)) >> 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 -= SIXTH1; //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);
 | 
						|
	og = og * rs + 255 * (256-rs);
 | 
						|
	ob = ob * rs + 255 * (256-rs);
 | 
						|
//printf( "__%d %d %d =-> %d\n", or, og, ob, rs );
 | 
						|
 | 
						|
	or >>= 8;
 | 
						|
	og >>= 8;
 | 
						|
	ob >>= 8;
 | 
						|
 | 
						|
	return or | (og<<8) | ((uint32_t)ob<<16);
 | 
						|
}
 | 
						|
 |