/*
Reads a stream of pairs of 2-byte signed integers, and outputs
mean, stdev, and peak stats for desired number of sample pairs.

The main use of this is to attach it to /dev/dsp output
for a level meter on mixing.

I intend to pipe the output from this program to a graphical
display someday.
*/

#include <stdio.h>
#include <math.h>
#include <stdio.h>

#define ABS(X)  (((X)<0)?(-(X)):(X))

int main(int argc, char *argv[])
{
  int period,n,asciiGraph,mono,sampRate;
  double dcx,dcy;
  char asciiLine[96],*eoln;

  if (argc < 2)
    {
      printf("\nUsage: stream_of_shorts | %s period [options]\n\n",argv[0]);
      puts("     period    -- Number of samples to collect for each output");
      puts("     -a        -- Output as ASCII graphics, not numbers");
      puts("     -m        -- Mono, not stereo input");
      puts("     -s        -- Sample rate (converts report units to time)");
      puts("     -r        -- Report form, not interractive\n");
      exit(1);
    }

  sscanf(argv[1],"%d",&period);

  sampRate = 0;
  asciiGraph = 0;
  eoln = "\r";
  mono = 0;
  for (n=2;n<argc;n++)
    {
      if (strcmp(argv[n],"-a")==0) asciiGraph=1;
      if (strcmp(argv[n],"-r")==0) eoln="\n";
      if (strcmp(argv[n],"-m")==0) mono=1;
      if (strcmp(argv[n],"-s")==0)
        {
          n++;
          sampRate = atoi(argv[n]);
        }
    }

  if (asciiGraph)
    {
      puts("0                                            32768");
      puts("|                                                |");
      for(n=0;n<50;n++)asciiLine[n]=' ';
      asciiLine[50]='*';
      asciiLine[51]=' ';
      asciiLine[52]=*eoln;
      asciiLine[53]=0;
    }
  else
    {
      if (mono)
	{
	  puts(" StDev  Peak-Mag");
	}
      else
	{
	  puts(" -----StDev---- -Peak-Mag--");
	  puts("   L       R      L     R");
	}
    }

  n = 0;
  dcx=dcy=0.0;
  for(;;)
    {
      double sx,sx2,sy,sy2;
      short mx,my;
      int i;

      sx=sx2=sy=sy2=0.0;
      mx=my=0;
      
      for (i=0;i<period;i++)
	{
	  register short s;
	  double d;
	  short sample[2];

	  if (mono)
	    {
	      if (fread(&sample,2,1,stdin)!=1)
		{
		  fprintf(stderr,"\nDC %9.2lf\n",dcx/n);
		  return 0;
		}
	    }
	  else
	    {
	      if (fread(&sample,2,2,stdin)!=2)
		{
		  fprintf(stderr,"\nDC %9.2lf %9.2lf\n",dcx/n,dcy/n);
		  return 0;
		}
	    }

	  d = s = sample[0];
	  sx += d;
          sx2 += d*d;
	  s = ABS(s);
	  if (s > mx) mx = s;

	  if (!mono)
	    {
	      d = s = sample[1];
	      sy += d;
	      sy2 += d*d;
	      s = ABS(s);
	      if (s > my) my = s;
	    }
	}
      sx /= period;
      sx2 = sqrt(sx2/period-sx*sx);

      if (*eoln == '\n')
        {
          long nSamp = (n+1)*period;
          if (sampRate)
            {
              double t;
              int mm;

              t = nSamp / (double)sampRate;
              mm = (int)(t/60.0);
              t -= mm*60;
              printf("%3d:%04.1lf ",mm,t);
            }
          else
            {
              printf("%9d ",(n+1)*period);
            }
        }

      if (mono)
	{
	  if (asciiGraph)
	    {
	      int j,k;

	      j = sx2 * 50.0 / 32768.0 + 0.5;
	      if (j > 49) j = 49;
	      asciiLine[j]='x';
	      k = mx  * 50.0 / 32768.0 + 0.5;
	      if (k > 49) k = 49;
	      asciiLine[k]='X';

	      fputs(asciiLine,stdout);
	      /* clear out old entries for next time */
	      asciiLine[j] = ' ';
	      asciiLine[k] = ' ';
	    }
	  else printf("%7.1lf %5d%s",sx2,mx,eoln);
	}
      else
	{
	  sy /= period;
	  sy2 = sqrt(sy2/period-sy*sy);

	  if (asciiGraph)
	    {
	      int p[4],j;
	      static char sym[4] = {'l','r','L','R'};

	      p[0] = sx2 * 50.0 / 32768.0 + 0.5;
	      p[1] = sy2 * 50.0 / 32768.0 + 0.5;
	      p[2] = mx  * 50.0 / 32768.0 + 0.5;
	      p[3] = my  * 50.0 / 32768.0 + 0.5;
	      for (j=0;j<4;j++)
		{
		  if (p[j] > 49) p[j] = 49;
		  asciiLine[p[j]]=sym[j];
		}
	      if (p[0] == p[1]) asciiLine[p[0]] = 'x';
	      if (p[2] == p[3]) asciiLine[p[2]] = 'X';

	      fputs(asciiLine,stdout);
	      /* clear out old entries for next time */
	      for (j=0;j<4;j++) asciiLine[p[j]] = ' ';
	    }
	  else
            printf("%7.1lf %7.1lf %5d %5d%s",sx2,sy2,mx,my,eoln);
	  dcy += sy;
	}
      fflush(stdout);
      dcx += sx;
      n++;
    }
}

