diff --git a/Makefile b/Makefile index c6dfdc7..a1dce0a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ 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 WINGCC:=i586-mingw32msvc-gcc -WINGCCFLAGS:= -lwinmm -lgdi32 -lws2_32 -O2 -ffast-math -g +WINGCCFLAGS:= -O2 -ffast-math -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 @@ -16,8 +17,8 @@ colorchord : os_generic.o main.o dft.o decompose.o filter.o color.o sort.o note 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 - $(WINGCC) -o $@ $^ $(WINGCCFLAGS) + $(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS) clean : - rm -rf *.o *~ colorchord + rm -rf *.o *~ colorchord colorchord.exe 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/colorchord.exe b/colorchord.exe index 867fcfc..7e2638d 100755 Binary files a/colorchord.exe and b/colorchord.exe differ diff --git a/dft.c b/dft.c index 1326363..8543846 100644 --- a/dft.c +++ b/dft.c @@ -1,7 +1,10 @@ + #include "dft.h" #include #include - +#include +#include +#include void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q ) { @@ -41,6 +44,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 +71,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 +79,250 @@ 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 * goutbins; +static float * lastbins; +static float * advances; + +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 + + + + +#define PROGIIR .005 + +//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; + 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 < gbins; 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 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/dft.h b/dft.h index 7fedc79..bae53b5 100644 --- a/dft.h +++ b/dft.h @@ -12,5 +12,12 @@ void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, //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. +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 diff --git a/integerprog.conf b/integerprog.conf new file mode 100644 index 0000000..d321461 --- /dev/null +++ b/integerprog.conf @@ -0,0 +1,5 @@ +do_progressive_dft = 1 +samplerate = 8000 +buffer = 128 + + diff --git a/main.c b/main.c index d268ede..be4cd84 100644 --- a/main.c +++ b/main.c @@ -14,8 +14,15 @@ #include "outdrivers.h" #include "parameters.h" +struct SoundDriver * sd; + #ifdef WIN32 #include +void WindowsTerm() +{ + CloseSound( sd ); +} + #endif int lastfps; @@ -244,7 +251,7 @@ int main(int argc, char ** argv) //Initialize Sound - struct SoundDriver * sd = InitSound( sound_source, &SoundCB ); + sd = InitSound( sound_source, &SoundCB ); if( !sd ) { diff --git a/notefinder.c b/notefinder.c index 96d042c..11078c8 100644 --- a/notefinder.c +++ b/notefinder.c @@ -25,6 +25,7 @@ struct NoteFinder * CreateNoteFinder( int spsRec ) ret->decompose_iterations = 1000; ret->dft_speedup = 300; ret->dft_q = 16; + ret->do_progressive_dft = 0; ret->default_sigma = 1.4; ret->note_jumpability = 2.5; ret->note_combine_distance = 0.5; @@ -58,6 +59,7 @@ struct NoteFinder * CreateNoteFinder( int spsRec ) 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,7 +177,20 @@ 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; + default: + fprintf( stderr, "Error: No DFT Seleced\n" ); + } nf->DFTTime = OGGetAbsoluteTime(); for( i = 0; i < freqs; i++ ) diff --git a/notefinder.h b/notefinder.h index f42d4b4..937ebc7 100644 --- a/notefinder.h +++ b/notefinder.h @@ -16,6 +16,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/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); }