From ec4f175c2b33a9f1269ee8cfd7e7a575de75d4a6 Mon Sep 17 00:00:00 2001 From: cnlohr Date: Sat, 4 Apr 2015 21:19:46 -0400 Subject: [PATCH] Add a lot of documentation, etc. for ColorChord Embedded. --- DFT32.c | 36 +++++++++++------ DFT32.h | 16 +++++--- README.md | 9 ++++- {embeddedx86 => embeddedlinux}/Makefile | 0 {embeddedx86 => embeddedlinux}/embeddedcc.c | 2 +- embeddednf.c | 43 ++++++++++++++------- embeddednf.h | 29 ++++++++------ embeddedout.c | 1 - 8 files changed, 92 insertions(+), 44 deletions(-) rename {embeddedx86 => embeddedlinux}/Makefile (100%) rename {embeddedx86 => embeddedlinux}/embeddedcc.c (99%) diff --git a/DFT32.c b/DFT32.c index ded5ea7..5e5dc8d 100644 --- a/DFT32.c +++ b/DFT32.c @@ -87,13 +87,22 @@ int main() uint16_t Sdatspace32A[FIXBINS*2]; //(advances,places) int32_t Sdatspace32B[FIXBINS*2]; //(isses,icses) + +//This is updated every time the DFT hits the octavecount, or 1/32 updates. int32_t Sdatspace32BOut[FIXBINS*2]; //(isses,icses) -//For +//Sdo_this_octave is a scheduling state for the running SIN/COS states for +//each bin. We have to execute the highest octave every time, however, we can +//get away with updating the next octave down every-other-time, then the next +//one down yet, every-other-time from that one. That way, no matter how many +//octaves we have, we only need to update FIXBPERO*2 DFT bins. static uint8_t Sdo_this_octave[BINCYCLE]; + static int32_t Saccum_octavebins[OCTAVES]; static uint8_t Swhichoctaveplace; -uint16_t embeddedbins[FIXBINS]; //This is updated every time the DFT hits the octavecount, or 1/32 updates. + +// +uint16_t embeddedbins[FIXBINS]; //From: http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2 /** @@ -158,13 +167,22 @@ void UpdateOutputBins32() int octave = i / FIXBPERO; + //If we are running DFT32 on regular ColorChord, then we will need to + //also update goutbins[]... But if we're on embedded systems, we only + //update embeddedbins32. #ifndef CCEMBEDDED uint32_t mux = ( (isps) * (isps)) + ((ispc) * (ispc)); goutbins[i] = sqrtf( (float)mux ); - goutbins[i] /= (78<> octave; } } @@ -182,7 +200,8 @@ static void HandleInt( int16_t sample ) if( oct > 128 ) { //Special: This is when we can update everything. - + //This gets run one out of every 1/(1< 255-(1<>AMP_1_NERFING_BITS) + (this>>(AMP_1_NERFING_BITS-3)); - note_peak_amps2[marked_note] = note_peak_amps2[marked_note] - (note_peak_amps2[marked_note]>>AMP_2_NERFING_BITS) + (this>>(AMP_2_NERFING_BITS-3)); + + note_peak_amps[marked_note] = + note_peak_amps[marked_note] - + (note_peak_amps[marked_note]>>AMP_1_IIR_BITS) + + (this>>(AMP_1_IIR_BITS-3)); + + note_peak_amps2[marked_note] = + note_peak_amps2[marked_note] - + (note_peak_amps2[marked_note]>>AMP_2_IIR_BITS) + + (this>>(AMP_2_IIR_BITS-3)); } } } @@ -310,6 +318,8 @@ void HandleFrameInfo() if( distance < 0 ) distance = -distance; + //If it wraps around above the halfway point, then we're closer to it + //on the other side. if( distance > ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) ) { distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance; @@ -343,23 +353,30 @@ void HandleFrameInfo() uint32_t porp = (amp1<<15) / (amp1+amp2); uint16_t newnote = (nf1 * porp + nf2 * (32768-porp))>>15; + //When combining notes, we have to use the stronger amplitude note. + //trying to average or combine the power of the notes looks awful. note_peak_freqs[into] = newnote; - note_peak_amps[into] = (note_peak_amps[into]>note_peak_amps[from])?note_peak_amps[into]:note_peak_amps[j]; - note_peak_amps2[into] = (note_peak_amps2[into]>note_peak_amps2[from])?note_peak_amps2[into]:note_peak_amps2[j]; + note_peak_amps[into] = (note_peak_amps[into]>note_peak_amps[from])? + note_peak_amps[into]:note_peak_amps[j]; + note_peak_amps2[into] = (note_peak_amps2[into]>note_peak_amps2[from])? + note_peak_amps2[into]:note_peak_amps2[j]; note_peak_freqs[from] = 255; note_peak_amps[from] = 0; note_jumped_to[from] = i; } - + //For al lof the notes that have not been hit, we have to allow them to + //to decay. We only do this for notes that have not found a peak. for( i = 0; i < MAXNOTES; i++ ) { if( note_peak_freqs[i] == 255 || hitnotes[i] ) continue; - note_peak_amps[i] -= note_peak_amps[i]>>AMP_1_NERFING_BITS; - note_peak_amps2[i] -= note_peak_amps2[i]>>AMP_2_NERFING_BITS; + note_peak_amps[i] -= note_peak_amps[i]>>AMP_1_IIR_BITS; + note_peak_amps2[i] -= note_peak_amps2[i]>>AMP_2_IIR_BITS; + //In the event a note is not strong enough anymore, it is to be + //returned back into the great pool of unused notes. if( note_peak_amps[i] < MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR ) { note_peak_freqs[i] = 255; diff --git a/embeddednf.h b/embeddednf.h index 290cb2e..90087f4 100644 --- a/embeddednf.h +++ b/embeddednf.h @@ -19,27 +19,36 @@ //vaporize in one frame doesn't mean it is annihilated immediately. #define MAXNOTES 12 +//We take the raw signal off of the #define FILTER_BLUR_PASSES 2 -//Determines bit shifts for where notes lie. We represent notes with an uint8_t -//We have to define all of the possible locations on the note line in this. -//note_frequency = 0..((1<>1); // ((((65535-renote)>>8) * (uint32_t)(third>>8)) >> 1) + (third<<1); } hue >>= 8; -// printf( "%d;", hue ); return EHSVtoHEX( hue, sat, val ); }