Replace SortFloats()/RemapFloats() with stdlib's qsort and struct refactoring.

This commit is contained in:
Cleon Chick 2016-10-08 14:52:20 -04:00
parent fc2a404acf
commit 29d07b168d
9 changed files with 98 additions and 188 deletions

View file

@ -16,10 +16,10 @@ LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse
CFLAGS:=-g -O0 -flto -Wall -ffast-math -I../embeddedcommon -I. -DICACHE_FLASH_ATTR=
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 hook.o ../embeddedcommon/DFT32.o configs.o
colorchord : os_generic.o main.o dft.o decompose.o filter.o color.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o hook.o ../embeddedcommon/DFT32.o configs.o
gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS)
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c sort.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c
$(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS)

View file

@ -1,6 +1,7 @@
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
#include "decompose.h"
#include "notefinder.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
@ -10,7 +11,7 @@
#ifdef TURBO_DECOMPOSE
int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations )
int DecomposeHistogram( float * histogram, int bins, struct NoteDists * out_dists, int max_dists, double default_sigma, int iterations )
{
//Step 1: Find the actual peaks.
@ -41,35 +42,35 @@ int DecomposeHistogram( float * histogram, int bins, float * out_means, float *
offset = (0.5 - porpdiffN);
}
out_means[peak] = i + offset;
out_dists[peak].mean = i + offset;
//XXX XXX TODO Examine difference or relationship of "this" and "totaldiff"
out_amps[peak] = this * 4;
out_dists[peak].amp = this * 4;
//powf( totaldiff, .8) * 10;//powf( totaldiff, .5 )*4; //
out_sigmas[peak] = default_sigma;
out_dists[peak].sigma = default_sigma;
peak++;
}
for( i = peak; i < max_dists; i++ )
{
out_means[i] = -1;
out_amps[i] = 0;
out_sigmas[i] = default_sigma;
out_dists[i].mean = -1;
out_dists[i].amp = 0;
out_dists[i].sigma = default_sigma;
}
return peak;
}
//Yick: Doesn't match.. I guess it's only for debugging, right?
float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists )
float CalcHistAt( float pt, int bins, struct NoteDists * out_dists, int cur_dists )
{
int i;
float mark = 0.0;
for( i = 0; i < cur_dists; i++ )
{
float amp = out_amps[i];
float mean = out_means[i];
float var = out_sigmas[i];
float amp = out_dists[i].amp;
float mean = out_dists[i].mean;
float var = out_dists[i].sigma;
float x = mean - pt;
if( x < - bins / 2 ) x += bins;
@ -83,11 +84,11 @@ float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float
#else
float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists );
float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists );
float AttemptDecomposition( float * histogram, int bins, struct NoteDists * out_dists, int cur_dists );
float CalcHistAt( float pt, int bins, struct NoteDists * out_dists, int cur_dists );
int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations )
int DecomposeHistogram( float * histogram, int bins, struct NoteDists * out_dists, int max_dists, double default_sigma, int iterations )
{
//NOTE: The sigma may change depending on all sorts of things, maybe?
@ -108,9 +109,9 @@ int DecomposeHistogram( float * histogram, int bins, float * out_means, float *
else if( went_up)
{
went_up = 0;
out_amps[sigs] = thishist / (default_sigma + 1);
out_sigmas[sigs] = default_sigma;
out_means[sigs] = i-0.5;
out_dists[sigs].amp = thishist / (default_sigma + 1);
out_dists[sigs].sigma = default_sigma;
out_dists[sigs].mean = i-0.5;
sigs++;
}
vhist = thishist;
@ -119,7 +120,7 @@ int DecomposeHistogram( float * histogram, int bins, float * out_means, float *
return 0;
int iteration;
float errbest = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs );
float errbest = AttemptDecomposition( histogram, bins, out_dists, sigs );
int dropped[bins];
for( i = 0; i < bins; i++ )
{
@ -130,33 +131,28 @@ int DecomposeHistogram( float * histogram, int bins, float * out_means, float *
{
if( dropped[iteration%sigs] ) continue;
//Tweak with the values until they are closer to what we want.
float backup_mean = out_means[iteration%sigs];
float backup_amps = out_amps[iteration%sigs];
float backup_sigmas = out_sigmas[iteration%sigs];
struct NoteDists backup = out_dists[iteration%sigs];
float mute = 20. / (iteration+20.);
#define RANDFN ((rand()%2)-0.5)*mute
//#define RANDFN ((rand()%10000)-5000.0) / 5000.0 * mute
// out_sigmas[iteration%sigs] += RANDFN;
out_means[iteration%sigs] += RANDFN;
out_amps[iteration%sigs] += RANDFN;
float err = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs );
// out_dists[iteration%sigs].sigma += RANDFN;
out_dists[iteration%sigs].mean += RANDFN;
out_dists[iteration%sigs].amp += RANDFN;
float err = AttemptDecomposition( histogram, bins, out_dists, sigs );
if( err > errbest )
{
out_means[iteration%sigs] = backup_mean;
out_amps[iteration%sigs] = backup_amps;
out_sigmas[iteration%sigs] = backup_sigmas;
out_dists[iteration%sigs] = backup;
}
else
{
if( out_amps[iteration%sigs] < 0.01 )
if( out_dists[iteration%sigs].amp < 0.01 )
{
dropped[iteration%sigs] = 1;
out_amps[iteration%sigs] = 0.0;
out_dists[iteration%sigs].amp = 0.0;
}
errbest = err;
}
}
// printf( "%f / %f = %f\n", origerr, errbest, origerr/errbest );
@ -164,15 +160,15 @@ int DecomposeHistogram( float * histogram, int bins, float * out_means, float *
return sigs;
}
float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists )
float CalcHistAt( float pt, int bins, struct NoteDists * out_dists, int cur_dists )
{
int i;
float mark = 0.0;
for( i = 0; i < cur_dists; i++ )
{
float amp = out_amps[i];
float mean = out_means[i];
float var = out_sigmas[i];
float amp = out_dists[i].amp;
float mean = out_dists[i].mean;
float var = out_dists[i].sigma;
float x = mean - pt;
if( x < - bins / 2 ) x += bins;
@ -183,16 +179,16 @@ float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float
return mark;
}
float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists )
float AttemptDecomposition( float * histogram, int bins, struct NoteDists * out_dists, int cur_dists )
{
int i, j;
float hist[bins];
memcpy( hist, histogram, sizeof(hist) );
for( i = 0; i < cur_dists; i++ )
{
float amp = out_amps[i];
float mean = out_means[i];
float var = out_sigmas[i];
float amp = out_dists[i].amp;
float mean = out_dists[i].mean;
float var = out_dists[i].sigma;
for( j = 0; j < bins; j++ )
{

View file

@ -3,9 +3,11 @@
#ifndef _DECOMPOSE_H
#define _DECOMPOSE_H
#include "notefinder.h"
//Decompose a histogram into a series of normal distributions.
int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations );
float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists );
int DecomposeHistogram( float * histogram, int bins, struct NoteDists * out_dists, int max_dists, double default_sigma, int iterations );
float CalcHistAt( float pt, int bins, struct NoteDists * out_dists, int cur_dists );
#define TURBO_DECOMPOSE

View file

@ -306,13 +306,13 @@ int main(int argc, char ** argv)
//char sttdebug[1024];
//char * sttend = sttdebug;
for( i = 0; i < nf->dists; i++ )
for( i = 0; i < nf->dists_count; i++ )
{
CNFGPenX = (nf->dist_means[i] + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
CNFGPenY = 400-nf->dist_amps[i] * 150.0 / nf->dist_sigmas[i];
//printf( "%f %f\n", dist_means[i], dist_amps[i] );
sprintf( stt, "%f\n%f\n", nf->dist_means[i], nf->dist_amps[i] );
// sttend += sprintf( sttend, "%f/%f ",nf->dist_means[i], nf->dist_amps[i] );
CNFGPenX = (nf->dists[i].mean + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
CNFGPenY = 400-nf->dists[i].amp * 150.0 / nf->dists[i].sigma;
//printf( "%f %f\n", dists[i].mean, dists[i].amp );
sprintf( stt, "%f\n%f\n", nf->dists[i].mean, nf->dists[i].amp );
// sttend += sprintf( sttend, "%f/%f ",nf->dists[i].mean, nf->dists[i].amp );
CNFGDrawText( stt, 2 );
}
CNFGColor( 0xffffff );
@ -366,7 +366,7 @@ int main(int argc, char ** argv)
for( i = -1; i < screenx; i++ )
{
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, nf->dists );
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dists, nf->dists_count );
if( i >= 0 )
CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 );
lasthistval = thishistval;

View file

@ -10,7 +10,6 @@
#include "dft.h"
#include "filter.h"
#include "decompose.h"
#include "sort.h"
#include "DFT32.h"
struct NoteFinder * CreateNoteFinder( int spsRec )
@ -151,18 +150,8 @@ printf( "%d %d %f %f %f\n", ret->freqbins, ret->octaves, ret->base_hz, ret->dft_
if( ret->folded_bins ) free( ret->folded_bins );
ret->folded_bins = calloc( 1, sizeof( float ) * ret->freqbins );
if( ret->dist_amps ) free( ret->dist_amps );
ret->dist_amps = calloc( 1, sizeof( float ) * maxdists );
if( ret->dist_means ) free( ret->dist_means );
ret->dist_means = calloc( 1, sizeof( float ) * maxdists );
if( ret->dist_sigmas ) free( ret->dist_sigmas );
ret->dist_sigmas = calloc( 1, sizeof( float ) * maxdists );
if( ret->dist_takens ) free( ret->dist_takens );
ret->dist_takens = calloc( 1, sizeof( unsigned char ) * maxdists );
if( ret->dists ) free ( ret->dists );
ret->dists = calloc( 1, sizeof( struct NoteDists ) * maxdists );
ret->ofreqs = freqs;
}
@ -174,6 +163,12 @@ printf( "%d %d %f %f %f\n", ret->freqbins, ret->octaves, ret->base_hz, ret->dft_
}
int NoteDistsComparer(const void * a, const void * b)
{
float v = ((struct NoteDists *)a)->amp - ((struct NoteDists *)b)->amp;
return (0.f < v) - (v < 0.f);
}
void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head, int buffersize )
{
int i, j;
@ -242,37 +237,35 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head
nf->FilterTime = OGGetAbsoluteTime();
memset( nf->dist_takens, 0, sizeof( unsigned char ) * maxdists );
nf->dists = DecomposeHistogram( nf->folded_bins, freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, maxdists, nf->default_sigma, nf->decompose_iterations );
for (i = 0; i < maxdists; i++)
{
nf->dists[i].taken = 0;
}
nf->dists_count = DecomposeHistogram( nf->folded_bins, freqbins, nf->dists, maxdists, nf->default_sigma, nf->decompose_iterations );
//Compress/normalize dist_amps
float total_dist = 0;
for( i = 0; i < nf->dists; i++ )
for( i = 0; i < nf->dists_count; i++ )
{
total_dist += nf->dist_amps[i];
total_dist += nf->dists[i].amp;
}
float muxer = nf->compress_coefficient/powf( total_dist * nf->compress_coefficient, nf->compress_exponenet );
total_dist = muxer;
for( i = 0; i < nf->dists; i++ )
for( i = 0; i < nf->dists_count; i++ )
{
nf->dist_amps[i]*=total_dist;
nf->dists[i].amp*=total_dist;
}
{
int dist_sorts[nf->dists];
SortFloats( dist_sorts, nf->dist_amps, nf->dists );
RemapFloats( dist_sorts, nf->dist_amps, nf->dists );
RemapFloats( dist_sorts, nf->dist_means, nf->dists );
RemapFloats( dist_sorts, nf->dist_sigmas, nf->dists );
}
qsort(nf->dists, nf->dists_count, sizeof(struct NoteDists), NoteDistsComparer);
nf->DecomposeTime = OGGetAbsoluteTime();
//We now have the positions and amplitudes of the normal distributions that comprise our spectrum. IN SORTED ORDER!
//dists = # of distributions
//dist_amps[] = amplitudes of the normal distributions
//dist_means[] = positions of the normal distributions
//dists_count = # of distributions
//dists[].amp = amplitudes of the normal distributions
//dists[].mean = positions of the normal distributions
//We need to use this in a filtered manner to obtain the "note" peaks
//note_peaks = total number of peaks.
@ -283,26 +276,26 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head
//First try to find any close peaks.
for( i = 0; i < note_peaks; i++ )
{
for( j = 0; j < nf->dists; j++ )
for( j = 0; j < nf->dists_count; j++ )
{
if( !nf->dist_takens[j] && !nf->note_founds[i] && fabsloop( nf->note_positions[i], nf->dist_means[j], freqbins ) < nf->note_jumpability && nf->dist_amps[j] > 0.00001 ) //0.00001 for stability.
if( !nf->dists[j].taken && !nf->note_founds[i] && fabsloop( nf->note_positions[i], nf->dists[j].mean, freqbins ) < nf->note_jumpability && nf->dists[j].amp > 0.00001 ) //0.00001 for stability.
{
//Attach ourselves to this bin.
nf->note_peaks_to_dists_mapping[i] = j;
nf->dist_takens[j] = 1;
nf->dists[j].taken = 1;
if( nf->enduring_note_id[i] == 0 )
nf->enduring_note_id[i] = nf->current_note_id++;
nf->note_founds[i] = 1;
nf->note_positions[i] = avgloop( nf->note_positions[i], (1.-nf->note_attach_freq_iir), nf->dist_means[j], nf->note_attach_freq_iir, nf->freqbins);
nf->note_positions[i] = avgloop( nf->note_positions[i], (1.-nf->note_attach_freq_iir), nf->dists[j].mean, nf->note_attach_freq_iir, nf->freqbins);
//I guess you can't IIR this like normal.
////note_positions[i] * (1.-note_attach_freq_iir) + dist_means[j] * note_attach_freq_iir;
////note_positions[i] * (1.-note_attach_freq_iir) + dists[j].mean * note_attach_freq_iir;
nf->note_amplitudes[i] = nf->note_amplitudes[i] * (1.-nf->note_attach_amp_iir) + nf->dist_amps[j] * nf->note_attach_amp_iir;
nf->note_amplitudes[i] = nf->note_amplitudes[i] * (1.-nf->note_attach_amp_iir) + nf->dists[j].amp * nf->note_attach_amp_iir;
//XXX TODO: Consider: Always boost power, never reduce?
// if( dist_amps[i] > note_amplitudes[i] )
// note_amplitudes[i] = dist_amps[i];
// if( dists[i].amp > note_amplitudes[i] )
// note_amplitudes[i] = dists[i].amp;
}
}
}
@ -350,16 +343,15 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head
nf->enduring_note_id[i] = 0;
//Find a new peak for this note.
for( j = 0; j < nf->dists; j++ )
for( j = 0; j < nf->dists_count; j++ )
{
if( !nf->dist_takens[j] && nf->dist_amps[j] > nf->note_minimum_new_distribution_value )
if( !nf->dists[j].taken && nf->dists[j].amp > nf->note_minimum_new_distribution_value )
{
nf->enduring_note_id[i] = nf->current_note_id++;
nf->dist_takens[j] = 1;
nf->note_amplitudes[i] = nf->dist_amps[j];//min_note_amplitude + dist_amps[j] * note_attach_amp_iir; //TODO: Should this jump?
nf->note_positions[i] = nf->dist_means[j];
nf->dists[j].taken = 1;
nf->note_amplitudes[i] = nf->dists[j].amp;//min_note_amplitude + dists[j].amp * note_attach_amp_iir; //TODO: Should this jump?
nf->note_positions[i] = nf->dists[j].mean;
nf->note_founds[i] = 1;
nf->dist_takens[j] = 1;
}
}
}

View file

@ -5,6 +5,12 @@
#include "os_generic.h"
struct NoteDists {
float amp; //Amplitude of normal distribution
float mean; //Mean of normal distribution
float sigma; //Sigma of normal distribution
unsigned char taken; //Is distribution associated with any notes?
};
struct NoteFinder
{
@ -78,11 +84,8 @@ struct NoteFinder
//Dists: These things are the distributions that are found, they are very fickle and change frequently.
int dists; //# of distributions (these are the precursors to notes - it is trying to find the normal distributions.)
float * dist_amps; //Amplitude of normal distribution... [nf->dists]
float * dist_means; //Mean of normal distribution... [nf->dists]
float * dist_sigmas; //Sigma of normal distribution... [nf->dists]
unsigned char * dist_takens; //Which distributions are now associated with notes
int dists_count; //# of distributions (these are the precursors to notes - it is trying to find the normal distributions.)
struct NoteDists * dists;
//For profiling, all in absolute time in seconds.

View file

@ -1,63 +0,0 @@
//Copyright (Public Domain) 2015 <>< Charles Lohr, under the NewBSD License.
//This file may be used in whole or part in any way for any purpose by anyone
//without restriction.
#include "sort.h"
#include <string.h>
#include <stdio.h>
//Sort the indices of an array of floating point numbers
void SortFloats( int * indexouts, float * array, int count )
{
int i;
int j;
unsigned char selected[count];
memset( selected, 0, sizeof( selected ) );
for( i = 0; i < count; i++ )
{
int leastindex = -1;
float leastval = -1e200;
for( j = 0; j < count; j++ )
{
if( !selected[j] && array[j] > leastval )
{
leastval = array[j];
leastindex = j;
}
}
if( leastindex < 0 )
{
fprintf( stderr, "ERROR: Sorting fault.\n" );
goto fault;
}
selected[leastindex] = 1;
indexouts[i] = leastindex;
}
return;
fault:
for( i = 0; i < count; i++ )
{
indexouts[i] = i;
}
}
//Move the floats around according to the new index.
void RemapFloats( int * indexouts, float * array, int count )
{
int i;
float copyarray[count];
memcpy( copyarray, array, sizeof( copyarray ) );
for( i = 0; i < count; i++ )
{
array[i] = copyarray[indexouts[i]];;
}
}

View file

@ -1,20 +0,0 @@
//Copyright (Public Domain) 2015 <>< Charles Lohr, under the NewBSD License.
//This file may be used in whole or part in any way for any purpose by anyone
//without restriction.
#ifndef _SORT_H
#define _SORT_H
//XXX WARNING: This is a TERRIBLE TERRIBLE O(N^2) SORTING ALGORITHM
//You should probably fix this!!!
//Sort the indices of an array of floating point numbers
//Highest->Lowest
void SortFloats( int * indexouts, float * array, int count );
//Move the floats around according to the new index.
void RemapFloats( int * indexouts, float * array, int count );
#endif

View file

@ -424,13 +424,13 @@ int main(int argc, char ** argv)
//char sttdebug[1024];
//char * sttend = sttdebug;
for( i = 0; i < nf->dists; i++ )
for( i = 0; i < nf->dists_count; i++ )
{
CNFGPenX = (nf->dist_means[i] + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
CNFGPenY = 400-nf->dist_amps[i] * 150.0 / nf->dist_sigmas[i];
//printf( "%f %f\n", dist_means[i], dist_amps[i] );
sprintf( stt, "%f\n%f\n", nf->dist_means[i], nf->dist_amps[i] );
// sttend += sprintf( sttend, "%f/%f ",nf->dist_means[i], nf->dist_amps[i] );
CNFGPenX = (nf->dists[i].mean + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
CNFGPenY = 400-nf->dists[i].amp * 150.0 / nf->dists[i].sigma;
//printf( "%f %f\n", dists[i].mean, dists[i].amp );
sprintf( stt, "%f\n%f\n", nf->dists[i].mean, nf->dists[i].amp );
// sttend += sprintf( sttend, "%f/%f ",nf->dists[i].mean, nf->dists[i].amp );
CNFGDrawText( stt, 2 );
}
CNFGColor( 0xffffff );
@ -484,7 +484,7 @@ int main(int argc, char ** argv)
for( i = -1; i < screenx; i++ )
{
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, nf->dists );
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dists, nf->dists_count );
if( i >= 0 )
CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 );
lasthistval = thishistval;