Voice Speech Recognition on Arduino Due - HowTo ...

I wanted to start this Topic :

  • by asking are there any good Voice / Speech Recognition code for the Arduino Due ?
  • I tried FFT, but the results seem to sloppy, and slow to use.

For example, a simple Square Wave - returns a list of dwindling frequencies.
This seems too complicated for Speech Phonemes Recognition for me.

  • There are some (not perfect) Speech / Sound Input Programs for the Arduino,
    but it is usually too slow for the input via ADC.

  • There is the uSpeech - which works both on the Arduino and the Due.
    https://github.com/arjo129/uSpeech/wiki

It works with some success.
I looked the code over, it seems only to scan for Phonenes via Amplitude

  • that surprised me !
  • Does anyboy have or know of any good Code to do this - for the Arduino Due ?

I have a simple Sketch for the Arduino Due.

I wired up the GY-Max4465 up to A0.

It uses Frequency measurements between Inflections - PosNeg and NegPos,
and thus returns Multiple Frequncies.
It seems pretty reliable so far, for recognizing obvious Phonemes.

I would like to present it here, for any ideas to improve it.

First half of the Sketch :

/// Adc_1Msps_Graph_FAdj_FmHz_LA_ADue.ino ///
/// - from AdcScope_ADue.ino ///

// 1MSamp/Sec 

/*
 *  +++  Try Printing out to LED Matrix - by Freqs  +++  *
 */


/*
   5000-6000  5000                                 Whistle
   5000-7000  3300,5000,6000,7500,10000            S
    500-7500   500,1000,1800,3700,5000,6000,7500   F
   3700-10000 3500,6000,7500,1000                  Z
   2000-10000 2000,3300,4300,5000,6000,7500,10000  J
   2000-5000   800,1000,1400,1800,2200             )a
   2000-4000  1100,1300,2500,3700,5000             /E
   1500-3000  1000,2000,5000,7500                  )e
   1000-2500  1000,1300,2500                       )o
   1700-3700  1800,2000,2500,3700                  R
    800-2000  1000,2300,3700,4300                  /O
    500-2500  500,900,2300,3700                    /U
 */


/// DIV to reduce Freq : ///
///  - this adjusts sampling frquency.
///    this can be adjusted faster (up to 1Msps) but also reduces the Period Size in Time.
//#define  F_DIV  1     // 1MHz
//#define  F_DIV  10    // 100KHz
#define  F_DIV  33   // 33KHz 
//#define  F_DIV  50   // 20KHz 
//#define  F_DIV  100   // 10KHz 

unsigned long start_time;
unsigned long stop_time;

/// Sample Size : ///
///  - this specifies the Size of the Period (more RAM used) but also slow printing back to Serial.  
#define  A_MAX  1000
//#define  A_MAX  2000
//#define  A_MAX  4000
//#define  A_MAX  10000
////#define  A_MAX  20000
unsigned int values[A_MAX];

//char  Md = 'a';
char  Md = 'f';

/// Display of Freq Distribution Bars :
#define A_L_MAX       100
int     A_L[A_L_MAX];
#define A_L_MIN       1
#define A_L_MAX       19

String  SPC_ = "                  ";
char    s[20];

/// Limits to Clip out NOISE : ///
//#define  VAL_MIN  3000
#define  VAL_MIN  2900
//#define  VAL_MAX  3150
#define  VAL_MAX  3200

//

void setup() 
{
  Serial.begin(9600);  
  ADC->ADC_MR   |= 0x80;  //set free running mode on ADC
  ADC->ADC_CHER  = 0x80; //enable ADC on pin A0
}

//

void loop() 
{
  char         ch ;
  unsigned int i , j ;
  long         n;
  char         p = 0;
  int          c = 0, cl = 0 ;  // - count and last count 
  int          f1=0,  f2=0,  f3=0,  f4=0,  f6=0,  f8=0  ;    // - Frequencies of each Amplitudes
  int          f1i=0, f2i=0, f3i=0, f4i=0, f6i=0, f8i=0 ;    // - Freq If First Init Flag yet 
  int          f1c=0, f2c=0, f3c=0, f4c=0, f6c=0, f8c=0 ;    // - Frequency Counters (counts of Freq Cycle) 
  int          f1t=0, f2t=0, f3t=0, f4t=0, f6t=0, f8t=0 ;    // - Time of current Freq 
  int          f_t = 0;      // - Freq Total Time 
  float        f_tp = 0.0;    // - Freq current position within Full Freq Cycle 
  int          v;
  
  /// get Samples group of ADC : ///
  start_time = micros();
  for(i=0; i<A_MAX; i++)
  {
    
    /// get Average (of ADC at 1MHz) Counted/Div down to Sampled Freq : ///
    n = 0;
    for(j=0; j<F_DIV; j++)
    {
    
      while( (ADC->ADC_ISR & 0x80) == 0 ) ;    // wait for conversion
//      values[i] = ADC->ADC_CDR[7] ; //get values
      n += ADC->ADC_CDR[7] ; //get values

    }

    /// Samples group Counted/Div down to desired samples Freq : ///
    values[i] = ( n / F_DIV );
  }
  stop_time = micros();

//

  /// Serial Menu: [ A/0:all, V:values, F:freqsgraph, G:bargraph ] : ///
  if( Serial.available() > 0 )
  {
    ch = Serial.read();

    if(ch == 'f')
      Md = 'f';
      
    if(ch == 'g')
      Md = 'g';
      
    if(ch == 'v')
      Md = 'v';
      
    if(ch == 'a'  ||  ch == '0')
      Md = 'a';
      
  }

//

  Serial.println("\n======================================================\n");

  Serial.print("Total time us: ");
  Serial.println(stop_time-start_time); 
  Serial.print("Average time per conversion: ");
  Serial.println((float)(stop_time-start_time)/1000);

  Serial.println("Values: \n");

  FClr() ;   // - Clr L_A[] 
  for(i=0; i<A_MAX; i++) 
  {
//    Serial.println(values[i]);

   /// ignore first 200 bytes - because of Noise : ///
   if( i > 200 )
   {

    cl = c ;
    c ++ ;

    if(i > 0  &&  p != '-'  &&  values[i-1] > values[i])
    {
      p = '-' ;
///  Only need POS->NEG Inflection - for Full Freq : ///
//      if( values[i] < 2950  ||  values[i] > 3150 )
      if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
        c = 0;    /// - reset c if Inflection
      if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }
    
    else
    if(i > 0  &&  p != '+'  &&  values[i-1] > values[i])
    {
      p = '+' ;
///  Ignore POS->NEG Inflection - only need NEG->POS : ///
////      if( values[i] < 3000  ||  values[i] > 3150 )
//      if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
//        c = 0;
      if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }
    
    else
//    if( values[i] > 2950  &&  values[i] < 3150 )
    if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
    {
      if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }
    
    if(Md == 'a'  ||  Md == 'v')
    {
      Serial.print(p);
      Serial.print(values[i]);
      Serial.print(" ");
    }
    
//

    /// Inc Freq Counters - for calculating Freq between Inflections : ///
    f2c ++ ;
    f3c ++ ;
    f4c ++ ;
    f6c ++ ;
    f8c ++ ;

    f_t  = (i);  // - (i) out of A_MAX 
    f_tp = (i / A_MAX);  /// - percent of segment of freq cycle 
    
    if( c >= 2  &&  cl  < 2 )
    {
      f2 = ((f2 + (f2c * 10)) / 2) ;
      f2c = 0 ;

      {
       if(f2i)
       {
//        FAdd( f2 , f2t , f_t , A_MAX );
        FAdd( ( (1000000 / F_DIV) / (f2 / 10) ) , f2t , f_t , A_MAX );
        f2t = f_t ;
       }
       f2i = 1;
      }
      
      if(Md == 'f')
      {
        Serial.print("\t");
        Serial.print("f2= ");
        Serial.print(f2);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f2 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }
    
    if( c >= 3  &&  cl  < 3 )
    {
      f3 = ((f3 + (f3c * 10)) / 2) ;
      f3c = 0 ;

      if( f3 != f2 )
      {
       if(f3i)
       {
        FAdd( f3 , f3t , f_t , A_MAX );
        f3t = f_t ;
       }
       f3i = 1;
      }
      
      if(Md == 'f')
      {
        Serial.print("\t\t");
        Serial.print("f3= ");
        Serial.print(f3);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f3 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }
    
    if( c >= 4  &&  cl  < 4 )
    {
      f4 = ((f4 + (f4c * 10)) / 2) ;
      f4c = 0 ;

      if( f4 != f3  &&  f4 != f2 )
      {
       if(f4i)
       {
        FAdd( f4 , f4t , f_t , A_MAX );
        f2t = f_t ;
       }
       f4i = 1;
      }      

      if(Md == 'f')
      {
        Serial.print("\t\t\t");
        Serial.print("f4= ");
        Serial.print(f4);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f4 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }
    
    if( c >= 6  &&  cl  < 6 )
    {
      f6 = ((f6 + (f6c * 10)) / 2) ;
      f6c = 0 ;
      
      if( f6 != f4  &&  f6 != f3  &&  f6 != f2)
      {
       if(f6i)
       {
        FAdd( f6 , f6t , f_t , A_MAX );
        f6t = f_t ;
       }
       f6i = 1;
      }      

      if(Md == 'f')
      {
        Serial.print("\t\t\t\t");
        Serial.print("f6= ");
        Serial.print(f6);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f6 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }
    
    if( c >= 8  &&  cl  < 8 )
    {
      f8 = ((f8 + (f8c * 10)) / 2) ;
      f8c = 0 ;
      
      if( f8 != f6  &&  f6 != f4  &&  f6 != f3  &&  f6 != f2)
      {
       if(f8i)
       {
        FAdd( f8 , f8t , f_t , A_MAX );
        f8t = f_t ;
       }
       f8i = 1;
      }      

      if(Md == 'f')
      {
        Serial.print("\t\t\t\t\t");
        Serial.print("f8= ");
        Serial.print(f8);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f8 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

   }  // - end if(i).

  }  // - end for(i=..).
  Serial.println("");

//

 if(Md == 'g'  ||  Md == 'f'  ||  Md == 'a')
 {
  
  Serial.println("\n ");
  for(i=A_L_MIN; i<=A_L_MAX; i++)
  {
    v = ( 1000 * A_L[ i ] / A_MAX );
    Serial.print( v );
    Serial.print( " " );
  }
  Serial.println("\n");

 }

 ;

 if(Md == 'g'  ||  Md == 'f'  ||  Md == 'a')
 {
  
  for(j=1; j<=10; j++)
//  for(j=1; j<=20; j++)
  {
//    Serial.println("\n ");
  
    for(i=A_L_MIN; i<=A_L_MAX; i++)
    {
      v = ( 1000 * A_L[ i ] / A_MAX );
      sprintf(s,"%d",v);

      if( (v / 50) >= j )
//      if( (v / 100) >= j )
        Serial.print( "*" );
      else
        Serial.print( " " );
      
//      Serial.print( v );
      Serial.print( SPC_.substring(0,strlen(s)) );
//      Serial.print( " " );
    }
  
    Serial.println("\n");
  }

 }
  
//

  delay(2000);
}

//

And, second half of the Sketch :

//

void  FClr()
{
int  i;
  
  for(i=0; i<A_L_MAX; i++)
  {
    A_L[i] = 0;
  }
}

///  Fadd( f2 , f2t , f_t , A_MAX );
void  FAdd( int f , int t1 , int t2 , int tmax )
{
//int tt = ((t2 - t1) / tmax);
int tt = ((t2 - t1) / 1);
  
  if( f <=  500 )
  {
    A_L[1] += tt ;
  }
  else
  if( f <=  700 )
  {
    A_L[2] += tt ;
  }
  else
  if( f <=  900 )
  {
    A_L[3] += tt ;
  }
  else
  
  if( f <= 1333 )
  {
    A_L[4] += tt ;
  }
  else
  if( f <= 1666 )
  {
    A_L[5] += tt ;
  }
  else
  if( f <= 1900 )
  {
    A_L[6] += tt ;
  }
  else
  
  if( f <= 2333 )
  {
    A_L[7] += tt ;
  }
  else
  if( f <= 2666 )
  {
    A_L[8] += tt ;
  }
  else
  if( f <= 2900 )
  {
    A_L[9] += tt ;
  }
  else

  if( f <= 3400 )
  {
    A_L[10] += tt ;
  }
  else
  if( f <= 3900 )
  {
    A_L[11] += tt ;
  }
  else

  if( f <= 4500 )
  {
    A_L[12] += tt ;
  }
  else
  if( f <= 4900 )
  {
    A_L[13] += tt ;
  }
  else

  if( f <= 5500 )
  {
    A_L[14] += tt ;
  }
  else
  
  if( f <= 6500 )
  {
    A_L[15] += tt ;
  }
  else

  if( f <= 7900 )
  {
    A_L[16] += tt ;
  }
  else
  if( f <= 9000 )
  {
    A_L[17] += tt ;
  }
  else
  
  if( f <= 11000 )
  {
    A_L[18] += tt ;
  }
  else
//  if( f > 11000 )
  {
    A_L[19] += tt ;
  }

}

Since reliability of ADC conversions seems the starting point of speech recognition process, every improvement might help.

I see two of them:

1/ In some extent, it is possible to get 16-bit ADC conversions from 12-bit ADC conversions. This Application Note from Silicon Labs explains how to:

IMPROVING ADC RESOLUTION BY OVERSAMPLING AND AVERAGING AN118

2/ One good trick with ADC is to have one input dedicated as a purging input. Connect it to ground through a small resistor (say 100 ohms) and sample that channel in between each channel you are interested in. This ensures that the sample and hold capacitor is purged of residual charges between readings. The resistor is important to reduce current flow, but you want it small enough that the capacitor discharges in a reasonable time.

Note 1: If you sample 2 channels instead of 1, you will want to double the ADC conversion frequency to keep the same conversion frequency for a single channel.

Note 2: You can reduce the core load by using a PDC DMA to fill the ADC conversions buffer. This will give you more clock cycles for the main process to improve voice recognition.

Note 3: I guess you know this FFT Library for DUE
https://github.com/dujianyi/ardFFT

Note 4: Your reference voltage should be as stable as possible (< 50 uV)

1 of 3 Code Modified / Fixed.

  • Was measuring Count Sizes , instead of the Amplitude Sizes.
/// Adc_1Msps_Graph_FAdj_FmHz_LA_ADue.ino ///
/// - from AdcScope_ADue.ino ///

// 1MSamp/Sec 

/*
 *  +++  Try Printing out to LED Matrix - by Freqs  +++  *
 */


/*
   5000-6000  5000                                 Whistle
   5000-7000  3300,5000,6000,7500,10000            S
    500-7500   500,1000,1800,3700,5000,6000,7500   F
   3700-10000 3500,6000,7500,1000                  Z
   2000-10000 2000,3300,4300,5000,6000,7500,10000  J
   2000-5000   800,1000,1400,1800,2200             )a
   2000-4000  1100,1300,2500,3700,5000             /E
   1500-3000  1000,2000,5000,7500                  )e
   1000-2500  1000,1300,2500                       )o
   1700-3700  1800,2000,2500,3700                  R
    800-2000  1000,2300,3700,4300                  /O
    500-2500  500,900,2300,3700                    /U
 */


/// DIV to reduce Freq : ///
///  - this adjusts sampling frquency.
///    this can be adjusted faster (up to 1Msps) but also reduces the Period Size in Time.
//#define  F_DIV  1     // 1MHz
//#define  F_DIV  10    // 100KHz
#define  F_DIV  33   // 33KHz 
//#define  F_DIV  50   // 20KHz 
//#define  F_DIV  100   // 10KHz 

unsigned long start_time;
unsigned long stop_time;

/// Sample Size : ///
///  - this specifies the Size of the Period (more RAM used) but also slow printing back to Serial.  
#define  A_MAX  1000
//#define  A_MAX  2000
//#define  A_MAX  4000
//#define  A_MAX  10000
////#define  A_MAX  20000
unsigned int values[A_MAX];

//char  Md = 'a';
char  Md = 'f';

/// Display of Freq Distribution Bars :
#define A_L_MAX       100
int     A_L[A_L_MAX];
#define A_L_MIN       1
#define A_L_MAX       19

String  SPC_ = "                  ";
char    s[20];

/// Limits to Clip out NOISE : ///
//#define  VAL_MIN  3000
#define  VAL_MIN  2900
//#define  VAL_MAX  3150
#define  VAL_MAX  3200

//

void setup() 
{
  Serial.begin(9600);  
  ADC->ADC_MR   |= 0x80;  //set free running mode on ADC
  ADC->ADC_CHER  = 0x80; //enable ADC on pin A0
}

//

2 of 3 Code Mod :

//

void loop() 
{
char         ch ;
unsigned int i , j ;
long  n;
char  p = 0;
int  c = 0, cl = 0 ;  // - count and last count 
int  f1=0,  f2=0,  f3=0,  f4=0,  f6=0,  f8=0  ;    // - Frequencies of each Amplitudes
int  f1i=0, f2i=0, f3i=0, f4i=0, f6i=0, f8i=0 ;    // - Freq If First Init Flag yet 
int  f1s=0, f2s=0, f3s=0, f4s=0, f6s=0, f8s=0 ;    // - Freq If Cycle Set Flag yet 
int  f1c=0, f2c=0, f3c=0, f4c=0, f6c=0, f8c=0 ;    // - Frequency Counters (counts of Freq Cycle) 
int  f1t=0, f2t=0, f3t=0, f4t=0, f6t=0, f8t=0 ;    // - Time of current Freq 
int  f_t = 0;      // - Freq Total Time 
float  f_tp = 0.0;    // - Freq current position within Full Freq Cycle 
int  v;
#define  v_Inc  100 


  /// get Samples group of ADC -> into values[] array : ///
  start_time = micros();
  for(i=0; i<A_MAX; i++)
  {

    /// get Average (of ADC at 1MHz) Counted/Div down to Sampled Freq : ///
    n = 0;
    for(j=0; j<F_DIV; j++)
    {

      while( (ADC->ADC_ISR & 0x80) == 0 ) ;    // wait for conversion
//      values[i] = ADC->ADC_CDR[7] ; //get values
      n += ADC->ADC_CDR[7] ; //get values

    }

    /// Samples group Counted/Div down to desired samples Freq : ///
    values[i] = ( n / F_DIV );
  }
  stop_time = micros();

//

  /// Serial Menu: [ A/0:all, V:values, F:freqsgraph, G:bargraph ] : ///
  if( Serial.available() > 0 )
  {
    ch = Serial.read();

    if(ch == 'f')
      Md = 'f';
      
    if(ch == 'g')
      Md = 'g';
      
    if(ch == 'v')
      Md = 'v';
      
    if(ch == 'V')
      Md = 'V';
      
    if(ch == 'a'  ||  ch == '0')
      Md = 'a';
      
  }

//

  Serial.println("\n======================================================\n");

  Serial.print("Total time us: ");
  Serial.println(stop_time-start_time); 
  Serial.print("Average time per conversion: ");
  Serial.println((float)(stop_time-start_time)/1000);

  Serial.println("Values: \n");

  /// Clear L_A[] array : ///
  FClr() ;   // - Clr L_A[] 

  /// Loop through Samples of values[] array - to Calc Freqs : ///
  for(i=0; i<A_MAX; i++) 
  {
//    Serial.println(values[i]);

   /// skip over first 200 bytes - because of Noise : ///
   if( i > 200 )
   {

    cl = c ;    /// - get Last (c) count 
    c ++ ;      /// - Inc (c) counter

    if(i > 0  &&  p != '-'  &&  values[i-1] > values[i])
    {
      p = '-' ;
///  Only need POS->NEG Inflection - for Full Freq : ///
//      if( values[i] < 2950  ||  values[i] > 3150 )
      if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
        c = 0;      /// - reset (c) if Inflection
      if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }

    else
    if(i > 0  &&  p != '+'  &&  values[i-1] > values[i])
    {
      p = '+' ;
///  Ignore POS->NEG Inflection - only need NEG->POS : ///
////      if( values[i] < 3000  ||  values[i] > 3150 )
//      if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
//        c = 0;
        f1s=0;  f2s=0;  f3s=0;  f4s=0;  f6s=0;  f8s=0 ;
        if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }

    else
//    if( values[i] > 2950  &&  values[i] < 3150 )
    if( values[i] < VAL_MIN  ||  values[i] > VAL_MAX )
    {
      if(Md == 'a'  ||  Md == 'v')
        Serial.println("");
    }
    
    if(Md == 'a'  ||  Md == 'v')
    {
      Serial.print(p);
      Serial.print(values[i]);
      Serial.print(" ");
    }
    else
    if(Md == 'V'  &&  ( values[i] < VAL_MIN  ||  values[i] > VAL_MAX ) )
    {
      Serial.print(p);
      Serial.print(values[i]);
      Serial.print(" \n");
    }
    
//

    /// Inc Freq Counters - for calculating Freq between Inflections : ///
    f2c ++ ;
    f3c ++ ;
    f4c ++ ;
    f6c ++ ;
    f8c ++ ;

    f_t  = (i);  // - (i) out of A_MAX 
    f_tp = (i / A_MAX);  /// - percent of segment of freq cycle 

//    int  v_Inc = 100 ;

#define  F_AMP  1
    /// if Amplitude >= 2 : ///
#ifndef  F_AMP  
    if( c >= 2  &&  cl  < 2 )    // - why c , cl ?  // <<< ??? 
#else    
    if(  abs( values[i] )  >  ( ( ( VAL_MIN + VAL_MAX ) / 2 ) + ( 1 * v_Inc ) )  &&  f2s == 0  )  // - should be --- ???
#endif
    {
      f2s = 1;
      f2 = ((f2 + (f2c * 10)) / 2) ;
      f2c = 0 ;

      {
       if(f2i)
       {
//        FAdd( f2 , f2t , f_t , A_MAX );
        FAdd( ( (1000000 / F_DIV) / (f2 / 10) ) , f2t , f_t , A_MAX );
        f2t = f_t ;
       }
       f2i = 1;
      }

      if(Md == 'f')
      {
        Serial.print("\t");
        Serial.print("f2= ");
        Serial.print(f2);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f2 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

    /// if Amplitude >= 3 : ///
#ifndef  F_AMP  
    if( c >= 3  &&  cl  < 3 )    // - why c , cl ?  // <<< ??? 
#else    
    if(  abs( values[i] )  >  ( ( ( VAL_MIN + VAL_MAX ) / 2 ) + ( 2 * v_Inc ) )  &&  f3s == 0  )  // - should be --- ???
#endif
    {
      f3s = 1;
      f3 = ((f3 + (f3c * 10)) / 2) ;
      f3c = 0 ;

      if( f3 != f2 )
      {
       if(f3i)
       {
        FAdd( f3 , f3t , f_t , A_MAX );
        f3t = f_t ;
       }
       f3i = 1;
      }
      
      if(Md == 'f')
      {
        Serial.print("\t\t");
        Serial.print("f3= ");
        Serial.print(f3);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f3 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

    /// if Amplitude >= 4 : ///
#ifndef  F_AMP  
    if( c >= 4  &&  cl  < 4 )    // - why c , cl ?  // <<< ??? 
#else    
    if(  abs( values[i] )  >  ( ( ( VAL_MIN + VAL_MAX ) / 2 ) + ( 3 * v_Inc ) )  &&  f4s == 0  )  // - should be --- ???
#endif
    {
      f4s = 1;
      f4 = ((f4 + (f4c * 10)) / 2) ;
      f4c = 0 ;

      if( f4 != f3  &&  f4 != f2 )
      {
       if(f4i)
       {
        FAdd( f4 , f4t , f_t , A_MAX );
        f2t = f_t ;
       }
       f4i = 1;
      }      

      if(Md == 'f')
      {
        Serial.print("\t\t\t");
        Serial.print("f4= ");
        Serial.print(f4);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f4 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

    /// if Amplitude >= 6 : ///
#ifndef  F_AMP  
    if( c >= 6  &&  cl  < 6 )    // - why c , cl ?  // <<< ??? 
#else    
    if(  abs( values[i] )  >  ( ( ( VAL_MIN + VAL_MAX ) / 2 ) + ( 6 * v_Inc ) )  &&  f6s == 0  )  // - should be --- ???
#endif
    {
      f6s = 1;
      f6 = ((f6 + (f6c * 10)) / 2) ;
      f6c = 0 ;
      
      if( f6 != f4  &&  f6 != f3  &&  f6 != f2)
      {
       if(f6i)
       {
        FAdd( f6 , f6t , f_t , A_MAX );
        f6t = f_t ;
       }
       f6i = 1;
      }

      if(Md == 'f')
      {
        Serial.print("\t\t\t\t");
        Serial.print("f6= ");
        Serial.print(f6);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f6 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

     /// if Amplitude >= 8 : ///
#ifndef  F_AMP  
   if( c >= 8  &&  cl  < 8 )    // - why c , cl ?  // <<< ??? 
#else    
    if(  abs( values[i] )  >  ( ( ( VAL_MIN + VAL_MAX ) / 2 ) + ( 9 * v_Inc ) )  &&  f8s == 0  )  // - should be --- ???
#endif
    {
      f8s = 1;
      f8 = ((f8 + (f8c * 10)) / 2) ;
      f8c = 0 ;

      if( f8 != f6  &&  f6 != f4  &&  f6 != f3  &&  f6 != f2)
      {
       if(f8i)
       {
        FAdd( f8 , f8t , f_t , A_MAX );
        f8t = f_t ;
       }
       f8i = 1;
      }      

      if(Md == 'f')
      {
        Serial.print("\t\t\t\t\t");
        Serial.print("f8= ");
        Serial.print(f8);
        Serial.print(" ");
        Serial.print( (1000000 / F_DIV) / (f8 / 10) );
        Serial.print(" Hz ");
        Serial.println("");
      }
    }

   }  // - end if(i).

  }  // - end for(i=..).
  Serial.println("");

//

 if(Md == 'g'  ||  Md == 'f'  ||  Md == 'a')
 {
  
  Serial.println("\n ");
  for(i=A_L_MIN; i<=A_L_MAX; i++)
  {
    v = ( 1000 * A_L[ i ] / A_MAX );
    Serial.print( v );
    Serial.print( " " );
  }
  Serial.println("\n");

 }

 ;

 if(Md == 'g'  ||  Md == 'f'  ||  Md == 'a')
 {
  
  for(j=1; j<=10; j++)
//  for(j=1; j<=20; j++)
  {
//    Serial.println("\n ");

    for(i=A_L_MIN; i<=A_L_MAX; i++)
    {
      v = ( 1000 * A_L[ i ] / A_MAX );
      sprintf(s,"%d",v);

      if( (v / 50) >= j )
//      if( (v / 100) >= j )
        Serial.print( "*" );
      else
        Serial.print( " " );
      
//      Serial.print( v );
      Serial.print( SPC_.substring(0,strlen(s)) );
//      Serial.print( " " );
    }

    Serial.println("\n");
  }

 }
  
//

  delay(2000);
}

//

3 of 3 Code Mod :

//

void  FClr()
{
int  i;
  
  for(i=0; i<A_L_MAX; i++)
  {
    A_L[i] = 0;
  }
}

///  Fadd( f2 , f2t , f_t , A_MAX );
void  FAdd( int f , int t1 , int t2 , int tmax )
{
//int tt = ((t2 - t1) / tmax);
int tt = ((t2 - t1) / 1);
  
  if( f <=  500 )
  {
    A_L[1] += tt ;
  }
  else
  if( f <=  700 )
  {
    A_L[2] += tt ;
  }
  else
  if( f <=  900 )
  {
    A_L[3] += tt ;
  }
  else
  
  if( f <= 1333 )
  {
    A_L[4] += tt ;
  }
  else
  if( f <= 1666 )
  {
    A_L[5] += tt ;
  }
  else
  if( f <= 1900 )
  {
    A_L[6] += tt ;
  }
  else
  
  if( f <= 2333 )
  {
    A_L[7] += tt ;
  }
  else
  if( f <= 2666 )
  {
    A_L[8] += tt ;
  }
  else
  if( f <= 2900 )
  {
    A_L[9] += tt ;
  }
  else

  if( f <= 3400 )
  {
    A_L[10] += tt ;
  }
  else
  if( f <= 3900 )
  {
    A_L[11] += tt ;
  }
  else

  if( f <= 4500 )
  {
    A_L[12] += tt ;
  }
  else
  if( f <= 4900 )
  {
    A_L[13] += tt ;
  }
  else

  if( f <= 5500 )
  {
    A_L[14] += tt ;
  }
  else
  
  if( f <= 6500 )
  {
    A_L[15] += tt ;
  }
  else

  if( f <= 7900 )
  {
    A_L[16] += tt ;
  }
  else
  if( f <= 9000 )
  {
    A_L[17] += tt ;
  }
  else
  
  if( f <= 11000 )
  {
    A_L[18] += tt ;
  }
  else
//  if( f > 11000 )
  {
    A_L[19] += tt ;
  }

}