okay, things are moving along quite well. Almost ready for my first test.

This commit is contained in:
cnlohr 2015-04-01 22:59:12 -04:00
parent 6d75249cb8
commit 09be0f349b
6 changed files with 406 additions and 98 deletions

View file

@ -16,7 +16,7 @@ EXTRALIBS:=-lusb-1.0
colorchord : os_generic.o main.o dft.o decompose.o filter.o color.o sort.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o
gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS)
embeddedcc : os_generic.c embeddedcc.c dft.c
embeddedcc : os_generic.c embeddedcc.c dft.c embeddednf.c
gcc -o $@ $^ $(CFLAGS) -DCCEMBEDDED $(LDFLAGS) $(EXTRALIBS) $(RAWDRAWLIBS)
runembedded : embeddedcc

4
dft.c
View file

@ -559,13 +559,13 @@ void HandleProgressiveIntSkippy( int8_t sample1 )
//Add TS and TC to the datspace stuff. (24 instructions)
tmp1 = (*ds); //Read out, sin component. 4 Accurate.
// tmp1 -= tmp1>>4; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += ts>>4; //Add MSBs with carry 2 -> 6 AS/IS: 6
tmp1 += ts>>SHIFT_ADD_DETAIL; //Add MSBs with carry 2 -> 6 AS/IS: 6
*(ds++) = tmp1; //Store values back 4
tmp1 = *ds; //Read out, sin component. 4
// tmp1 -= tmp1>>4; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += tc>>4; //Add MSBs with carry 2 -> 6 AS/IS: 6
tmp1 += tc>>SHIFT_ADD_DETAIL; //Add MSBs with carry 2 -> 6 AS/IS: 6
*ds++ = tmp1; //Store values back 4

7
dft.h
View file

@ -56,6 +56,13 @@ void Push8BitIntegerSkippy( int8_t dat ); //Call this to push on new frames of s
#define FIXBINS (FIXBPERO*OCTAVES)
#define BINCYCLE (1<<OCTAVES)
//This variable determins how much to nerf the current sample of the DFT.
//I've found issues when this is smaller, but bigger values do have a negative
//impact on quality. We should strongly consider using 32-bit accumulators.
#ifndef SHIFT_ADD_DETAIL
#define SHIFT_ADD_DETAIL 5
#endif
//Whenever you need to read the bins, you can do it from here.
extern uint16_t Sdatspace[]; //(advances,places,isses,icses)
extern uint16_t embeddedbins[]; //This is updated every time the DFT hits the octavecount, or 1/32 updates.

View file

@ -4,102 +4,8 @@
//
#include <stdio.h>
#include "embeddednf.h"
#include "dft.h"
#define DFREQ 8000
#define BASE_FREQ 55.0
const float bf_table[24] = {
1.000000, 1.029302, 1.059463, 1.090508, 1.122462, 1.155353,
1.189207, 1.224054, 1.259921, 1.296840, 1.334840, 1.373954,
1.414214, 1.455653, 1.498307, 1.542211, 1.587401, 1.633915,
1.681793, 1.731073, 1.781797, 1.834008, 1.887749, 1.943064 };
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
/* The above table was generated using the following code:
#include <stdio.h>
#include <math.h>
int main()
{
int i;
#define FIXBPERO 24
printf( "const float bf_table[%d] = {", FIXBPERO );
for( i = 0; i < FIXBPERO; i++ )
{
if( ( i % 6 ) == 0 )
printf( "\n\t" );
printf( "%f, ", pow( 2, (float)i / (float)FIXBPERO ) );
}
printf( "};\n" );
return 0;
}
*/
void UpdateFreqs()
{
uint16_t fbins[FIXBPERO];
int i;
BUILD_BUG_ON( sizeof(bf_table) != FIXBPERO*4 );
for( i = 0; i < FIXBPERO; i++ )
{
float frq = ( bf_table[i] * BASE_FREQ );
fbins[i] = ( 65536.0 ) / ( DFREQ ) * frq * 16;
}
UpdateBinsForProgressiveIntegerSkippyInt( fbins );
}
void Init()
{
//Step 1: Initialize the Integer DFT.
SetupDFTProgressiveIntegerSkippy();
//Step 2: Set up the frequency list.
UpdateFreqs();
}
void HandleFrameInfo()
{
uint16_t folded_bins[FIXBPERO];
int i, j, k = 0;
for( i = 0; i < FIXBPERO; i++ )
folded_bins[i] = 0;
for( j = 0; j < OCTAVES; j++ )
{
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] += embeddedbins[k++];
}
}
//XXX TODO Taper the first and last octaves.
// for( i = 0; i < freqbins; i++ )
// {
// nf->outbins[i] *= (i+1.0)/nf->freqbins;
// }
// for( i = 0; i < freqbins; i++ )
// {
// nf->outbins[freqs-i-1] *= (i+1.0)/nf->freqbins;
// }
//We now have the system folded into one
for( i = 0; i < FIXBPERO; i++ )
{
printf( "%5d ", folded_bins[i] );
}
printf( "\n" );
}
int main()
{

342
embeddednf.c Normal file
View file

@ -0,0 +1,342 @@
#include "embeddednf.h"
#include <stdio.h>
uint16_t folded_bins[FIXBPERO];
uint16_t fuzzed_bins[FIXBINS];
uint8_t note_peak_freqs[MAXNOTES];
uint16_t note_peak_amps[MAXNOTES];
uint16_t note_peak_amps2[MAXNOTES];
static const float bf_table[24] = {
1.000000, 1.029302, 1.059463, 1.090508, 1.122462, 1.155353,
1.189207, 1.224054, 1.259921, 1.296840, 1.334840, 1.373954,
1.414214, 1.455653, 1.498307, 1.542211, 1.587401, 1.633915,
1.681793, 1.731073, 1.781797, 1.834008, 1.887749, 1.943064 };
/* The above table was generated using the following code:
#include <stdio.h>
#include <math.h>
int main()
{
int i;
#define FIXBPERO 24
printf( "const float bf_table[%d] = {", FIXBPERO );
for( i = 0; i < FIXBPERO; i++ )
{
if( ( i % 6 ) == 0 )
printf( "\n\t" );
printf( "%f, ", pow( 2, (float)i / (float)FIXBPERO ) );
}
printf( "};\n" );
return 0;
}
*/
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
void UpdateFreqs()
{
uint16_t fbins[FIXBPERO];
int i;
BUILD_BUG_ON( sizeof(bf_table) != FIXBPERO*4 );
//Warning: This does floating point. Avoid doing this frequently. If you
//absolutely cannot have floating point on your system, you may precompute
//this and store it as a table. It does preclude you from changing
//BASE_FREQ in runtime.
for( i = 0; i < FIXBPERO; i++ )
{
float frq = ( bf_table[i] * BASE_FREQ );
fbins[i] = ( 65536.0 ) / ( DFREQ ) * frq * 16;
}
UpdateBinsForProgressiveIntegerSkippyInt( fbins );
}
void Init()
{
int i;
//Set up and initialize arrays.
for( i = 0; i < MAXNOTES; i++ )
{
note_peak_freqs[i] = 255;
note_peak_amps[i] = 0;
note_peak_amps2[i] = 0;
}
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] = 0;
}
for( i = 0; i < FIXBINS; i++ )
{
fuzzed_bins[i] = 0;
}
//Step 1: Initialize the Integer DFT.
SetupDFTProgressiveIntegerSkippy();
//Step 2: Set up the frequency list. You could do this multiple times
//if you want to change the loadout of the frequencies.
UpdateFreqs();
}
void HandleFrameInfo()
{
int i, j, k;
//Copy out the bins from the DFT to our fuzzed bins.
for( i = 0; i < FIXBINS; i++ )
{
fuzzed_bins[i] = (fuzzed_bins[i] + (embeddedbins[i]>>FUZZ_IIR_BITS) -
(fuzzed_bins[i]>>FUZZ_IIR_BITS));
}
//Taper first octave
for( i = 0; i < FIXBPERO; i++ )
{
uint32_t taperamt = (65536 / FIXBPERO) * i;
fuzzed_bins[i] = (taperamt * fuzzed_bins[i]) >> 16;
}
//Taper last octave
for( i = 0; i < FIXBPERO; i++ )
{
int newi = FIXBINS - i - 1;
uint32_t taperamt = (65536 / FIXBPERO) * i;
fuzzed_bins[newi] = (taperamt * fuzzed_bins[newi]) >> 16;
}
//Fold the bins from fuzzedbins into one octave.
for( i = 0; i < FIXBPERO; i++ )
folded_bins[i] = 0;
k = 0;
for( j = 0; j < OCTAVES; j++ )
{
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] += fuzzed_bins[k++];
}
}
//Now, we must blur the folded bins to get a good result.
//Sometimes you may notice every other bin being out-of
//line, and this fixes that. We may consider running this
//more than once, but in my experience, once is enough.
{
//Extra scoping because this is a large on-stack buffer.
uint16_t folded_out[FIXBPERO];
uint8_t adjLeft = FIXBPERO-1;
uint8_t adjRight = 1;
for( i = 0; i < FIXBPERO; i++ )
{
uint16_t lbin = folded_bins[adjLeft]>>2;
uint16_t rbin = folded_bins[adjRight]>>2;
uint16_t tbin = folded_bins[i]>>1;
folded_out[i] = lbin + rbin + tbin;
//We do this funny dance to avoid a modulus operation. On some
//processors, a modulus operation is slow. This is cheap.
adjLeft++; if( adjLeft == FIXBPERO ) adjLeft = 0;
adjRight++; if( adjRight == FIXBPERO ) adjRight = 0;
}
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] = folded_out[i];
}
}
//Next, we have to find the peaks, this is what "decompose" does in our
//normal tool. As a warning, it expects that the values in foolded_bins
//do NOT exceed 32767.
{
uint8_t adjLeft = FIXBPERO-1;
uint8_t adjRight = 1;
for( i = 0; i < FIXBPERO; i++ )
{
int16_t prev = folded_bins[adjLeft];
int16_t next = folded_bins[adjRight];
int16_t this = folded_bins[i];
uint8_t thisfreq = i<<SEMIBITSPERBIN;
int16_t offset;
adjLeft++; if( adjLeft == FIXBPERO ) adjLeft = 0;
adjRight++; if( adjRight == FIXBPERO ) adjRight = 0;
if( this < MIN_AMP_FOR_NOTE ) continue;
if( prev > this || next > this ) continue;
if( prev == this && next == this ) continue;
//i is at a peak...
int32_t totaldiff = (( this - prev ) + ( this - next ));
int32_t porpdiffP = ((this-prev)<<16) / totaldiff; //close to 0 =
//closer to this side, 32768 = in the middle, 65535 away.
int32_t porpdiffN = ((this-next)<<16) / totaldiff;
if( porpdiffP < porpdiffN )
{
//Closer to prev.
offset = -(32768 - porpdiffP);
}
else
{
//Closer to next
offset = (32768 - porpdiffN);
}
//Need to round. That's what that extra +(15.. is in the center.
thisfreq += (offset+(1<<(15-SEMIBITSPERBIN)))>>(16-SEMIBITSPERBIN);
//In the event we went 'below zero' need to wrap to the top.
if( thisfreq > 255-(1<<SEMIBITSPERBIN) )
thisfreq = (1<<SEMIBITSPERBIN)*FIXBPERO - (256-thisfreq);
//printf( "Peak At: %3d /(%2d) %4d/%4d/%4d\n", thisfreq, i,prev, this, next );
//Okay, we have a peak, and a frequency. Now, we need to search
//through the existing notes to see if we have any matches.
//If we have a note that's close enough, we will try to pull it
//closer to us and boost it.
int8_t lowest_found_free_note = -1;
int8_t closest_note_id = -1;
int16_t closest_note_distance = 32767;
for( j = 0; j < MAXNOTES; j++ )
{
uint8_t nf = note_peak_freqs[j];
if( nf == 255 )
{
if( lowest_found_free_note == -1 )
lowest_found_free_note = j;
continue;
}
int16_t distance = thisfreq - nf;
if( distance < 0 ) distance = -distance;
//Make sure that if we've wrapped around the right side of the
//array, we can detect it and loop it back.
if( distance > ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) )
{
distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance;
}
if( distance < closest_note_distance )
{
closest_note_id = j;
closest_note_distance = distance;
}
}
int8_t marked_note = -1;
if( closest_note_distance <= MAX_JUMP_DISTANCE )
{
//We found the note we need to augment.
//XXX: TODO: Should we be IIRing this?
note_peak_freqs[closest_note_id] = thisfreq;
marked_note = closest_note_id;
}
//The note was not found.
else if( lowest_found_free_note != -1 )
{
note_peak_freqs[lowest_found_free_note] = thisfreq;
marked_note = lowest_found_free_note;
}
if( marked_note != -1 )
{
if( note_peak_amps[marked_note] <= this )
note_peak_amps[marked_note] = this;
if( note_peak_amps2[marked_note] <= this )
note_peak_amps2[marked_note] = this;
}
}
}
//Now we need to handle combining notes.
for( i = 0; i < MAXNOTES; i++ )
for( j = 0; j < i; j++ )
{
//We'd be combining nf2 (j) into nf1 (i) if they're close enough.
uint8_t nf1 = note_peak_freqs[i];
uint8_t nf2 = note_peak_freqs[j];
int16_t distance = nf1 - nf2;
if( nf1 == 255 || nf2 == 255 ) continue;
if( distance < 0 ) distance = -distance;
if( distance > ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) )
{
distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance;
}
if( distance > MAX_JUMP_DISTANCE * 2 )
{
continue;
}
//We need to combine the notes. We need to move the new note freq
//towards the stronger of the two notes.
int16_t amp1 = note_peak_amps[i];
int16_t amp2 = note_peak_amps[j];
//0 to 32768 porportional to how much of amp1 we want.
uint32_t porp = (amp1<<15) / (amp1+amp2);
uint16_t newnote = (nf1 * porp + nf2 * (32768-porp))>>15;
note_peak_amps[i] = amp1 + amp2;
note_peak_amps[j] = 0;
note_peak_freqs[i] = newnote;
note_peak_freqs[j] = 255;
note_peak_amps2[i] += note_peak_amps2[j];
}
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 ) 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;
if( note_peak_amps[i] < MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR )
{
note_peak_freqs[i] = 255;
note_peak_amps[i] = 0;
note_peak_amps2[i] = 0;
}
}
//We now have notes!!!
/*
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 ) continue;
printf( "(%3d %4d %4d) ", note_peak_freqs[i], note_peak_amps[i], note_peak_amps2[i] );
}
printf( "\n") ;
*/
/*
for( i = 0; i < FIXBPERO; i++ )
{
printf( "%5d ", folded_bins[i] );
}
printf( "\n" );*/
}

53
embeddednf.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef _EMBEDDEDNF_H
#define _EMBEDDEDNF_H
#include "dft.h"
#define DFREQ 8000
#define BASE_FREQ 55.0 // You may make this a float.
//The higher the number the slackier your FFT will be come.
#define FUZZ_IIR_BITS 1
//Notes are the individually identifiable notes we receive from the sound.
//We track up to this many at one time. Just because a note may appear to
//vaporize in one frame doesn't mean it is annihilated immediately.
#define MAXNOTES 10
//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<<SEMIBITSPERBIN)*FIXBPERO-1)
#define SEMIBITSPERBIN 3
//This is the amplitude, coming from folded_bins. If the value is below this
//it is considered a non-note.
#define MIN_AMP_FOR_NOTE 128
//If there is detected note this far away from an established note, we will
//then consider this new note the same one as last time, and move the established
//note. This is also used when combining notes. It is this distance times two.
#define MAX_JUMP_DISTANCE 7
#define MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR 64
#define AMP_1_NERFING_BITS 5
#define AMP_2_NERFING_BITS 3
extern uint16_t folded_bins[]; //[FIXBPERO] <- The folded fourier output.
extern uint16_t fuzzed_bins[]; //[FIXBINS] <- The Full DFT after IIR, Blur and Taper
//[MAXNOTES] <- frequency of note; Note if it is == 255, then it means it is not set.
extern uint8_t note_peak_freqs[];
extern uint16_t note_peak_amps[]; //[MAXNOTES]
extern uint16_t note_peak_amps2[]; //[MAXNOTES] (Responds quicker)
//XXX: TODO: Consider doing the fuzz IIR on the folded bins. That way we can
//save several bytes of RAM on not having to keep fuzzed_bins around.
void Init();
void UpdateFreqs();
void HandleFrameInfo();
#endif