From 6d75249cb8d98e9f99a216318a07b08866783c04 Mon Sep 17 00:00:00 2001 From: cnlohr Date: Wed, 1 Apr 2015 00:21:01 -0400 Subject: [PATCH] The starts of Embedded ColorChord --- Makefile | 15 ++- OutputLinear.c | 4 +- OutputProminent.c | 90 ++++++++++++++ colorchord.exe | Bin 64000 -> 0 bytes default.conf | 13 +- dft.c | 310 ++++++++++++++++++++++++++++++++++------------ dft.h | 35 +++++- embeddedcc.c | 123 ++++++++++++++++++ main.c | 18 ++- quickwash.conf | 26 ++++ sound_pulse.c | 5 + 11 files changed, 545 insertions(+), 94 deletions(-) create mode 100644 OutputProminent.c delete mode 100755 colorchord.exe create mode 100644 embeddedcc.c create mode 100644 quickwash.conf diff --git a/Makefile b/Makefile index a1dce0a..c42a863 100644 --- a/Makefile +++ b/Makefile @@ -2,23 +2,30 @@ all : colorchord RAWDRAW:=DrawFunctions.o XDriver.o SOUND:=sound.o sound_alsa.o sound_pulse.o sound_null.o -OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o +OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o OutputProminent.o WINGCC:=i586-mingw32msvc-gcc -WINGCCFLAGS:= -O2 -ffast-math -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections -s +WINGCCFLAGS:= -O2 -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections -s WINLDFLAGS:=-lwinmm -lgdi32 -lws2_32 RAWDRAWLIBS:=-lX11 -lm -lpthread -lXinerama -lXext LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse -CFLAGS:=-g -Os -flto -Wall -ffast-math +CFLAGS:=-g -Os -flto -Wall 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 + gcc -o $@ $^ $(CFLAGS) -DCCEMBEDDED $(LDFLAGS) $(EXTRALIBS) $(RAWDRAWLIBS) + +runembedded : embeddedcc + parec --format=u8 --rate=8000 --channels=1 --device=alsa_output.pci-0000_00_1b.0.analog-stereo.monitor | ./embeddedcc + + 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 $(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS) clean : - rm -rf *.o *~ colorchord colorchord.exe + rm -rf *.o *~ colorchord colorchord.exe embeddedcc diff --git a/OutputLinear.c b/OutputLinear.c index 631db2c..6e3fbda 100644 --- a/OutputLinear.c +++ b/OutputLinear.c @@ -157,7 +157,9 @@ static void LEDUpdate(void * id, struct NoteFinder*nf) if( satQ > 1 ) satQ = 1; led->last_led_pos[i] = rledpos[ia]; led->last_led_amp[i] = sat; - int r = CCtoHEX( led->last_led_pos[i], 1.0, (led->steady_bright?sat:satQ) ); + float sendsat = (led->steady_bright?sat:satQ); + if( sendsat > 1 ) sendsat = 1; + int r = CCtoHEX( led->last_led_pos[i], 1.0, sendsat ); OutLEDs[i*3+0] = r & 0xff; OutLEDs[i*3+1] = (r>>8) & 0xff; diff --git a/OutputProminent.c b/OutputProminent.c new file mode 100644 index 0000000..aa5adcb --- /dev/null +++ b/OutputProminent.c @@ -0,0 +1,90 @@ +//Really basic driver, that just selects the most prominent color and washes all the LEDs with that. + +#include "outdrivers.h" +#include "notefinder.h" +#include +#include +#include "parameters.h" +#include +#include "color.h" +#include +#include +#include + +struct ProminentDriver +{ + int did_init; + int total_leds; + float satamp; +}; + +static void LEDUpdate(void * id, struct NoteFinder*nf) +{ + struct ProminentDriver * led = (struct ProminentDriver*)id; + + + //Step 1: Calculate the quantity of all the LEDs we'll want. + int totbins = nf->note_peaks;//nf->dists; + int i; + float selected_amp = 0; + float selected_note = 0; + +// if( totbins > led_bins ) totbins = led_bins; + + for( i = 0; i < totbins; i++ ) + { + float freq = nf->note_positions[i] / nf->freqbins; + float amp = nf->note_amplitudes2[i] * led->satamp; + if( amp > selected_amp ) + { + selected_amp = amp; + selected_note = freq; + } + } + + + + //Advance the LEDs to this position when outputting the values. + for( i = 0; i < led->total_leds; i++ ) + { + float sendsat = selected_amp; + if( sendsat > 1 ) sendsat = 1; + int r = CCtoHEX( selected_note, 1.0, sendsat ); + + OutLEDs[i*3+0] = r & 0xff; + OutLEDs[i*3+1] = (r>>8) & 0xff; + OutLEDs[i*3+2] = (r>>16) & 0xff; + } + +} + +static void LEDParams(void * id ) +{ + struct ProminentDriver * led = (struct ProminentDriver*)id; + + led->satamp = 2; RegisterValue( "satamp", PAFLOAT, &led->satamp, sizeof( led->satamp ) ); + led->total_leds = 4; RegisterValue( "leds", PAINT, &led->total_leds, sizeof( led->total_leds ) ); + + + printf( "Found Prominent for output. leds=%d\n", led->total_leds ); + +} + + +static struct DriverInstances * OutputProminent() +{ + struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); + memset( ret, 0, sizeof( struct DriverInstances ) ); + struct ProminentDriver * led = ret->id = malloc( sizeof( struct ProminentDriver ) ); + memset( led, 0, sizeof( struct ProminentDriver ) ); + + ret->Func = LEDUpdate; + ret->Params = LEDParams; + LEDParams( led ); + return ret; + +} + +REGISTER_OUT_DRIVER(OutputProminent); + + diff --git a/colorchord.exe b/colorchord.exe deleted file mode 100755 index f0899d3e9460e3719bfe4c618694a29f68d38927..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64000 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 diff --git a/default.conf b/default.conf index f96c54e..502124b 100644 --- a/default.conf +++ b/default.conf @@ -17,7 +17,7 @@ buffer = 128 play = 0 rec = 1 channels = 2 -samplerate = 44100 +samplerate = 8000 wininput = 0 #Compiled version will default this. @@ -31,7 +31,7 @@ sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor ################################## # How much to amplify the incoming signal. -amplify = 2.5 +amplify = 2.0 # What is the base note? I.e. the lowest note. # Note that it won't have very much impact until an octave up though! @@ -47,6 +47,13 @@ dft_q = 20.0000 dft_speedup = 1000.0000 octaves = 5 +# Should we use a progressive DFT? +# 0 = DFT Quick +# 1 = DFT Progressive +# 2 = DFT Progressive Integer +# 3 = DFT Progressive Integer Skippy +do_progressive_dft = 3 + filter_iter = 2 filter_strength = .5 @@ -63,7 +70,7 @@ note_attach_freq_iir = 0.3000 note_combine_distance = 0.5000 note_jumpability = 1.8000 note_minimum_new_distribution_value = 0.0200 -note_out_chop = 0.1000 +note_out_chop = 0.05000 #======================================================================= diff --git a/dft.c b/dft.c index c40ae19..bfa3d02 100644 --- a/dft.c +++ b/dft.c @@ -1,4 +1,3 @@ - #include "dft.h" #include #include @@ -6,6 +5,9 @@ #include #include + +#ifndef CCEMBEDDED + void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q ) { int i, j; @@ -88,10 +90,9 @@ static float * gbinqtys; static float * gbinqtyc; static float * phis; static float * gfrequencies; -static float * goutbins; static float * lastbins; static float * advances; - +static float * goutbins; static int gbins; static float gq; static float gspeedup; @@ -325,7 +326,7 @@ void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, co - +#endif @@ -337,14 +338,6 @@ void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, co ////////////////////////SKIPPY DFT -//Skippy DFT is a very ood one. - - - -#define OCTAVES 5 -#define FIXBPERO 24 -#define FIXBINS (FIXBPERO*OCTAVES) -#define BINCYCLE (1< +#include +#include + +int8_t Ssintable[512]; //Actually [sin][cos] pairs. + +int main() +{ + int i; + for( i = 0; i < 256; i++ ) + { + Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); + Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); + } + + printf( "const int8_t Ssintable[512] = {" ); + for( i = 0; i < 512; i++ ) + { + if( !(i & 0xf ) ) + { + printf( "\n\t" ); + } + printf( "%4d," ,Ssintable[i] ); + } + printf( "};\n" ); +} + */ + + + +uint16_t Sdatspace[FIXBINS*4]; //(advances,places,isses,icses) //For -static uint8_t Sdo_this_octave[BINCYCLE]; -static int16_t Saccum_octavebins[OCTAVES]; -static uint8_t Swhichoctaveplace; +uint8_t Sdo_this_octave[BINCYCLE]; +int16_t Saccum_octavebins[OCTAVES]; +uint8_t Swhichoctaveplace; +uint16_t embeddedbins[FIXBINS]; //This is updated every time the DFT hits the octavecount, or 1/32 updates. + +//From: http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2 +/** + * \brief Fast Square root algorithm, with rounding + * + * This does arithmetic rounding of the result. That is, if the real answer + * would have a fractional part of 0.5 or greater, the result is rounded up to + * the next integer. + * - SquareRootRounded(2) --> 1 + * - SquareRootRounded(3) --> 2 + * - SquareRootRounded(4) --> 2 + * - SquareRootRounded(6) --> 2 + * - SquareRootRounded(7) --> 3 + * - SquareRootRounded(8) --> 3 + * - SquareRootRounded(9) --> 3 + * + * \param[in] a_nInput - unsigned integer for which to find the square root + * + * \return Integer square root of the input value. + */ +static uint16_t SquareRootRounded(uint32_t a_nInput) +{ + uint32_t op = a_nInput; + uint32_t res = 0; + uint32_t one = 1uL << 30; // The second-to-top bit is set: use 1u << 14 for uint16_t type; use 1uL<<30 for uint32_t type + + + // "one" starts at the highest power of four <= than the argument. + while (one > op) + { + one >>= 2; + } + + while (one != 0) + { + if (op >= res + one) + { + op = op - (res + one); + res = res + 2 * one; + } + res >>= 1; + one >>= 2; + } + + /* Do arithmetic rounding to nearest integer */ + if (op > res) + { + res++; + } + + return res; +} void HandleProgressiveIntSkippy( int8_t sample1 ) { @@ -390,27 +500,40 @@ void HandleProgressiveIntSkippy( int8_t sample1 ) { int16_t isps = Sdatspace[i*4+2]; int16_t ispc = Sdatspace[i*4+3]; - int16_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256)); // printf( "%d (%d %d)\n", mux, isps, ispc ); int octave = i / FIXBPERO; // mux >>= octave; - goutbins[i] = sqrt( mux ); -// goutbins[i]/=100.0; - goutbins[i]/=100*(1<>5; - Sdatspace[i*4+3] -= ispc>>5; - } +#ifndef CCEMBEDDED + uint32_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256)); + goutbins[i] = sqrt( mux ); + goutbins[i]/=25*(1<>= octave; + + Sdatspace[i*4+2] -= isps>>4; //XXX 4 is more responsive AND doesn't overflow as easily. + Sdatspace[i*4+3] -= ispc>>4; //XXX 4 is more responsive AND doesn't overflow as easily. + + //TRICKY: It is possible for the sin and cos accumulators to overflow, + //I DO NOT INTEND TO FIX THIS NOW! It could be easily fixed by using 32-bit integers, or + //by decreasing the quality a little bit, but it is an extreme case with a pure, full-volume sinewave. + } + return; } + for( i = 0; i < OCTAVES;i++ ) { Saccum_octavebins[i] += sample1; } uint16_t * ds = &Sdatspace[oct*FIXBPERO*4]; - int8_t * st; + const int8_t * st; sample1 = Saccum_octavebins[oct]>>(OCTAVES-oct); Saccum_octavebins[oct] = 0; @@ -436,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>>3; //Add MSBs with carry 2 -> 6 AS/IS: 6 + tmp1 += ts>>4; //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>>3; //Add MSBs with carry 2 -> 6 AS/IS: 6 + tmp1 += tc>>4; //Add MSBs with carry 2 -> 6 AS/IS: 6 *ds++ = tmp1; //Store values back 4 @@ -452,46 +575,82 @@ void HandleProgressiveIntSkippy( int8_t sample1 ) } } +void SetupDFTProgressiveIntegerSkippy() +{ + int i; + int j; + //Sdatspace = malloc(FIXBPERO*OCTAVES*8); + //memset(Sdatspace,0,FIXBPERO*OCTAVES*8); + //printf( "MS: %d\n", FIXBPERO*OCTAVES*8); + Sdonefirstrun = 1; +/* + for( i = 0; i < 256; i++ ) + { + Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); + Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); + } +*/ + for( i = 0; i < BINCYCLE; i++ ) + { + // Sdo_this_octave = + // 4 3 4 2 4 3 4 ... + //search for "first" zero + + for( j = 0; j <= OCTAVES; j++ ) + { + if( ((1< OCTAVES ) + { + fprintf( stderr, "Error: algorithm fault.\n" ); + exit( -1 ); + } + Sdo_this_octave[i] = OCTAVES-j-1; + } +} + +#ifndef CCEMBEDDED + +void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies ) +{ + int i; + for( i = 0; i < FIXBINS; i++ ) + { + float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))]; + Sdatspace[i*4] = (65536.0/freq);// / oneoveroctave; + } +} + +#endif + + +void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies ) +{ + int i; + for( i = 0; i < FIXBINS; i++ ) + { + uint16_t freq = frequencies[i%FIXBPERO]; + Sdatspace[i*4] = freq;// / oneoveroctave; + } +} + +void Push8BitIntegerSkippy( int8_t dat ) +{ + HandleProgressiveIntSkippy( dat ); + HandleProgressiveIntSkippy( dat ); +} + + +#ifndef CCEMBEDDED + void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) { static float backupbins[FIXBINS]; - int i, j; + int i; static int last_place; -//printf( "SKIPPY\n" ); - - if( !Sdonefirstrun ) - { - memset( outbins, 0, bins * sizeof( float ) ); - goutbins = outbins; - //Sdatspace = malloc(FIXBPERO*OCTAVES*8); - //memset(Sdatspace,0,FIXBPERO*OCTAVES*8); - //printf( "MS: %d\n", FIXBPERO*OCTAVES*8); - Sdonefirstrun = 1; - for( i = 0; i < 256; i++ ) - { - Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); - Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); - } - - for( i = 0; i < BINCYCLE; i++ ) - { - // Sdo_this_octave = - // 4 3 4 2 4 3 4 ... - //search for "first" zero - - for( j = 0; j <= OCTAVES; j++ ) - { - if( ((1< OCTAVES ) - { - fprintf( stderr, "Error: algorithm fault.\n" ); - exit( -1 ); - } - Sdo_this_octave[i] = OCTAVES-j-1; - } - } + memset( outbins, 0, bins * sizeof( float ) ); + goutbins = outbins; memcpy( outbins, backupbins, FIXBINS*4 ); @@ -501,13 +660,16 @@ void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bi return; } - - for( i = 0; i < bins; i++ ) + +//printf( "SKIPPY\n" ); + + if( !Sdonefirstrun ) { - float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))]; - Sdatspace[i*4] = (65536.0/freq);// / oneoveroctave; + SetupDFTProgressiveIntegerSkippy(); + Sdonefirstrun = 1; } + UpdateBinsForProgressiveIntegerSkippy( frequencies ); for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) { @@ -519,23 +681,9 @@ void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bi last_place = place_in_data_buffer; memcpy( backupbins, outbins, FIXBINS*4 ); - - //Extract bins. -/* - for( i = 0; i < bins; i++ ) - { - int16_t isps = Sdatspace[i*4+2]; - int16_t ispc = Sdatspace[i*4+3]; - int16_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256)); -// printf( "%d (%d %d)\n", mux, isps, ispc ); - outbins[i] = sqrt( mux )/100.0; - } -*/ - -// printf( "\n"); } - +#endif diff --git a/dft.h b/dft.h index 944b949..1589c22 100644 --- a/dft.h +++ b/dft.h @@ -1,10 +1,13 @@ #ifndef _DFT_H #define _DFT_H +#include + +//Warning: Most ColorChords are not available for ColorChord Embedded. +#ifndef CCEMBEDDED //There are several options here, the last few are selectable by modifying the do_progressive_dft flag. - //Do a DFT on a live audio ring buffer. It assumes new samples are added on in the + direction, older samples go negative. //Frequencies are as a function of the samplerate, for example, a frequency of 22050 is actually 2 Hz @ 44100 SPS //bins = number of frequencies to check against. @@ -22,10 +25,40 @@ void DoDFTProgressive( float * outbins, float * frequencies, int bins, const flo //This is fast enough to run on an ESP8266 void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); +#endif + //Everything the integer one buys, except it only calculates 2 octaves worth of notes per audio frame. //This is sort of working, but still have some quality issues. //It would theoretically be fast enough to work on an AVR. +//NOTE: This is the only DFT available to the embedded port of ColorChord void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); +//It's actually split into a few functions, which you can call on your own: +void SetupDFTProgressiveIntegerSkippy(); //Call at start. + +#ifndef CCEMBEDDED +void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies ); //Update the frequencies +#endif + +void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies ); +void Push8BitIntegerSkippy( int8_t dat ); //Call this to push on new frames of sound. + + +//You can # define these to be other things. +#ifndef OCTAVES +#define OCTAVES 5 +#endif + +#ifndef FIXBPERO +#define FIXBPERO 24 +#endif + +#define FIXBINS (FIXBPERO*OCTAVES) +#define BINCYCLE (1< + +#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 +#include + +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() +{ + int wf = 0; + int ci; + Init(); + while( ( ci = getchar() ) != EOF ) + { + int cs = ci - 0x80; + Push8BitIntegerSkippy( (int8_t)cs ); + //printf( "%d ", cs ); fflush( stdout ); + wf++; + if( wf == 64 ) + { + HandleFrameInfo(); + wf = 0; + } + } + return 0; +} + diff --git a/main.c b/main.c index 3664a82..57aae5d 100644 --- a/main.c +++ b/main.c @@ -44,7 +44,7 @@ int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT ); struct NoteFinder * nf; //Sound circular buffer -#define SOUNDCBSIZE 65536 +#define SOUNDCBSIZE 8096 #define MAX_CHANNELS 2 double VisTimeEnd, VisTimeStart; @@ -98,10 +98,15 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun for( j = 0; j < channelin; j++ ) { float f = in[i*channelin+j]; - if( f > -1 && f < 1 ) + if( f >= -1 && f <= 1 ) { fo += f; } + else + { + fo += (f>0)?1:-1; +// printf( "Sound fault A %d/%d %d/%d %f\n", j, channelin, i, samplesr, f ); + } } fo /= channelin; @@ -114,9 +119,13 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun float f = in[i*channelin+sample_channel]; if( f > -1 && f < 1 ) { - sound[soundhead] = f; - soundhead = (soundhead+1)%SOUNDCBSIZE; + f = (f>0)?1:-1; } + + //printf( "Sound fault B %d/%d\n", i, samplesr ); + sound[soundhead] = f; + soundhead = (soundhead+1)%SOUNDCBSIZE; + } } } @@ -374,6 +383,7 @@ int main(int argc, char ** argv) int thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; for( i = 0; i < screenx; i++ ) { + if( thisy < 0 || thisy > 256 ) printf( "%d/%d\n", thisy,thissoundhead ); CNFGTackSegment( i, lasty, i+1, thisy ); lasty = thisy; thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; diff --git a/quickwash.conf b/quickwash.conf new file mode 100644 index 0000000..ab598e8 --- /dev/null +++ b/quickwash.conf @@ -0,0 +1,26 @@ + +This is a vornoi thing: +outdrivers = DisplayArray, OutputProminent +lightx = 2 +lighty = 2 +leds = 4 +fromsides = 1 +shape_cutoff = 0.03 +satamp = 5.000 +amppow = 2.510 +distpow = 1.500 + +samplerate = 11025 +buffer = 64 + +sourcename = default + +amplify = 2.5 +note_attach_amp_iir = 0.9000 +note_attach_amp_iir2 = 0.550 +note_attach_freq_iir = 0.9000 +dft_iir = .6 +dft_q = 20.0000 +dft_speedup = 1000.0000 +note_jumpability = 1.0000 + diff --git a/sound_pulse.c b/sound_pulse.c index 513b53a..7033db8 100644 --- a/sound_pulse.c +++ b/sound_pulse.c @@ -267,6 +267,11 @@ void * InitSoundPulse( SoundCBType cb ) r->channelsRec = r->channelsPlay; r->sourceName = GetParameterS( "sourcename", NULL ); + if( strcmp( r->sourceName, "default" ) == 0 ) + { + r->sourceName = 0; + } + r->play = 0; r->rec = 0; r->buffer = GetParameterI( "buffer", 1024 );