Here is what I modified from the original sources to "do" the assignment. I modified the following to get rid of the FFT stuff and have it compile under MSVC (you can compare my version against the original using diff on UNIX systems). Some of the changes are due to me starting with an older version of the source code, and comparing that to the latest version. Complex.h Control.cpp Controls.h control.h Display.cpp Display.h Fft.cpp Fft.h fft.h Recorder.cpp Recorder.h SmartPtrs.cpp smartptrs.h Views.cpp Views.h view.h Wavein.h params.h Freq.dsp fft.rc I included some additional files for another project where I saved WAV files. DDC.H DDCRET.CPP RIFF.CPP RIFF.H The modifications to do the "clapper" are in Views.cpp, and consist of implementing the leaky integrator to tell whether we are hearing sound or silence, and the state machine to generate symbols corresponding to sound or silence. ViewFreq::Update is called whenever there is a new buffer of audio data to process. /**********************************************************************/ /* Typedefs */ typedef struct transition { int type; long time; } TRANSITION; /* Some useful values */ int display_scale = 256; /* Global variables */ int buffer_size = SAMPLES_PER_SECOND; short buffer[SAMPLES_PER_SECOND]; int buffer_index = 0; long the_time = 0; float mean = 0; #define N_TRANSITIONS 10 TRANSITION transitions[N_TRANSITIONS]; /* The state machine */ /* States */ #define SOUND 10 #define IN_BETWEEN 20 #define SILENCE 30 /* Thresholds */ float silence_threshold = 5000; float sound_threshold = 50000; /* The state variable */ int state = IN_BETWEEN; /* Some debugging stuff */ FILE *debug_stream = NULL; /***************************************************************/ /* stash_transition() is called every time there is a transition, and updates the transitions[] array */ void stash_transition() { static int transitions_initialized = FALSE; int i; if ( !transitions_initialized ) { for ( i = 0; i < N_TRANSITIONS; i++ ) { transitions[i].type = IN_BETWEEN; transitions[i].time = -10000; } transitions_initialized = TRUE; } for ( i = N_TRANSITIONS - 2; i >=0; i-- ) { transitions[i+1].type = transitions[i].type; transitions[i+1].time = transitions[i].time; } transitions[0].type = state; transitions[0].time = the_time; } /***************************************************************/ /* recognize_claps() tests whether the values in transitions[] match a clap */ int recognize_claps() { int i; if ( state != SILENCE ) return FALSE; if ( the_time - transitions[0].time != 10 ) return FALSE; /* Here is a debugging printout, so I can figure out how to set all these numbers */ /* if ( debug_stream == NULL ) debug_stream = fopen( "debug.txt", "w" ); if ( debug_stream != NULL ) { fprintf( debug_stream, "%d %ld \n", state, the_time ); i = 0; fprintf( debug_stream, "%d %ld; \n", transitions[i].type, transitions[i].time ); for( i = 1; i < N_TRANSITIONS; i++ ) fprintf( debug_stream, "%d %ld %d; \n", transitions[i].type, transitions[i].time, transitions[i-1].time - transitions[i].time ); fprintf( debug_stream, "\n" ); fflush( debug_stream ); } */ if ( transitions[0].type != SILENCE ) return FALSE; if ( transitions[1].type != IN_BETWEEN ) return FALSE; /* If nonsilence too long bag it. */ if ( transitions[0].time - transitions[1].time > 2000 ) return FALSE; if ( transitions[2].type != SOUND ) return FALSE; /* If loud part too long bag it. */ if ( transitions[1].time - transitions[2].time > 2500 ) return FALSE; if ( transitions[3].type != IN_BETWEEN ) return FALSE; if ( transitions[2].time - transitions[3].time > 100 ) return FALSE; if ( transitions[4].type != SILENCE ) return FALSE; return TRUE; } /***************************************************************/ /* recognition_state_machine() updates the state machine based on the thresholds */ void recognition_state_machine( float value ) { the_time++; switch( state ) { case SILENCE: if ( value > silence_threshold*1.1 ) { state = IN_BETWEEN; stash_transition(); } break; case IN_BETWEEN: if ( value < silence_threshold ) { state = SILENCE; stash_transition(); } if ( value > sound_threshold ) { state = SOUND; stash_transition(); } break; case SOUND: if ( value < sound_threshold*0.9 ) { state = IN_BETWEEN; stash_transition(); } break; } } /***************************************************************/ /* Here is the freq routine I hacked to add my stuff to. */ void ViewFreq::Update (SampleIter& iter) { UpdateCanvas canvas (Hwnd ()); ClientRect rect (Hwnd ()); int min, max; long int sum = 0; int n_points = iter.Count(); int last_buffer_index = buffer_index; int i, index; int ss, min_ss, max_ss; static float leaky_integrator = 0; int got_one = FALSE; /* Copy new data into buffer */ for ( i = 0; i < n_points; i++, iter.Advance() ) { /* Subtract out mean. */ int value = (int) (iter.GetSample() - mean); /* update mean. */ mean = (float) (0.999*mean * 0.001*value); /* Make sure we don't have an overflow. */ if ( value > 32767 ) value = 32767; if ( value < -32768 ) value = -32768; buffer[buffer_index++] = value; if ( buffer_index >= buffer_size ) buffer_index = 0; } /* Now display stuff */ { // Erase background for this vertical line of display BlackPen pen(canvas); canvas.Line (_xRecord, 0, _xRecord, rect.bottom); } // set min and max of values to be middle of display /* What makes this routine a little complicated is that the entire buffer of data is plotted at one X value in the display. Therefore what is plotted is a vertical line, and min and max are the bottom and top of that line. Same for min_ss and max_ss. */ min = max = (rect.bottom - 1)/2; min_ss = rect.bottom; max_ss = 0; index = last_buffer_index; for ( i = 0; i < n_points; i++ ) { int value = buffer[index++]; if ( index >= buffer_size ) index = 0; /* s is the data point in display coordinates */ int s = value / display_scale + (rect.bottom - 1) / 2; if ( s < 0 ) s = 0; else if (s >= rect.bottom) s = rect.bottom - 1; if ( s > max ) max = s; if ( s < min ) min = s; /* Here is the leaky integrator. 0.00001 is a value to make it easy to plot. 0.995 determines how fast it leaks. */ leaky_integrator = (float) (0.00001*value*value + 0.995*leaky_integrator); /* ss is the leaky integrator in display coordinates */ ss = (int) (-leaky_integrator / display_scale) + (rect.bottom - 1); if ( ss < 0 ) ss = 0; else if (ss >= rect.bottom) ss = rect.bottom - 1; if ( ss > max_ss ) max_ss = ss; if ( ss < min_ss ) min_ss = ss; recognition_state_machine( leaky_integrator ); if ( recognize_claps() ) got_one = TRUE; } if ( min == max ) { COLORREF color; color = RGB( 0, 255, 0 ); canvas.Point( _xRecord, min, color ); } else { PenHolder pen (canvas, _penGreen); canvas.Line (_xRecord, min, _xRecord, max); } if ( min_ss == max_ss ) { COLORREF color; color = RGB( 255, 0, 0 ); canvas.Point( _xRecord, min_ss, color ); } else { PenHolder pen (canvas, _penRed); canvas.Line (_xRecord, min_ss, _xRecord, max_ss); } { COLORREF color; switch ( state ) { case SILENCE: color = RGB( 0, 255, 255 ); break; case SOUND: color = RGB( 255, 255, 255 ); break; case IN_BETWEEN: color = RGB( 0, 0, 255 ); break; } canvas.Point( _xRecord, state, color ); } /* If we found a clap mark it */ if ( got_one ) { // Draw white vertical mark WhitePen pen(canvas); canvas.Line (_xRecord, 0, _xRecord, 50 ); got_one = FALSE; } _xRecord += 1; if (_xRecord >= rect.right) _xRecord = 0; /* Erase ahead of us */ { // Draw white vertical mark WhitePen pen(canvas); canvas.Line (_xRecord, 0, _xRecord, rect.bottom); // Erase ahead i = 10; if ( _xRecord+i < rect.right ) { BlackPen pen(canvas); canvas.Line (_xRecord+i, 0, _xRecord+i, rect.bottom); } } } /***************************************************************/