diff --git a/LICENSE b/LICENSE index 5e07f48..23b7afa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015, Charles +Copyright (c) 2015, Charles Lohr (CNLohr) All rights reserved. Redistribution and use in source and binary forms, with or without @@ -11,9 +11,7 @@ modification, are permitted provided that the following conditions are met: this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of colorchord nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. +* The third clause of this license has been voluentarily lifted by its author. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/Makefile b/Makefile index bc6c872..d74a544 100644 --- a/Makefile +++ b/Makefile @@ -2,22 +2,26 @@ 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 RecorderPlugin.o + +OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o OutputProminent.o RecorderPlugin.o WINGCC:=i586-mingw32msvc-gcc -WINGCCFLAGS:= -lwinmm -lgdi32 -lws2_32 -O2 -ffast-math -g +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 -O2 -flto -Wall -ffast-math + + +CFLAGS:=-g -Os -flto -Wall -ffast-math -Iembeddedcommon 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 +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 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 - $(WINGCC) -o $@ $^ $(WINGCCFLAGS) +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 + $(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS) clean : - rm -rf *.o *~ colorchord + 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/README.md b/README.md index b905700..7e28ea2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ What is ColorChord? Chromatic Sound to Light Conversion System. It's really that simple. Unlike so many of the sound responsive systems out there, ColorChord looks at the chromatic properties of the sound. It looks for notes, not ranges. If it hears an "E" it doesn't care what octave it's in, it's an E. This provides a good deal more interesting patterns between instruments and music than would be available otherwise. - Background ---------- @@ -21,11 +20,22 @@ Here's a video of it running: https://www.youtube.com/watch?v=UI4eqOP2AU0 Current State of Affairs ------------------------ -Currently, ColorChord 2 is designed to run on Linux. It's not particularly tied to an architecture, but does pretty much need a dedicated FPU to achieve any decent performance. Right now there aren't very many output options available for it. The most interesting one used for debugging is a vornoi-diagram-like thing called "DisplayShapeDriver." +Currently, ColorChord 2 is designed to run on Linux or Windows. It's not particularly tied to an architecture, but does pretty much need a dedicated FPU to achieve any decent performance. Right now there aren't very many output options available for it. The most interesting one used for debugging is a vornoi-diagram-like thing called "DisplayShapeDriver." + +ColorChord: Embedded +-------------------- + +There is work on an embedded version of ColorChord, which avoids floating point operations anywhere in the output pipeline. Though I have made efforts to port it to AVRs, it doesn't seem feasable to operate on AVRs in the normal sense, so I have retargeted my efforts to 32-bit systems. + Building and Using ------------------ +On Linux you'll need the following packages, for Debian/Ubuntu/Mint you'll need the following: +``` +apt-get install libpulse-dev libasound2-dev libx11-dev libxext-dev libxinerama-dev libusb-1.0-0-dev +``` + To make colorchord, type: ``` diff --git a/TODO b/TODO index 9dd1cb9..a7c2c83 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ Still to do: Try this: -* Separate "LED Selection" from "output" algorithms. << Do this by allowing arbitrary Lights Drivers +* Make Linear keep the order of the notes in-order. * For light finding, pick lights off the peaks to get number of lights to use. * For light shifting (for 1d-looping light systems) shift the centers of the notes, then vernoi between the notes. diff --git a/WinDriver.c b/WinDriver.c index 4b054ed..b0f41d7 100644 --- a/WinDriver.c +++ b/WinDriver.c @@ -5,6 +5,7 @@ #include "DrawFunctions.h" #include #include +#include #include //for alloca static HINSTANCE lhInstance; @@ -193,6 +194,8 @@ void CNFGSetup( const char * name_of_window, int width, int height ) InternalHandleResize(); } +void WindowsTerm(); + void CNFGHandleInput() { int ldown = 0; @@ -204,6 +207,13 @@ void CNFGHandleInput() switch( msg.message ) { + case WM_QUIT: + case WM_DESTROY: + case WM_CLOSE: + printf( "Close\n" ); + WindowsTerm(); + TerminateProcess( 0, 0 ); + break; case WM_MOUSEMOVE: HandleMotion( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, ( (msg.wParam & 0x01)?1:0) | ((msg.wParam & 0x02)?2:0) | ((msg.wParam & 0x10)?4:0) ); break; diff --git a/default.conf b/default.conf index 1c31890..dee236d 100644 --- a/default.conf +++ b/default.conf @@ -23,8 +23,9 @@ wininput = 0 #Compiled version will default this. #sound_source = PULSE #-1 indicates left and right, 0 left, 1 right. + sample_channel = 1 -sourcename = +sourcename = default alsa_output.pci-0000_00_1b.0.analog-stereo.monitor ################################## @@ -32,7 +33,7 @@ sourcename = ################################## # 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! @@ -48,6 +49,14 @@ 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 +# 4 = Integer, 32-Bit, Progressive, Skippy. +do_progressive_dft = 4 + filter_iter = 2 filter_strength = .5 @@ -55,16 +64,16 @@ filter_strength = .5 freqbins = 24 # For the final note information... How much to slack everything? -note_attach_amp_iir = 0.3000 -note_attach_amp_iir2 = 0.200 -note_attach_freq_iir = 0.4000 +note_attach_amp_iir = 0.2000 +note_attach_amp_iir2 = 0.150 +note_attach_freq_iir = 0.3000 #How many bins a note can jump from frame to frame to be considered a slide. #this is used to prevent notes from popping in and out a lot. 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 #======================================================================= @@ -72,7 +81,7 @@ note_out_chop = 0.1000 This is a vornoi thing: -outdrivers = DisplayArray, OutputVoronoi +outdrivers = OutputVoronoi, DisplayArray lightx = 64 lighty = 32 fromsides = 1 diff --git a/dft.c b/dft.c index 1326363..d9e574a 100644 --- a/dft.c +++ b/dft.c @@ -1,8 +1,13 @@ #include "dft.h" #include #include +#include +#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; @@ -41,6 +46,8 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d for( i = 0; i < bins; i++ ) { + int flirts = 0; + float freq = frequencies[i]; float phi = 0; int ftq = freq * q; @@ -66,6 +73,7 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d binqtyc += cv; phi += advance; + flirts++; } float amp = sqrtf( binqtys * binqtys + binqtyc * binqtyc ); @@ -73,3 +81,610 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d } } + + +////////////////////////////DFT Progressive is for embedded systems, primarily. + + +static float * gbinqtys; +static float * gbinqtyc; +static float * phis; +static float * gfrequencies; +static float * lastbins; +static float * advances; +static float * goutbins; +static int gbins; +static float gq; +static float gspeedup; + +#define PROGIIR .005 + +void HandleProgressive( float sample ) +{ + int i; + + for( i = 0; i < gbins; i++ ) + { + float thiss = sinf( phis[i] ) * sample; + float thisc = cosf( phis[i] ) * sample; + + float s = gbinqtys[i] = gbinqtys[i] * (1.-PROGIIR) + thiss * PROGIIR; + float c = gbinqtyc[i] = gbinqtyc[i] * (1.-PROGIIR) + thisc * PROGIIR; + + phis[i] += advances[i]; + if( phis[i] > 6.283 ) phis[i]-=6.283; + + goutbins[i] = sqrtf( s * s + c * c ); + } +} + + +void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) +{ + int i; + static int last_place; + + if( gbins != bins ) + { + if( gbinqtys ) free( gbinqtys ); + if( gbinqtyc ) free( gbinqtyc ); + if( phis ) free( phis ); + if( lastbins ) free( lastbins ); + if( advances ) free( advances ); + + gbinqtys = malloc( sizeof(float)*bins ); + gbinqtyc = malloc( sizeof(float)*bins ); + phis = malloc( sizeof(float)*bins ); + lastbins = malloc( sizeof(float)*bins ); + advances = malloc( sizeof(float)*bins ); + + memset( gbinqtys, 0, sizeof(float)*bins ); + memset( gbinqtyc, 0, sizeof(float)*bins ); + memset( phis, 0, sizeof(float)*bins ); + memset( lastbins, 0, sizeof(float)*bins ); + + } + memcpy( outbins, lastbins, sizeof(float)*bins ); + + for( i = 0; i < bins; i++ ) + { + float freq = frequencies[i]; + advances[i] = 3.14159*2.0/freq; + } + + gbins = bins; + gfrequencies = frequencies; + goutbins = outbins; + gspeedup = speedup; + gq = q; + + place_in_data_buffer = (place_in_data_buffer+1)%size_of_data_buffer; + + int didrun = 0; + for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) + { + float fin = ((float)((int)(databuffer[i] * 127))) / 127.0; //simulate 8-bit input (it looks FINE!) + HandleProgressive( fin ); + didrun = 1; + } + last_place = place_in_data_buffer; + + if( didrun ) + { + memcpy( lastbins, outbins, sizeof(float)*bins ); + } + +/* for( i = 0; i < bins; i++ ) + { + printf( "%0.2f ", outbins[i]*100 ); + } + printf( "\n" );*/ + +} + + + + + + + +/////////////////////////////INTEGER DFT + + + + +//NOTES to self: +// +// Let's say we want to try this on an AVR. +// 24 bins, 5 octaves = 120 bins. +// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :( +// We can do two at the same time, this frees us up some + +static uint8_t donefirstrun; +static int8_t sintable[512]; //Actually [sin][cos] pairs. + + +//LDD instruction on AVR can read with constant offset. We can set Y to be the place in the buffer, and read with offset. +static uint16_t * datspace; //(advances,places,isses,icses) + +void HandleProgressiveInt( int8_t sample1, int8_t sample2 ) +{ + int i; + int16_t ts, tc; + int16_t tmp1; + int8_t s1, c1; + uint16_t ipl, localipl, adv; + + uint16_t * ds = &datspace[0]; + int8_t * st; + //Clocks are listed for AVR. + + //Estimated 78 minimum instructions... So for two pairs each... just over 4ksps, theoretical. + //Running overall at ~2kHz. With GCC: YUCK! 102 cycles!!! + for( i = 0; i < gbins; i++ ) //Loop, fixed size = 3 + 2 cycles N/A + { + //12 cycles MIN + adv = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4 + ipl = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4 + + //13 cycles MIN + ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2 + localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4 + + st = &sintable[localipl]; + s1 = *(st++); //Read s1 component out of table. 2+2 cycles 2 + c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4 + + ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2 ->Deferred + tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2 ->Deferred + + + //15 cycles MIN + ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2 + localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4 + + // need to load Z with 'sintable' and add localipl 2 + st = &sintable[localipl]; + s1 = *(st++); //Read s1 component out of table. 2 cycles 2 + c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4 + + ts += (s1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 ->Deferred + tc += (c1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 ->Deferred + + + //Add TS and TC to the datspace stuff. (24 instructions) + tmp1 = (*ds); //Read out, sin component. 4 Accurate. + tmp1 -= tmp1>>7; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14 + tmp1 += ts>>7; //Add MSBs with carry 2 -> 6 AS/IS: 6 + + *(ds++) = tmp1; //Store values back 4 + + tmp1 = *ds; //Read out, sin component. 4 + tmp1 -= tmp1>>7; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14 + tmp1 += tc>>7; //Add MSBs with carry 2 -> 6 AS/IS: 6 + + *ds++ = tmp1; //Store values back 4 + + *(ds-3) = ipl; //Store values back 4 AS/IS: 6 + + //AS-IS: 8 loop overhead. + } +} + +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 ) +{ + int i; + static int last_place; + + if( !donefirstrun ) + { + donefirstrun = 1; + for( i = 0; i < 256; i++ ) + { + sintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); + sintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); + } + } + + if( gbins != bins ) + { + gbins = bins; + if( datspace ) free( datspace ); + datspace = malloc( bins * 2 * 4 ); + } + + + for( i = 0; i < bins; i++ ) + { + float freq = frequencies[i]; + datspace[i*4] = 65536.0/freq; + } + + + for( i = last_place; i != ( place_in_data_buffer&0xffffe ); i = (i+2)%size_of_data_buffer ) + { + int8_t ifr1 = (int8_t)( ((databuffer[i+0]) ) * 127 ); + int8_t ifr2 = (int8_t)( ((databuffer[i+1]) ) * 127 ); +// printf( "%d %d\n", i, place_in_data_buffer&0xffffe ); + HandleProgressiveInt( ifr1, ifr2 ); + } + + last_place = place_in_data_buffer&0xfffe; + + //Extract bins. + for( i = 0; i < bins; i++ ) + { + int16_t isps = datspace[i*4+2]; + int16_t ispc = datspace[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 + + + + + + + + + +////////////////////////SKIPPY DFT + + +//NOTES to self: +// +// Let's say we want to try this on an AVR. +// 24 bins, 5 octaves = 120 bins. +// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :( +// We can do two at the same time, this frees us up some + +static uint8_t Sdonefirstrun; +//int8_t Ssintable[512]; //Actually [sin][cos] pairs. +static const int8_t Ssintable[512] = { + 0, 127, 3, 126, 6, 126, 9, 126, 12, 126, 15, 126, 18, 125, 21, 125, + 24, 124, 27, 123, 30, 123, 33, 122, 36, 121, 39, 120, 42, 119, 45, 118, + 48, 117, 51, 116, 54, 114, 57, 113, 59, 112, 62, 110, 65, 108, 67, 107, + 70, 105, 73, 103, 75, 102, 78, 100, 80, 98, 82, 96, 85, 94, 87, 91, + 89, 89, 91, 87, 94, 85, 96, 82, 98, 80, 100, 78, 102, 75, 103, 73, + 105, 70, 107, 67, 108, 65, 110, 62, 112, 59, 113, 57, 114, 54, 116, 51, + 117, 48, 118, 45, 119, 42, 120, 39, 121, 36, 122, 33, 123, 30, 123, 27, + 124, 24, 125, 21, 125, 18, 126, 15, 126, 12, 126, 9, 126, 6, 126, 3, + 127, 0, 126, -3, 126, -6, 126, -9, 126, -12, 126, -15, 125, -18, 125, -21, + 124, -24, 123, -27, 123, -30, 122, -33, 121, -36, 120, -39, 119, -42, 118, -45, + 117, -48, 116, -51, 114, -54, 113, -57, 112, -59, 110, -62, 108, -65, 107, -67, + 105, -70, 103, -73, 102, -75, 100, -78, 98, -80, 96, -82, 94, -85, 91, -87, + 89, -89, 87, -91, 85, -94, 82, -96, 80, -98, 78,-100, 75,-102, 73,-103, + 70,-105, 67,-107, 65,-108, 62,-110, 59,-111, 57,-113, 54,-114, 51,-116, + 48,-117, 45,-118, 42,-119, 39,-120, 36,-121, 33,-122, 30,-123, 27,-123, + 24,-124, 21,-125, 18,-125, 15,-126, 12,-126, 9,-126, 6,-126, 3,-126, + 0,-127, -3,-126, -6,-126, -9,-126, -12,-126, -15,-126, -18,-125, -21,-125, + -24,-124, -27,-123, -30,-123, -33,-122, -36,-121, -39,-120, -42,-119, -45,-118, + -48,-117, -51,-116, -54,-114, -57,-113, -59,-112, -62,-110, -65,-108, -67,-107, + -70,-105, -73,-103, -75,-102, -78,-100, -80, -98, -82, -96, -85, -94, -87, -91, + -89, -89, -91, -87, -94, -85, -96, -82, -98, -80,-100, -78,-101, -75,-103, -73, + -105, -70,-107, -67,-108, -65,-110, -62,-111, -59,-113, -57,-114, -54,-116, -51, + -117, -48,-118, -45,-119, -42,-120, -39,-121, -36,-122, -33,-123, -30,-123, -27, + -124, -24,-125, -21,-125, -18,-126, -15,-126, -12,-126, -9,-126, -6,-126, -3, + -127, 0,-126, 3,-126, 6,-126, 9,-126, 12,-126, 15,-125, 18,-125, 21, + -124, 24,-123, 27,-123, 30,-122, 33,-121, 36,-120, 39,-119, 42,-118, 45, + -117, 48,-116, 51,-114, 54,-113, 57,-112, 59,-110, 62,-108, 65,-107, 67, + -105, 70,-103, 73,-102, 75,-100, 78, -98, 80, -96, 82, -94, 85, -91, 87, + -89, 89, -87, 91, -85, 94, -82, 96, -80, 98, -78, 100, -75, 101, -73, 103, + -70, 105, -67, 107, -65, 108, -62, 110, -59, 111, -57, 113, -54, 114, -51, 116, + -48, 117, -45, 118, -42, 119, -39, 120, -36, 121, -33, 122, -30, 123, -27, 123, + -24, 124, -21, 125, -18, 125, -15, 126, -12, 126, -9, 126, -6, 126, -3, 126,}; +/** The above table was created using the following code: +#include +#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( "static 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; +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 ) +{ + int i; + int16_t ts, tc; + int16_t tmp1; + int8_t s1, c1; + uint16_t ipl, localipl, adv; + + uint8_t oct = Sdo_this_octave[Swhichoctaveplace]; + Swhichoctaveplace ++; + Swhichoctaveplace &= BINCYCLE-1; + + if( oct > 128 ) + { + //Special: This is when we can update everything. + +/* if( (rand()%100) == 0 ) + { + for( i = 0; i < FIXBINS; i++ ) +// printf( "%0.2f ",goutbins[i]*100 ); + printf( "(%d %d)",Sdatspace[i*4+2], Sdatspace[i*4+3] ); + printf( "\n" ); + } */ + + for( i = 0; i < FIXBINS; i++ ) + { + int16_t isps = Sdatspace[i*4+2]; + int16_t ispc = Sdatspace[i*4+3]; + // printf( "%d (%d %d)\n", mux, isps, ispc ); + + int octave = i / FIXBPERO; +// mux >>= octave; + +#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]; + const int8_t * st; + + sample1 = Saccum_octavebins[oct]>>(OCTAVES-oct); + Saccum_octavebins[oct] = 0; + + for( i = 0; i < FIXBPERO; i++ ) //Loop, fixed size = 3 + 2 cycles N/A + { + //12 cycles MIN + adv = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4 + ipl = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4 + + //13 cycles MIN + ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2 + localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4 + + st = &Ssintable[localipl]; + s1 = *(st++); //Read s1 component out of table. 2+2 cycles 2 + c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4 + + ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2 ->Deferred + tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2 ->Deferred + + + //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>>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>>SHIFT_ADD_DETAIL; //Add MSBs with carry 2 -> 6 AS/IS: 6 + + *ds++ = tmp1; //Store values back 4 + + *(ds-3) = ipl; //Store values back 4 AS/IS: 6 + + //AS-IS: 8 loop overhead. + } +} + +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; + static int last_place; + + memset( outbins, 0, bins * sizeof( float ) ); + goutbins = outbins; + + memcpy( outbins, backupbins, FIXBINS*4 ); + + if( FIXBINS != bins ) + { + fprintf( stderr, "Error: Bins was reconfigured. skippy requires a constant number of bins.\n" ); + return; + } + + +//printf( "SKIPPY\n" ); + + if( !Sdonefirstrun ) + { + SetupDFTProgressiveIntegerSkippy(); + Sdonefirstrun = 1; + } + + UpdateBinsForProgressiveIntegerSkippy( frequencies ); + + for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) + { + int8_t ifr1 = (int8_t)( ((databuffer[i]) ) * 127 ); + HandleProgressiveIntSkippy( ifr1 ); + HandleProgressiveIntSkippy( ifr1 ); + } + + last_place = place_in_data_buffer; + + memcpy( backupbins, outbins, FIXBINS*4 ); +} + +#endif + + + + diff --git a/dft.h b/dft.h index 7fedc79..19d845e 100644 --- a/dft.h +++ b/dft.h @@ -1,16 +1,76 @@ #ifndef _DFT_H #define _DFT_H -//XXX WARNING: TODO: the last two parameters are a double due to a compiler bug. +#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. void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q ); -//Skip many of the samples on lower frequencies; TODO: Need to fix the nyquist problem where high frequencies show low-frequency components. +//Skip many of the samples on lower frequencies. //Speedup = target number of data points void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); +//An unusual tool to do a "progressive" DFT, using data from previous rounds. +void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); + +//A progressive DFT that's done using only low-bit integer math. +//This is almost fast enough to work on an AVR, with two AVRs, it's likely that it could be powerful enough. +//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 + +#ifndef FIXBINS +#define FIXBINS (FIXBPERO*OCTAVES) +#endif + +#ifndef BINCYCLE +#define BINCYCLE (1< +#include +#include + +#include +//#include "ssc.h" +//#include "at.h" + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; +//extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen]; + +LOCAL void uart0_rx_intr_handler(void *para); + +/****************************************************************************** + * FunctionName : uart_config + * Description : Internal used function + * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled + * UART1 just used for debug output + * Parameters : uart_no, use UART0 or UART1 defined ahead + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +uart_config(uint8 uart_no) +{ + if (uart_no == UART1) + { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } + else + { + /* rcv_buff size if 0x100 */ + ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); +// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); + } + + uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); + + WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity + | UartDev.parity + | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) + | (UartDev.data_bits << UART_BIT_NUM_S)); + + //clear rx and tx fifo,not ready + SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + + //set rx fifo trigger +// WRITE_PERI_REG(UART_CONF1(uart_no), +// ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | +// ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) | +// UART_RX_FLOW_EN); + if (uart_no == UART0) + { + //set rx fifo trigger + WRITE_PERI_REG(UART_CONF1(uart_no), + ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | + ((0x01 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | + UART_RX_FLOW_EN); + } + else + { + WRITE_PERI_REG(UART_CONF1(uart_no), + ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); + } + + //clear all interrupt + WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); + //enable rx_interrupt + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); +} + +/****************************************************************************** + * FunctionName : uart1_tx_one_char + * Description : Internal used function + * Use uart1 interface to transfer one char + * Parameters : uint8 TxChar - character to tx + * Returns : OK +*******************************************************************************/ +LOCAL STATUS +uart_tx_one_char(uint8 uart, uint8 TxChar) +{ + while (true) + { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { + break; + } + } + + WRITE_PERI_REG(UART_FIFO(uart) , TxChar); + return OK; +} + +/****************************************************************************** + * FunctionName : uart1_write_char + * Description : Internal used function + * Do some special deal while tx char is '\r' or '\n' + * Parameters : char c - character to tx + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +uart1_write_char(char c) +{ + if (c == '\n') + { + uart_tx_one_char(UART1, '\r'); + uart_tx_one_char(UART1, '\n'); + } + else if (c == '\r') + { + } + else + { + uart_tx_one_char(UART1, c); + } +} +/****************************************************************************** + * FunctionName : uart0_tx_buffer + * Description : use uart0 to transfer buffer + * Parameters : uint8 *buf - point to send buffer + * uint16 len - buffer len + * Returns : +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart0_tx_buffer(uint8 *buf, uint16 len) +{ + uint16 i; + + for (i = 0; i < len; i++) + { + uart_tx_one_char(UART0, buf[i]); + } +} + +/****************************************************************************** + * FunctionName : uart0_sendStr + * Description : use uart0 to transfer buffer + * Parameters : uint8 *buf - point to send buffer + * uint16 len - buffer len + * Returns : +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart0_sendStr(const char *str) +{ + while(*str) + { + uart_tx_one_char(UART0, *str++); + } +} + +/****************************************************************************** + * FunctionName : uart0_rx_intr_handler + * Description : Internal used function + * UART0 interrupt handler, add self handle code inside + * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg + * Returns : NONE +*******************************************************************************/ +extern void at_recvTask(void); + +LOCAL void +uart0_rx_intr_handler(void *para) +{ + /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents + * uart1 and uart0 respectively + */ +// RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para; +// uint8 RcvChar; + uint8 uart_no = UART0;//UartDev.buff_uart_no; + +// if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) +// { +// return; +// } + if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) + { + at_recvTask(); + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); + } + +// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); + +// if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) +// { +// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF; +// at_recvTask(); +// *(pRxBuff->pWritePos) = RcvChar; + +// system_os_post(at_recvTaskPrio, NULL, RcvChar); + +// //insert here for get one command line from uart +// if (RcvChar == '\r') +// { +// pRxBuff->BuffState = WRITE_OVER; +// } +// +// pRxBuff->pWritePos++; +// +// if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) +// { +// // overflow ...we may need more error handle here. +// pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ; +// } +// } +} + +/****************************************************************************** + * FunctionName : uart_init + * Description : user interface for init uart + * Parameters : UartBautRate uart0_br - uart0 bautrate + * UartBautRate uart1_br - uart1 bautrate + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart_init(UartBautRate uart0_br, UartBautRate uart1_br) +{ + // rom use 74880 baut_rate, here reinitialize + UartDev.baut_rate = uart0_br; + uart_config(UART0); + UartDev.baut_rate = uart1_br; + uart_config(UART1); + ETS_UART_INTR_ENABLE(); + + // install uart1 putc callback + os_install_putc1((void *)uart1_write_char); +} + +void ICACHE_FLASH_ATTR +uart_reattach() +{ + uart_init(BIT_RATE_74880, BIT_RATE_74880); +// ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff)); +// ETS_UART_INTR_ENABLE(); +} diff --git a/embedded8266/image.elf b/embedded8266/image.elf new file mode 100755 index 0000000..d7a260c Binary files /dev/null and b/embedded8266/image.elf differ diff --git a/embedded8266/include/driver/uart.h b/embedded8266/include/driver/uart.h new file mode 100644 index 0000000..957621b --- /dev/null +++ b/embedded8266/include/driver/uart.h @@ -0,0 +1,101 @@ +#ifndef UART_APP_H +#define UART_APP_H + +#include "uart_register.h" +#include "eagle_soc.h" +#include "c_types.h" + +#define RX_BUFF_SIZE 256 +#define TX_BUFF_SIZE 100 +#define UART0 0 +#define UART1 1 + +typedef enum { + FIVE_BITS = 0x0, + SIX_BITS = 0x1, + SEVEN_BITS = 0x2, + EIGHT_BITS = 0x3 +} UartBitsNum4Char; + +typedef enum { + ONE_STOP_BIT = 0, + ONE_HALF_STOP_BIT = BIT2, + TWO_STOP_BIT = BIT2 +} UartStopBitsNum; + +typedef enum { + NONE_BITS = 0, + ODD_BITS = 0, + EVEN_BITS = BIT4 +} UartParityMode; + +typedef enum { + STICK_PARITY_DIS = 0, + STICK_PARITY_EN = BIT3 | BIT5 +} UartExistParity; + +typedef enum { + BIT_RATE_9600 = 9600, + BIT_RATE_19200 = 19200, + BIT_RATE_38400 = 38400, + BIT_RATE_57600 = 57600, + BIT_RATE_74880 = 74880, + BIT_RATE_115200 = 115200, + BIT_RATE_230400 = 230400, + BIT_RATE_460800 = 460800, + BIT_RATE_921600 = 921600 +} UartBautRate; + +typedef enum { + NONE_CTRL, + HARDWARE_CTRL, + XON_XOFF_CTRL +} UartFlowCtrl; + +typedef enum { + EMPTY, + UNDER_WRITE, + WRITE_OVER +} RcvMsgBuffState; + +typedef struct { + uint32 RcvBuffSize; + uint8 *pRcvMsgBuff; + uint8 *pWritePos; + uint8 *pReadPos; + uint8 TrigLvl; //JLU: may need to pad + RcvMsgBuffState BuffState; +} RcvMsgBuff; + +typedef struct { + uint32 TrxBuffSize; + uint8 *pTrxBuff; +} TrxMsgBuff; + +typedef enum { + BAUD_RATE_DET, + WAIT_SYNC_FRM, + SRCH_MSG_HEAD, + RCV_MSG_BODY, + RCV_ESC_CHAR, +} RcvMsgState; + +typedef struct { + UartBautRate baut_rate; + UartBitsNum4Char data_bits; + UartExistParity exist_parity; + UartParityMode parity; // chip size in byte + UartStopBitsNum stop_bits; + UartFlowCtrl flow_ctrl; + RcvMsgBuff rcv_buff; + TrxMsgBuff trx_buff; + RcvMsgState rcv_state; + int received; + int buff_uart_no; //indicate which uart use tx/rx buffer +} UartDevice; + +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +void uart0_sendStr(const char *str); + +#endif + diff --git a/embedded8266/include/driver/uart_register.h b/embedded8266/include/driver/uart_register.h new file mode 100644 index 0000000..6398879 --- /dev/null +++ b/embedded8266/include/driver/uart_register.h @@ -0,0 +1,128 @@ +//Generated at 2012-07-03 18:44:06 +/* + * Copyright (c) 2010 - 2011 Espressif System + * + */ + +#ifndef UART_REGISTER_H_INCLUDED +#define UART_REGISTER_H_INCLUDED +#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) +//version value:32'h062000 + +#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) +#define UART_RXFIFO_RD_BYTE 0x000000FF +#define UART_RXFIFO_RD_BYTE_S 0 + +#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) +#define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) +#define UART_BRK_DET_INT_RAW (BIT(7)) +#define UART_CTS_CHG_INT_RAW (BIT(6)) +#define UART_DSR_CHG_INT_RAW (BIT(5)) +#define UART_RXFIFO_OVF_INT_RAW (BIT(4)) +#define UART_FRM_ERR_INT_RAW (BIT(3)) +#define UART_PARITY_ERR_INT_RAW (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) +#define UART_RXFIFO_FULL_INT_RAW (BIT(0)) + +#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) +#define UART_RXFIFO_TOUT_INT_ST (BIT(8)) +#define UART_BRK_DET_INT_ST (BIT(7)) +#define UART_CTS_CHG_INT_ST (BIT(6)) +#define UART_DSR_CHG_INT_ST (BIT(5)) +#define UART_RXFIFO_OVF_INT_ST (BIT(4)) +#define UART_FRM_ERR_INT_ST (BIT(3)) +#define UART_PARITY_ERR_INT_ST (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) +#define UART_RXFIFO_FULL_INT_ST (BIT(0)) + +#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) +#define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) +#define UART_BRK_DET_INT_ENA (BIT(7)) +#define UART_CTS_CHG_INT_ENA (BIT(6)) +#define UART_DSR_CHG_INT_ENA (BIT(5)) +#define UART_RXFIFO_OVF_INT_ENA (BIT(4)) +#define UART_FRM_ERR_INT_ENA (BIT(3)) +#define UART_PARITY_ERR_INT_ENA (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) +#define UART_RXFIFO_FULL_INT_ENA (BIT(0)) + +#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) +#define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) +#define UART_BRK_DET_INT_CLR (BIT(7)) +#define UART_CTS_CHG_INT_CLR (BIT(6)) +#define UART_DSR_CHG_INT_CLR (BIT(5)) +#define UART_RXFIFO_OVF_INT_CLR (BIT(4)) +#define UART_FRM_ERR_INT_CLR (BIT(3)) +#define UART_PARITY_ERR_INT_CLR (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) +#define UART_RXFIFO_FULL_INT_CLR (BIT(0)) + +#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) +#define UART_CLKDIV_CNT 0x000FFFFF +#define UART_CLKDIV_S 0 + +#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) +#define UART_GLITCH_FILT 0x000000FF +#define UART_GLITCH_FILT_S 8 +#define UART_AUTOBAUD_EN (BIT(0)) + +#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) +#define UART_TXD (BIT(31)) +#define UART_RTSN (BIT(30)) +#define UART_DTRN (BIT(29)) +#define UART_TXFIFO_CNT 0x000000FF +#define UART_TXFIFO_CNT_S 16 +#define UART_RXD (BIT(15)) +#define UART_CTSN (BIT(14)) +#define UART_DSRN (BIT(13)) +#define UART_RXFIFO_CNT 0x000000FF +#define UART_RXFIFO_CNT_S 0 + +#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) +#define UART_TXFIFO_RST (BIT(18)) +#define UART_RXFIFO_RST (BIT(17)) +#define UART_IRDA_EN (BIT(16)) +#define UART_TX_FLOW_EN (BIT(15)) +#define UART_LOOPBACK (BIT(14)) +#define UART_IRDA_RX_INV (BIT(13)) +#define UART_IRDA_TX_INV (BIT(12)) +#define UART_IRDA_WCTL (BIT(11)) +#define UART_IRDA_TX_EN (BIT(10)) +#define UART_IRDA_DPLX (BIT(9)) +#define UART_TXD_BRK (BIT(8)) +#define UART_SW_DTR (BIT(7)) +#define UART_SW_RTS (BIT(6)) +#define UART_STOP_BIT_NUM 0x00000003 +#define UART_STOP_BIT_NUM_S 4 +#define UART_BIT_NUM 0x00000003 +#define UART_BIT_NUM_S 2 +#define UART_PARITY_EN (BIT(1)) +#define UART_PARITY (BIT(0)) + +#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) +#define UART_RX_TOUT_EN (BIT(31)) +#define UART_RX_TOUT_THRHD 0x0000007F +#define UART_RX_TOUT_THRHD_S 24 +#define UART_RX_FLOW_EN (BIT(23)) +#define UART_RX_FLOW_THRHD 0x0000007F +#define UART_RX_FLOW_THRHD_S 16 +#define UART_TXFIFO_EMPTY_THRHD 0x0000007F +#define UART_TXFIFO_EMPTY_THRHD_S 8 +#define UART_RXFIFO_FULL_THRHD 0x0000007F +#define UART_RXFIFO_FULL_THRHD_S 0 + +#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) +#define UART_LOWPULSE_MIN_CNT 0x000FFFFF +#define UART_LOWPULSE_MIN_CNT_S 0 + +#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) +#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF +#define UART_HIGHPULSE_MIN_CNT_S 0 + +#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) +#define UART_PULSE_NUM_CNT 0x0003FF +#define UART_PULSE_NUM_CNT_S 0 + +#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) +#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) +#endif // UART_REGISTER_H_INCLUDED diff --git a/embedded8266/include/string.h b/embedded8266/include/string.h new file mode 100644 index 0000000..bb97dcd --- /dev/null +++ b/embedded8266/include/string.h @@ -0,0 +1 @@ +//Nothing here. diff --git a/embedded8266/include/user_config.h b/embedded8266/include/user_config.h new file mode 100644 index 0000000..ff3f4e7 --- /dev/null +++ b/embedded8266/include/user_config.h @@ -0,0 +1,10 @@ +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define USE_US_TIMER +#define USE_OPTIMIZE_PRINTF +#define ESP_PLATFORM 1 + +#endif + + diff --git a/embedded8266/user/colorchord.c b/embedded8266/user/colorchord.c new file mode 100644 index 0000000..9fd5152 --- /dev/null +++ b/embedded8266/user/colorchord.c @@ -0,0 +1,150 @@ +#include "colorchord.h" + +static uint8_t donefirstrun; +static int8_t sintable[512]; //Actually [sin][cos] pairs. + +//LDD instruction on AVR can read with constant offset. We can set Y to be the place in the buffer, and read with offset. +static uint16_t datspace[bins*4]; //(advances,places,isses,icses) + +// +void HandleProgressiveInt( int8_t sample1, int8_t sample2 ) +{ + int i; + uint16_t startpl = 0; + int16_t ts, tc; + int16_t tmp1; + int8_t s1, c1; + uint16_t ipl, localipl, adv; + + + //startpl maps to 'Y' + // + + + //Estimated 68 minimum instructions... So for two pairs each... just under 5ksps, theoretical. + //Running overall at ~2kHz. + for( i = 0; i < bins; i++ ) //Loop, fixed size = 3 + 2 cycles 5 + { + //12 cycles MIN + adv = datspace[startpl++]; //Read, indirect from RAM (and increment) 2+2 cycles 4 + ipl = datspace[startpl++]; //Read, indirect from RAM (and increment) 2+2 cycles 4 + + //13 cycles MIN + ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2 + localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 + + // need to load Z with 'sintable' and add localipl 2 + s1 = sintable[localipl++]; //Read s1 component out of table. 2+2 cycles 2 + c1 = sintable[localipl++]; //Read c1 component out of table. 2 cycles 2 + + ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2 + tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2 + + + //15 cycles MIN + ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2 + localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 + + // need to load Z with 'sintable' and add localipl 2 + s1 = sintable[localipl++]; //Read s1 component out of table. 2 cycles 2 + c1 = sintable[localipl++]; //Read c1 component out of table. 2 cycles 2 + + ts += (s1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 + tc += (c1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 + + + //Add TS and TC to the datspace stuff. (24 instructions) + tmp1 = datspace[startpl]; //Read out, sin component. 4 + tmp1 -= tmp1>>6; //Subtract from the MSB (with carry) 2 + tmp1 += ts>>6; //Add MSBs with carry 2 + + datspace[startpl++] = tmp1; //Store values back 4 + + tmp1 = datspace[startpl]; //Read out, sin component. 4 + tmp1 -= tmp1>>6; //Subtract from the MSB (with carry) 2 + tmp1 += tc>>6; //Add MSBs with carry 2 + + datspace[startpl++] = tmp1; //Store values back 4 + + datspace[startpl-3] = ipl; //Store values back 4 + } +} + +void SetupConstants() +{ + int i; + static int last_place; + + if( !donefirstrun ) + { + donefirstrun = 1; + for( i = 0; i < 256; i++ ) + { + sintable[i*2+0] = i;//(int8_t)((sin( i / 256.0 * 6.283 ) * 127.0)); + sintable[i*2+1] = i+1;//(int8_t)((cos( i / 256.0 * 6.283 ) * 127.0)); + } + } + + + for( i = 0; i < bins; i++ ) + { + float freq = i;//frequencies[i]; + datspace[i*4] = 65536.0/freq; + } + +} + +/* +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 ) +{ + int i; + static int last_place; + + if( !donefirstrun ) + { + donefirstrun = 1; + for( i = 0; i < 256; i++ ) + { + sintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); + sintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); + } + } + + if( gbins != bins ) + { + gbins = bins; + if( datspace ) free( datspace ); + datspace = malloc( bins * 2 * 4 ); + } + + + for( i = 0; i < bins; i++ ) + { + float freq = frequencies[i]; + datspace[i*4] = 65536.0/freq; + } + + + for( i = last_place; i != ( place_in_data_buffer&0xffffe ); i = (i+2)%size_of_data_buffer ) + { + int8_t ifr1 = (int8_t)( ((databuffer[i+0]) ) * 127 ); + int8_t ifr2 = (int8_t)( ((databuffer[i+1]) ) * 127 ); +// printf( "%d %d\n", i, place_in_data_buffer&0xffffe ); + HandleProgressiveInt( ifr1, ifr2 ); + } + + last_place = place_in_data_buffer&0xfffe; + + //Extract bins. + for( i = 0; i < bins; i++ ) + { + int16_t isps = datspace[i*4+2]; + int16_t ispc = datspace[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"); +} + +*/ diff --git a/embedded8266/user/colorchord.h b/embedded8266/user/colorchord.h new file mode 100644 index 0000000..714deb8 --- /dev/null +++ b/embedded8266/user/colorchord.h @@ -0,0 +1,17 @@ +#ifndef _COLORCHORD_H +#define _COLORCHORD_H + +#include "mem.h" +#include "c_types.h" +#include "user_interface.h" +#include "ets_sys.h" +#include "osapi.h" + +#define bins 120 + +void HandleProgressiveInt( int8_t sample1, int8_t sample2 ); +void SetupConstants(); + +#endif + + diff --git a/embedded8266/user/mystuff.c b/embedded8266/user/mystuff.c new file mode 100644 index 0000000..78700b6 --- /dev/null +++ b/embedded8266/user/mystuff.c @@ -0,0 +1,3 @@ +#include "mystuff.h" + +char generic_print_buffer[384]; diff --git a/embedded8266/user/mystuff.h b/embedded8266/user/mystuff.h new file mode 100644 index 0000000..95756a8 --- /dev/null +++ b/embedded8266/user/mystuff.h @@ -0,0 +1,8 @@ +#ifndef _MYSTUFF_H +#define _MYSTUFF_H + +extern char generic_print_buffer[384]; + +#define printf( ... ) os_sprintf( generic_print_buffer, __VA_ARGS__ ); uart0_sendStr( generic_print_buffer ); + +#endif diff --git a/embedded8266/user/user_main.c b/embedded8266/user/user_main.c new file mode 100644 index 0000000..aa71bac --- /dev/null +++ b/embedded8266/user/user_main.c @@ -0,0 +1,143 @@ +#include "mem.h" +#include "c_types.h" +#include "user_interface.h" +#include "ets_sys.h" +#include "driver/uart.h" +#include "osapi.h" +#include "espconn.h" +#include "mystuff.h" +#include "ws2812.h" + +#define PORT 7777 +#define SERVER_TIMEOUT 1000 +#define MAX_CONNS 5 +#define MAX_FRAME 2000 + +#define procTaskPrio 0 +#define procTaskQueueLen 1 + + +static volatile os_timer_t some_timer; +static struct espconn *pUdpServer; + + + +//Note to self. In future consider looking at this: http://pastebin.com/6eLxSrNz + + + + + + + + +//Tasks that happen all the time. + +os_event_t procTaskQueue[procTaskQueueLen]; +static void ICACHE_FLASH_ATTR +procTask(os_event_t *events) +{ + system_os_post(procTaskPrio, 0, 0 ); + if( events->sig == 0 && events->par == 0 ) + { + //Idle Event. + } +} + + +//Timer event. +static void ICACHE_FLASH_ATTR + myTimer(void *arg) +{ + int i; + uart0_sendStr("."); + SetupConstants(); + +#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ + gpio_output_set(bit_value<type = ESPCONN_UDP; + pUdpServer->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); + pUdpServer->proto.udp->local_port = 7777; + espconn_regist_recvcb(pUdpServer, udpserver_recv); + + wifi_station_dhcpc_start(); + + if( espconn_create( pUdpServer ) ) + { + while(1) { uart0_sendStr( "\r\nFAULT\r\n" ); } + } + + //XXX TODO figure out how to safely re-allow this. + ets_wdt_disable(); + + char outbuffer[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,0xff,0xff, 0x00,0xff,0x00 }; + WS2812OutBuffer( outbuffer, 1 ); //Initialize the output. + + //Add a process + system_os_task(procTask, procTaskPrio, procTaskQueue, procTaskQueueLen); + + uart0_sendStr("\r\nCustom Server\r\n"); + WS2812OutBuffer( outbuffer, sizeof(outbuffer) ); + + + //Timer example + os_timer_disarm(&some_timer); + os_timer_setfn(&some_timer, (os_timer_func_t *)myTimer, NULL); + os_timer_arm(&some_timer, 1000, 1); + + system_os_post(procTaskPrio, 0, 0 ); +} + + diff --git a/embedded8266/user/ws2812.c b/embedded8266/user/ws2812.c new file mode 100644 index 0000000..6609723 --- /dev/null +++ b/embedded8266/user/ws2812.c @@ -0,0 +1,61 @@ +#include "ws2812.h" +#include "ets_sys.h" +#include "mystuff.h" +#include "osapi.h" + +#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ + gpio_output_set(bit_value< + +#ifndef CCEMBEDDED +#include +#include +#include +static float * goutbins; +#endif + +uint16_t embeddedbins32[FIXBINS]; + +//NOTES to self: +// +// Let's say we want to try this on an AVR. +// 24 bins, 5 octaves = 120 bins. +// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :( +// We can do two at the same time, this frees us up some + +static uint8_t Sdonefirstrun; + +//A table of precomputed sin() values. Ranging -1500 to +1500 +//If we increase this, it may cause overflows elsewhere in code. +const int16_t Ssinonlytable[256] = { + 0, 36, 73, 110, 147, 183, 220, 256, + 292, 328, 364, 400, 435, 470, 505, 539, + 574, 607, 641, 674, 707, 739, 771, 802, + 833, 863, 893, 922, 951, 979, 1007, 1034, + 1060, 1086, 1111, 1135, 1159, 1182, 1204, 1226, + 1247, 1267, 1286, 1305, 1322, 1339, 1355, 1371, + 1385, 1399, 1412, 1424, 1435, 1445, 1455, 1463, + 1471, 1477, 1483, 1488, 1492, 1495, 1498, 1499, + 1500, 1499, 1498, 1495, 1492, 1488, 1483, 1477, + 1471, 1463, 1455, 1445, 1435, 1424, 1412, 1399, + 1385, 1371, 1356, 1339, 1322, 1305, 1286, 1267, + 1247, 1226, 1204, 1182, 1159, 1135, 1111, 1086, + 1060, 1034, 1007, 979, 951, 922, 893, 863, + 833, 802, 771, 739, 707, 674, 641, 607, + 574, 539, 505, 470, 435, 400, 364, 328, + 292, 256, 220, 183, 147, 110, 73, 36, + 0, -36, -73, -110, -146, -183, -219, -256, + -292, -328, -364, -399, -435, -470, -505, -539, + -573, -607, -641, -674, -706, -739, -771, -802, + -833, -863, -893, -922, -951, -979, -1007, -1034, + -1060, -1086, -1111, -1135, -1159, -1182, -1204, -1226, + -1247, -1267, -1286, -1305, -1322, -1339, -1355, -1371, + -1385, -1399, -1412, -1424, -1435, -1445, -1454, -1463, + -1471, -1477, -1483, -1488, -1492, -1495, -1498, -1499, + -1500, -1499, -1498, -1495, -1492, -1488, -1483, -1477, + -1471, -1463, -1455, -1445, -1435, -1424, -1412, -1399, + -1385, -1371, -1356, -1339, -1322, -1305, -1286, -1267, + -1247, -1226, -1204, -1182, -1159, -1135, -1111, -1086, + -1060, -1034, -1007, -979, -951, -923, -893, -863, + -833, -802, -771, -739, -707, -674, -641, -608, + -574, -540, -505, -470, -435, -400, -364, -328, + -292, -256, -220, -183, -147, -110, -73, -37,}; + + +/** The above table was created using the following code: +#include +#include +#include + +int16_t Ssintable[256]; //Actually, just [sin]. + +int main() +{ + int i; + for( i = 0; i < 256; i++ ) + { + Ssintable[i] = (int16_t)((sinf( i / 256.0 * 6.283 ) * 1500.0)); + } + + printf( "const int16_t Ssinonlytable[256] = {" ); + for( i = 0; i < 256; i++ ) + { + if( !(i & 0x7 ) ) + { + printf( "\n\t" ); + } + printf( "%6d," ,Ssintable[i] ); + } + printf( "};\n" ); +} */ + + + +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) + +//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]; + +//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 UpdateOutputBins32() +{ + int i; + int * ipt = &Sdatspace32BOut[0]; + for( i = 0; i < FIXBINS; i++ ) + { + int16_t isps = *(ipt++)>>16; + int16_t ispc = *(ipt++)>>16; + + 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 ); + //reasonable (but arbitrary amplification) + goutbins[i] /= (78<> octave; + } +} + +static void HandleInt( int16_t sample ) +{ + int i; + uint16_t adv; + uint8_t localipl; + + uint8_t oct = Sdo_this_octave[Swhichoctaveplace]; + Swhichoctaveplace ++; + Swhichoctaveplace &= BINCYCLE-1; + + if( oct > 128 ) + { + //Special: This is when we can update everything. + //This gets run one out of every 1/(1<>DFTIIR; + + val = *(bins); + *(binsOut++) = val; + *(bins++) -= val>>DFTIIR; + } + return; + } + + + for( i = 0; i < OCTAVES;i++ ) + { + Saccum_octavebins[i] += sample; + } + + uint16_t * dsA = &Sdatspace32A[oct*FIXBPERO*2]; + int32_t * dsB = &Sdatspace32B[oct*FIXBPERO*2]; + + sample = Saccum_octavebins[oct]>>(OCTAVES-oct); + Saccum_octavebins[oct] = 0; + + for( i = 0; i < FIXBPERO; i++ ) + { + adv = *(dsA++); + localipl = *(dsA) >> 8; + *(dsA++) += adv; + + *(dsB++) += (Ssinonlytable[localipl] * sample); + //Get the cosine (1/4 wavelength out-of-phase with sin) + localipl += 64; + *(dsB++) += (Ssinonlytable[localipl] * sample); + } +} + +int SetupDFTProgressive32() +{ + int i; + int j; + + Sdonefirstrun = 1; + + 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 ) + { +#ifndef CCEMBEDDED + fprintf( stderr, "Error: algorithm fault.\n" ); + exit( -1 ); +#endif + return -1; + } + Sdo_this_octave[i] = OCTAVES-j-1; + } + return 0; +} + + + +void UpdateBins32( const uint16_t * frequencies ) +{ + int i; + for( i = 0; i < FIXBINS; i++ ) + { + uint16_t freq = frequencies[i%FIXBPERO]; + Sdatspace32A[i*2] = freq;// / oneoveroctave; + } +} + +void PushSample32( int16_t dat ) +{ + HandleInt( dat ); + HandleInt( dat ); +} + + +#ifndef CCEMBEDDED + +void UpdateBinsForDFT32( const float * frequencies ) +{ + int i; + for( i = 0; i < FIXBINS; i++ ) + { + float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))]; + Sdatspace32A[i*2] = (65536.0/freq);// / oneoveroctave; + } +} + +#endif + + +#ifndef CCEMBEDDED + +void DoDFTProgressive32( 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; + static int last_place; + + memset( outbins, 0, bins * sizeof( float ) ); + goutbins = outbins; + + memcpy( outbins, backupbins, FIXBINS*4 ); + + if( FIXBINS != bins ) + { + fprintf( stderr, "Error: Bins was reconfigured. skippy requires a constant number of bins.\n" ); + return; + } + + if( !Sdonefirstrun ) + { + SetupDFTProgressive32(); + Sdonefirstrun = 1; + } + + UpdateBinsForDFT32( frequencies ); + + for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) + { + int16_t ifr1 = (int16_t)( ((databuffer[i]) ) * 4095 ); + HandleInt( ifr1 ); + HandleInt( ifr1 ); + } + + UpdateOutputBins32(); + + last_place = place_in_data_buffer; + + memcpy( backupbins, outbins, FIXBINS*4 ); +} + +#endif + + + + diff --git a/embeddedcommon/DFT32.h b/embeddedcommon/DFT32.h new file mode 100644 index 0000000..ebc52e9 --- /dev/null +++ b/embeddedcommon/DFT32.h @@ -0,0 +1,75 @@ +#ifndef _DFT32_H +#define _DFT32_H + +#include + +//A 32-bit version of the DFT used for ColorChord. +//This header makes it convenient to use for an embedded system. +//The 32-bit DFT avoids some bit shifts, however it uses slightly +//more RAM and it uses a lot of 32-bit arithmatic. +// +//This is basically a clone of "ProgressiveIntegerSkippy" and changes +//made here should be backported there as well. + +//You can # define these to be other things elsewhere. +#ifndef OCTAVES +#define OCTAVES 5 +#endif + +#ifndef FIXBPERO +#define FIXBPERO 24 +#endif + +#ifndef FIXBINS +#define FIXBINS (FIXBPERO*OCTAVES) +#endif + +#ifndef BINCYCLE +#define BINCYCLE (1< + +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]; +uint8_t note_jumped_to[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 +#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; +} +*/ + + +#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; + } + +#ifdef USE_32DFT + UpdateBins32( fbins ); +#else + UpdateBinsForProgressiveIntegerSkippyInt( fbins ); +#endif +} + +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. +#ifdef USE_32DFT + SetupDFTProgressive32(); +#else + SetupDFTProgressiveIntegerSkippy(); +#endif + + //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; + uint8_t hitnotes[MAXNOTES]; + for( i = 0; i < MAXNOTES; i++ ) + { + hitnotes[i] = 0; + } + +#ifdef USE_32DFT + uint16_t * strens; + UpdateOutputBins32(); + strens = embeddedbins32; +#else + uint16_t * strens = embeddedbins; +#endif + + //Copy out the bins from the DFT to our fuzzed bins. + for( i = 0; i < FIXBINS; i++ ) + { + fuzzed_bins[i] = (fuzzed_bins[i] + (strens[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. + for( j = 0; j < FILTER_BLUR_PASSES; j++ ) + { + //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< 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< ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) ) + { + distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance; + } + + //If we find a note closer to where we are than any of the + //others, we can mark it as our desired note. + 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. + 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 we found a note to attach to, we have to use the IIR to + //increase the strength of the note, but we can't exactly snap + //it to the new strength. + if( marked_note != -1 ) + { + hitnotes[marked_note] = 1; + + 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<<3)>>(AMP_2_IIR_BITS)); + } + } + } + +#if 0 + for( i = 0; i < MAXNOTES; i++ ) + { + if( note_peak_freqs[i] == 255 ) continue; + printf( "%d / ", note_peak_amps[i] ); + } + printf( "\n" ); +#endif + + //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 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; + } + + if( distance > MAX_COMBINE_DISTANCE ) + { + continue; + } + + int into; + int from; + + if( note_peak_amps[i] > note_peak_amps[j] ) + { + into = i; + from = j; + } + else + { + into = j; + from = i; + } + + //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[into]; + int16_t amp2 = note_peak_amps[from]; + + //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; + + //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_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_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; + note_peak_amps[i] = 0; + note_peak_amps2[i] = 0; + } + } + + //We now have notes!!! +#if 0 + 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") ; +#endif + +#if 0 + for( i = 0; i < FIXBPERO; i++ ) + { + printf( "%4d ", folded_bins[i] ); + } + printf( "\n" ); +#endif + + +} + + diff --git a/embeddedcommon/embeddednf.h b/embeddedcommon/embeddednf.h new file mode 100644 index 0000000..4619300 --- /dev/null +++ b/embeddedcommon/embeddednf.h @@ -0,0 +1,82 @@ +#ifndef _EMBEDDEDNF_H +#define _EMBEDDEDNF_H + +//Use a 32-bit DFT. It won't work for AVRs, but for any 32-bit systems where +//they can multiply quickly, this is the bees knees. +#define USE_32DFT + +#ifndef DFREQ +#define DFREQ 8000 +#endif + +#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 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<>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( "\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<<8)/((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) >> 8; + 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], 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); +} + diff --git a/embeddedcommon/embeddedout.h b/embeddedcommon/embeddedout.h new file mode 100644 index 0000000..8a9685f --- /dev/null +++ b/embeddedcommon/embeddedout.h @@ -0,0 +1,27 @@ +#ifndef _EMBEDDEDOUT_H +#define _EMBEDDEDOUT_H + +#include "embeddednf.h" + + +//Controls brightness +#define NOTE_FINAL_AMP 12 //Number from 0...255 + +//Controls, basically, the minimum size of the splotches. +#define NERF_NOTE_PORP 15 //value from 0 to 255 + +#define NUM_LIN_LEDS 296 + +#define LIN_WRAPAROUND 0 //Whether the output lights wrap around. +#define SORT_NOTES 0 //Whether the notes will be sorted. + +extern uint8_t ledArray[]; +extern uint8_t ledOut[]; //[NUM_LIN_LEDS*3] +void UpdateLinearLEDs(); + +uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val ); +uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val ); //hue = 0..255 // TODO: TEST ME!!! + + +#endif + diff --git a/embeddedlinux/Makefile b/embeddedlinux/Makefile new file mode 100644 index 0000000..28b9233 --- /dev/null +++ b/embeddedlinux/Makefile @@ -0,0 +1,13 @@ +all : embeddedcc + +CFLAGS:=-Ofast -DCCEMBEDDED -I.. -flto -m32 -DDFREQ=11025 -I../embeddedcommon +LDFLAGS:=-ffunction-sections -Wl,--gc-sections -fno-asynchronous-unwind-tables -Wl,--strip-all + +embeddedcc : ../embeddedcommon/embeddednf.c ../embeddedcommon/DFT32.c embeddedcc.c ../embeddedcommon/embeddedout.c + gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) + +runembedded : embeddedcc + parec --format=u8 --rate=11025 --channels=1 --device=alsa_output.pci-0000_00_1b.0.analog-stereo.monitor --latency=128 | ./embeddedcc + +clean : + rm -rf embeddedcc *~ diff --git a/embeddedlinux/embeddedcc.c b/embeddedlinux/embeddedcc.c new file mode 100644 index 0000000..2b25c1e --- /dev/null +++ b/embeddedlinux/embeddedcc.c @@ -0,0 +1,74 @@ +// +// This is the teststrap for the Embedded ColorChord System. +// It is intended as a minimal scaffolding for testing Embedded ColorChord. +// + + +#include "embeddednf.h" +#include +#include +#include +#include +#include "embeddedout.h" + +struct sockaddr_in servaddr; +int sock; + +#define expected_lights 296 + +void NewFrame() +{ + int i; + char buffer[3000]; + + HandleFrameInfo(); + UpdateLinearLEDs(); + + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + + for( i = 0; i < expected_lights * 3; i++ ) + { + buffer[i+3] = ledOut[i]; + } + + int r = send(sock,buffer,expected_lights*3+3,0); +} + + +int main() +{ + int wf = 0; + int ci; + + sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); + printf( "%d\n", sock ); + + memset(&servaddr,0,sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr("192.168.0.245"); + servaddr.sin_port=htons(7777); + + connect( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) ); + + Init(); + + while( ( ci = getchar() ) != EOF ) + { + int cs = ci - 0x80; +#ifdef USE_32DFT + PushSample32( ((int8_t)cs)*32 ); +#else + Push8BitIntegerSkippy( (int8_t)cs ); +#endif + wf++; + if( wf == 128 ) + { + NewFrame(); + wf = 0; + } + } + return 0; +} + diff --git a/integerprog.conf b/integerprog.conf new file mode 100644 index 0000000..62f5ad6 --- /dev/null +++ b/integerprog.conf @@ -0,0 +1,5 @@ +do_progressive_dft = 3 +samplerate = 8000 +buffer = 64 +sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor + diff --git a/main.c b/main.c index cde602d..fd83569 100644 --- a/main.c +++ b/main.c @@ -15,8 +15,17 @@ #include "parameters.h" #include "hook.h" +#define NRDEFFILES 10 + +struct SoundDriver * sd; + #ifdef WIN32 #include +void WindowsTerm() +{ + CloseSound( sd ); +} + #endif int lastfps; @@ -26,6 +35,7 @@ char ** gargv; struct DriverInstances * outdriver[MAX_OUT_DRIVERS]; +int headless = 0; REGISTER_PARAM( headless, PAINT ); int set_screenx = 640; REGISTER_PARAM( set_screenx, PAINT ); int set_screeny = 480; REGISTER_PARAM( set_screeny, PAINT ); char sound_source[16]; REGISTER_PARAM( sound_source, PABUFFER ); @@ -35,7 +45,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; @@ -95,9 +105,17 @@ 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 ) continue; - fo += f; + 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; sound[soundhead] = fo; soundhead = (soundhead+1)%SOUNDCBSIZE; @@ -105,9 +123,15 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun else { float f = in[i*channelin+sample_channel]; - if( f < -1 || f > 1 ) continue; + if( f > -1 && f < 1 ) + { + f = (f>0)?1:-1; + } + + //printf( "Sound fault B %d/%d\n", i, samplesr ); sound[soundhead] = f; soundhead = (soundhead+1)%SOUNDCBSIZE; + } } @@ -121,7 +145,6 @@ void LoadFile( const char * filename ) { char * buffer; int r; - int i; FILE * f = fopen( filename, "rb" ); if( !f ) @@ -147,26 +170,69 @@ void LoadFile( const char * filename ) } free( buffer ); } +} - if( gargc > 2 ) +const char * InitialFile[NRDEFFILES]; +double FileTimes[NRDEFFILES]; +int InitialFileCount = 1; + +void SetEnvValues() +{ + int i; + int hits = 0; + for( i = 0; i < InitialFileCount; i++ ) { - for( i = 2; i < gargc; i++ ) + double ft = OGGetFileTime( InitialFile[i] ); + if( FileTimes[i] != ft ) + { + FileTimes[i] = ft; + hits++; + } + } + + if( !hits ) return; + + //Otherwise, something changed. + + LoadFile( InitialFile[0] ); + + for( i = 1; i < gargc; i++ ) + { + if( strchr( gargv[i], '=' ) != 0 ) { printf( "AP: %s\n", gargv[i] ); SetParametersFromString( gargv[i] ); } + else + { + printf( "LF: %s\n", gargv[i] ); + LoadFile( gargv[i] ); + } } } +void ProcessArgs() +{ + int i; + for( i = 1; i < gargc; i++ ) + { + if( strchr( gargv[i], '=' ) != 0 ) + { + //A value setting operation + } + else + { + InitialFile[InitialFileCount++] = gargv[i]; + } + } + + SetEnvValues(); +} + int main(int argc, char ** argv) { -// const char * OutDriver = "name=LEDOutDriver;leds=512;light_siding=1.9"; - const char * InitialFile = 0; - const char * InitialFileDefault = "default.conf"; int i; - double LastFileTimeInit = 0; - double LastFileTimeDefault = 0; #ifdef WIN32 WSADATA wsaData; @@ -181,23 +247,9 @@ int main(int argc, char ** argv) gargc = argc; gargv = argv; - if( argc > 1 ) - { - InitialFile = argv[1]; - } - - - { - LastFileTimeDefault = OGGetFileTime( InitialFileDefault ); - LoadFile( InitialFileDefault ); - } - - if( InitialFile ) - { - LastFileTimeInit = OGGetFileTime( InitialFile ); - LoadFile( InitialFile ); - } + InitialFile[0] = "default.conf"; + ProcessArgs(); //Initialize Rawdraw int frames = 0; @@ -222,7 +274,8 @@ int main(int argc, char ** argv) tp++; } *tp = 0; - CNFGSetup( title, set_screenx, set_screeny ); + if( !headless ) + CNFGSetup( title, set_screenx, set_screeny ); char * OutDriverNames = strdup( GetParameterS( "outdrivers", "null" ) ); @@ -254,7 +307,7 @@ int main(int argc, char ** argv) //Initialize Sound - struct SoundDriver * sd = InitSound( sound_source, &SoundCB ); + sd = InitSound( sound_source, &SoundCB ); if( !sd ) { @@ -269,10 +322,14 @@ int main(int argc, char ** argv) { char stt[1024]; //Handle Rawdraw frame swappign - CNFGHandleInput(); - CNFGClearFrame(); - CNFGColor( 0xFFFFFF ); - CNFGGetDimensions( &screenx, &screeny ); + + if( !headless ) + { + CNFGHandleInput(); + CNFGClearFrame(); + CNFGColor( 0xFFFFFF ); + CNFGGetDimensions( &screenx, &screeny ); + } RunNoteFinder( nf, sound, (soundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE, SOUNDCBSIZE ); //Done all ColorChord work. @@ -284,123 +341,128 @@ int main(int argc, char ** argv) VisTimeEnd = OGGetAbsoluteTime(); - //Handle outputs. - int freqbins = nf->freqbins; - int note_peaks = freqbins/2; - int freqs = freqbins * nf->octaves; - //int maxdists = freqbins/2; - - //Do a bunch of debugging. - if( show_debug_basic ) + if( !headless ) { - for( i = 0; i < nf->dists; i++ ) + //Handle outputs. + int freqbins = nf->freqbins; + int note_peaks = freqbins/2; + int freqs = freqbins * nf->octaves; + //int maxdists = freqbins/2; + + //Do a bunch of debugging. + if( show_debug_basic ) { - 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] ); - CNFGDrawText( stt, 2 ); + for( i = 0; i < nf->dists; 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] ); + CNFGDrawText( stt, 2 ); + } + CNFGColor( 0xffffff ); + + //Draw the folded bins + for( i = 0; i < freqbins; i++ ) + { + float x0 = i / (float)freqbins * (float)screenx; + float x1 = (i+1) / (float)freqbins * (float)screenx; + float amp = nf->folded_bins[i] * 250.0; + CNFGDialogColor = CCtoHEX( ((float)(i+0.5) / freqbins), 1.0, 1.0 ); + CNFGDrawBox( x0, 400-amp, x1, 400 ); + } + CNFGDialogColor = 0xf0f000; + + for( i = 0; i < note_peaks; i++ ) + { + //printf( "%f %f /", note_positions[i], note_amplitudes[i] ); + if( nf->note_amplitudes_out[i] < 0 ) continue; + CNFGDialogColor = CCtoHEX( (nf->note_positions[i] / freqbins), 1.0, 1.0 ); + CNFGDrawBox( ((float)i / note_peaks) * screenx, 480 - nf->note_amplitudes_out[i] * 100, ((float)(i+1) / note_peaks) * screenx, 480 ); + CNFGPenX = ((float)(i+.4) / note_peaks) * screenx; + CNFGPenY = screeny - 30; + sprintf( stt, "%d\n%0.0f", nf->enduring_note_id[i], nf->note_amplitudes2[i]*1000.0 ); + CNFGDrawText( stt, 2 ); + + } + + //Let's draw the o-scope. + int thissoundhead = soundhead; + thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; + int lasty = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; + 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; + } } + + //Extra debugging? + if( show_debug ) + { + //Draw the histogram + float lasthistval; + CNFGColor( 0xffffff ); + + 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 ); + if( i >= 0 ) + CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 ); + lasthistval = thishistval; + } + + CNFGColor( 0xffffff ); + + //Draw the bins + for( i = 0; i < freqs; i++ ) + { + float x0 = i / (float)freqs * (float)screenx; + float x1 = (i+1) / (float)freqs * (float)screenx; + float amp = nf->outbins[i] * 250.0; + CNFGDialogColor = CCtoHEX( ((float)i / freqbins), 1.0, 1.0 ); + CNFGDrawBox( x0, 0, x1, amp ); + } + CNFGDialogColor = 0x0f0f0f; + + char stdebug[1024]; + sprintf( stdebug, "DFT:%8.2fms\nFLT:%8.2f\nDEC:%8.2f\nFNL:%8.2f\nDPY:%8.2f", + (nf->DFTTime - nf->StartTime)*1000, + (nf->FilterTime - nf->DFTTime)*1000, + (nf->DecomposeTime - nf->FilterTime)*1000, + (nf->FinalizeTime - nf->DecomposeTime)*1000, + (VisTimeEnd - VisTimeStart)*1000 ); + CNFGPenX = 50; + CNFGPenY = 50; + CNFGDrawText( stdebug, 2 ); + } + + CNFGColor( show_debug?0xffffff:0x000000 ); + CNFGPenX = 0; CNFGPenY = screeny-10; + CNFGDrawText( "Extra Debug (D)", 2 ); + + CNFGColor( show_debug_basic?0xffffff:0x000000 ); + CNFGPenX = 120; CNFGPenY = screeny-10; + CNFGDrawText( "Basic Debug (E)", 2 ); + + CNFGColor( show_debug_basic?0xffffff:0x000000 ); + CNFGPenX = 240; CNFGPenY = screeny-10; + sprintf( stt, "[9] Key: %d [0] (%3.1f) [-]", gKey, nf->base_hz ); + CNFGDrawText( stt, 2 ); + CNFGColor( 0xffffff ); - - //Draw the folded bins - for( i = 0; i < freqbins; i++ ) - { - float x0 = i / (float)freqbins * (float)screenx; - float x1 = (i+1) / (float)freqbins * (float)screenx; - float amp = nf->folded_bins[i] * 250.0; - CNFGDialogColor = CCtoHEX( ((float)(i+0.5) / freqbins), 1.0, 1.0 ); - CNFGDrawBox( x0, 400-amp, x1, 400 ); - } - CNFGDialogColor = 0xf0f000; - - for( i = 0; i < note_peaks; i++ ) - { - //printf( "%f %f /", note_positions[i], note_amplitudes[i] ); - if( nf->note_amplitudes_out[i] < 0 ) continue; - CNFGDialogColor = CCtoHEX( (nf->note_positions[i] / freqbins), 1.0, 1.0 ); - CNFGDrawBox( ((float)i / note_peaks) * screenx, 480 - nf->note_amplitudes_out[i] * 100, ((float)(i+1) / note_peaks) * screenx, 480 ); - CNFGPenX = ((float)(i+.4) / note_peaks) * screenx; - CNFGPenY = screeny - 30; - sprintf( stt, "%d\n%0.0f", nf->enduring_note_id[i], nf->note_amplitudes2[i]*1000.0 ); - CNFGDrawText( stt, 2 ); - - } - - //Let's draw the o-scope. - int thissoundhead = soundhead; - thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; - int lasty = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; - int thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; - for( i = 0; i < screenx; i++ ) - { - CNFGTackSegment( i, lasty, i+1, thisy ); - lasty = thisy; - thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; - } + CNFGPenX = 440; CNFGPenY = screeny-10; + sprintf( stt, "FPS: %d", lastfps ); + CNFGDrawText( stt, 2 ); + CNFGSwapBuffers(); } - //Extra debugging? - if( show_debug ) - { - //Draw the histogram - float lasthistval; - CNFGColor( 0xffffff ); - - 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 ); - if( i >= 0 ) - CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 ); - lasthistval = thishistval; - } - - CNFGColor( 0xffffff ); - - //Draw the bins - for( i = 0; i < freqs; i++ ) - { - float x0 = i / (float)freqs * (float)screenx; - float x1 = (i+1) / (float)freqs * (float)screenx; - float amp = nf->outbins[i] * 250.0; - CNFGDialogColor = CCtoHEX( ((float)i / freqbins), 1.0, 1.0 ); - CNFGDrawBox( x0, 0, x1, amp ); - } - CNFGDialogColor = 0x0f0f0f; - - char stdebug[1024]; - sprintf( stdebug, "DFT:%8.2fms\nFLT:%8.2f\nDEC:%8.2f\nFNL:%8.2f\nDPY:%8.2f", - (nf->DFTTime - nf->StartTime)*1000, - (nf->FilterTime - nf->DFTTime)*1000, - (nf->DecomposeTime - nf->FilterTime)*1000, - (nf->FinalizeTime - nf->DecomposeTime)*1000, - (VisTimeEnd - VisTimeStart)*1000 ); - CNFGPenX = 50; - CNFGPenY = 50; - CNFGDrawText( stdebug, 2 ); - } - - CNFGColor( show_debug?0xffffff:0x000000 ); - CNFGPenX = 0; CNFGPenY = screeny-10; - CNFGDrawText( "Extra Debug (D)", 2 ); - - CNFGColor( show_debug_basic?0xffffff:0x000000 ); - CNFGPenX = 120; CNFGPenY = screeny-10; - CNFGDrawText( "Basic Debug (E)", 2 ); - - CNFGColor( show_debug_basic?0xffffff:0x000000 ); - CNFGPenX = 240; CNFGPenY = screeny-10; - sprintf( stt, "[9] Key: %d [0] (%3.1f) [-]", gKey, nf->base_hz ); - CNFGDrawText( stt, 2 ); - - CNFGColor( 0xffffff ); - CNFGPenX = 440; CNFGPenY = screeny-10; - sprintf( stt, "FPS: %d", lastfps ); - CNFGDrawText( stt, 2 ); - //Finish Rawdraw with FPS counter, and a nice delay loop. frames++; - CNFGSwapBuffers(); + ThisTime = OGGetAbsoluteTime(); if( ThisTime > LastFPSTime + 1 ) { @@ -419,18 +481,7 @@ int main(int argc, char ** argv) OGUSleep( (int)( SecToWait * 1000000 ) ); } - if( OGGetFileTime( InitialFileDefault ) != LastFileTimeDefault || - (InitialFile && LastFileTimeInit != OGGetFileTime( InitialFile ) ) ) - { - LastFileTimeDefault = OGGetFileTime( InitialFileDefault ); - LoadFile( InitialFileDefault ); - - if( InitialFile ) - { - LastFileTimeInit = OGGetFileTime( InitialFile ); - LoadFile( InitialFile ); - } - } + SetEnvValues(); } diff --git a/netlight.conf b/netlight.conf index dd2a2e2..13ee3b5 100644 --- a/netlight.conf +++ b/netlight.conf @@ -1,12 +1,12 @@ -outdrivers = DisplayNetwork, OutputLinear +outdrivers = DisplayPie,DisplayNetwork, OutputLinear leds = 296 light_siding = 1.0 #Turn this to ~1.9 for more uniformity, ~1.0 for less. satamp = 1.600 is_loop=0 led_floor = .1 #Turn to .25 for more uniformity, .1 for less. -note_attach_amp_iir = .3000 -note_attach_amp_iir2 = .1500 -note_attach_freq_iir = 0.3000 +#note_attach_amp_iir = .3 #.3000 +#note_attach_amp_iir2 = .15 #.1500 +#note_attach_freq_iir = .3 #0.3000 steady_bright = 0 #dft_iir = 0.0 #dft_q = 20.0000 @@ -17,3 +17,10 @@ firstval = 0 port = 7777 address = 192.168.0.245 +slope=.10 +amplify=.3 + + +lightx = 20 +lighty = 20 + diff --git a/notefinder.c b/notefinder.c index 96d042c..8f7b8f0 100644 --- a/notefinder.c +++ b/notefinder.c @@ -9,6 +9,7 @@ #include "filter.h" #include "decompose.h" #include "sort.h" +#include "DFT32.h" struct NoteFinder * CreateNoteFinder( int spsRec ) { @@ -25,6 +26,8 @@ struct NoteFinder * CreateNoteFinder( int spsRec ) ret->decompose_iterations = 1000; ret->dft_speedup = 300; ret->dft_q = 16; + ret->slope = 0.0; + ret->do_progressive_dft = 0; ret->default_sigma = 1.4; ret->note_jumpability = 2.5; ret->note_combine_distance = 0.5; @@ -52,12 +55,14 @@ struct NoteFinder * CreateNoteFinder( int spsRec ) RegisterValue( "default_sigma", PAFLOAT, &ret->default_sigma, sizeof( ret->default_sigma ) ); RegisterValue( "note_jumpability", PAFLOAT, &ret->note_jumpability, sizeof( ret->note_jumpability ) ); RegisterValue( "note_combine_distance", PAFLOAT, &ret->note_combine_distance, sizeof( ret->note_combine_distance ) ); + RegisterValue( "slope", PAFLOAT, &ret->slope, sizeof( ret->slope ) ); RegisterValue( "note_attach_freq_iir", PAFLOAT, &ret->note_attach_freq_iir, sizeof( ret->note_attach_freq_iir ) ); RegisterValue( "note_attach_amp_iir", PAFLOAT, &ret->note_attach_amp_iir, sizeof( ret->note_attach_amp_iir ) ); RegisterValue( "note_attach_amp_iir2", PAFLOAT, &ret->note_attach_amp_iir2, sizeof( ret->note_attach_amp_iir2 ) ); RegisterValue( "note_minimum_new_distribution_value", PAFLOAT, &ret->note_minimum_new_distribution_value, sizeof( ret->note_minimum_new_distribution_value ) ); RegisterValue( "note_out_chop", PAFLOAT, &ret->note_out_chop, sizeof( ret->note_out_chop ) ); RegisterValue( "dft_iir", PAFLOAT, &ret->dft_iir, sizeof( ret->dft_iir ) ); + RegisterValue( "do_progressive_dft", PAINT, &ret->do_progressive_dft, sizeof( ret->do_progressive_dft ) ); AddCallback( "freqbins", ChangeNFParameters, ret ); AddCallback( "octaves", ChangeNFParameters, ret ); @@ -175,12 +180,31 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head //This DFT function does not wavelet or anything. nf->StartTime = OGGetAbsoluteTime(); - DoDFTQuick( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + switch( nf->do_progressive_dft ) + { + case 0: + DoDFTQuick( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + break; + case 1: + DoDFTProgressive( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + break; + case 2: + DoDFTProgressiveInteger( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + break; + case 3: + DoDFTProgressiveIntegerSkippy( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + break; + case 4: + DoDFTProgressive32( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); + break; + default: + fprintf( stderr, "Error: No DFT Seleced\n" ); + } nf->DFTTime = OGGetAbsoluteTime(); for( i = 0; i < freqs; i++ ) { - nf->outbins[i] = nf->outbins[i] * (nf->dft_iir) + (dftbins[i] * (1.-nf->dft_iir) * nf->amplify); + nf->outbins[i] = (nf->outbins[i] * (nf->dft_iir) + (dftbins[i] * (1.-nf->dft_iir) * nf->amplify * ( 1. + nf->slope * i ))); } diff --git a/notefinder.h b/notefinder.h index f42d4b4..5d56462 100644 --- a/notefinder.h +++ b/notefinder.h @@ -8,6 +8,7 @@ struct NoteFinder { //Setup DFT Bins int ofreqs; + float slope;// = 0 int octaves;// = 5; int freqbins;// = 24; int note_peaks; //Calculated from freqbins (not configurable) @@ -16,6 +17,7 @@ struct NoteFinder int filter_iter;// = 1; int decompose_iterations;// = 1000; float amplify; // =1 (amplify input across the board) + int do_progressive_dft; //= 1 //at 300, there is still some minimal aliasing at higher frequencies. Increase this for less low-end distortion //NOTE: This /should/ get fixed, as we /should/ be decimating the input data intelligently with lower octaves. 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/recordtest.conf b/recordtest.conf index 5105e4e..10a661a 100644 --- a/recordtest.conf +++ b/recordtest.conf @@ -1 +1,7 @@ outdrivers = DisplayArray, OutputVoronoi, RecorderPlugin + +play = 1 +buffer = 512 +player_filename = inchristalone.raw +recorder_filename = recfile.raw +recorder_bypass = 44100 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 ); diff --git a/sound_win.c b/sound_win.c index e0c5afb..ee731ea 100644 --- a/sound_win.c +++ b/sound_win.c @@ -1,5 +1,3 @@ -//XXX THIS DRIVER IS INCOMPLETE XXX - #include #include "parameters.h" #include "sound.h" @@ -12,7 +10,7 @@ #pragma comment(lib,"winmm.lib") #endif -#define BUFFS 3 +#define BUFFS 2 struct SoundDriverWin { @@ -27,9 +25,7 @@ struct SoundDriverWin int buffer; int isEnding; - int Cbuff; int GOBUFF; - int OLDBUFF; int recording; @@ -42,6 +38,7 @@ static struct SoundDriverWin * w; void CloseSoundWin( struct SoundDriverWin * r ) { int i; + if( r ) { waveInStop(r->hMyWave); @@ -65,6 +62,7 @@ int SoundStateWin( struct SoundDriverWin * soundobject ) void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm) { int ctr; + int ob; long cValue; unsigned int maxWave=0; @@ -80,18 +78,20 @@ void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwpar break; case MM_WIM_DATA: - w->OLDBUFF=w->GOBUFF; - w->GOBUFF=w->Cbuff; - w->Cbuff = (w->Cbuff+1)%3; - waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR)); - waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR)); +// printf( "Mic Data.\n"); + ob = (w->GOBUFF+(BUFFS))%BUFFS; +// waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR)); for (ctr=0;ctrbuffer * w->channelsRec;ctr++) { - float cv = (uint16_t)(((uint8_t)w->WavBuff[w->GOBUFF].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[w->GOBUFF].lpData[ctr*2])+32768)-32768; + float cv = (uint16_t)(((uint8_t)w->WavBuff[ob].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[ob].lpData[ctr*2])+32768)-32768; cv /= 32768; +// if( ctr < 3 ) cv = -1; +// buffer[(w->buffer * w->channelsRec)-ctr-1] = cv; buffer[ctr] = cv; } + waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->GOBUFF]),sizeof(WAVEHDR)); + w->GOBUFF = ( w->GOBUFF + 1 ) % BUFFS; int playbacksamples; //Unused w->callback( 0, buffer, w->buffer, &playbacksamples, (struct SoundDriver*)w ); @@ -113,23 +113,34 @@ static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r ) w = r; + + printf( "WFMT: %d %d %d\n", r->channelsRec, r->spsRec, + r->spsRec * r->channelsRec ); + wfmt.wFormatTag = WAVE_FORMAT_PCM; wfmt.nChannels = r->channelsRec; wfmt.nSamplesPerSec = r->spsRec; - wfmt.nBlockAlign = 1; + wfmt.nAvgBytesPerSec = r->spsRec * r->channelsRec; + wfmt.nBlockAlign = r->channelsRec * 2; wfmt.wBitsPerSample = 16; - wfmt.nAvgBytesPerSec = 0; + wfmt.cbSize = 0; long dwdevice; dwdevice = GetParameterI( "wininput", WAVE_MAPPER ); - int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt,(DWORD)(void*)(HANDLEMIC) , 0, CALLBACK_FUNCTION); + printf( "Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %d\n", waveInGetNumDevs(), WAVE_MAPPER, dwdevice ); - printf( "WIO: %d\n", p ); + printf( "waveInOpen: %p, %p\n", &r->hMyWave, &wfmt ); + + int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt,(DWORD)(void*)(&HANDLEMIC) , 0, CALLBACK_FUNCTION); + + printf( "WIO: %d\n", p ); //On real windows, returns 11 for ( i=0;iWavBuff[i]), 0, sizeof(r->WavBuff[i]) ); (r->WavBuff[i]).dwBufferLength = r->buffer*2*r->channelsRec; + (r->WavBuff[i]).dwLoops = 1; (r->WavBuff[i]).lpData=(char*) malloc(r->buffer*r->channelsRec*2); waveInPrepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR)); waveInAddBuffer(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR)); @@ -137,7 +148,7 @@ static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r ) p = waveInStart(r->hMyWave); - printf( "WIS: %d\n", p ); + printf( "WIS: %d\n", p ); //On real windows returns 5. return r; } @@ -154,14 +165,12 @@ void * InitSoundWin( SoundCBType cb ) r->spsRec = GetParameterI( "samplerate", 44100 ); r->channelsRec = GetParameterI( "channels", 2 ); - r->buffer = GetParameterI( "buffer", 1024 ); + r->buffer = GetParameterI( "buffer", 384 ); r->recording = 0; r->isEnding = 0; printf( "Buffer: %d\n", r->buffer ); - r->Cbuff=0; r->GOBUFF=0; - r->OLDBUFF=0; return InitWinSound(r); }