shithub: sox

Download patch

ref: e52aa5209cbdb53e893772fea0872e5430b1a841
parent: 20c6a1f896c8c364056191bb71bf51e7d0576b13
author: rrt <rrt>
date: Sat Nov 25 17:24:41 EST 2006

Use FFT.c's PowerSpectrum instead of yet another FFT.

--- a/src/stat.c
+++ b/src/stat.c
@@ -1,4 +1,13 @@
 /*
+ * Sound Tools statistics "effect" file.
+ *
+ * Compute various statistics on file and print them.
+ *
+ * Output is unmodified from input.
+ *
+ */
+
+/*
  * July 5, 1991
  * Copyright 1991 Lance Norskog And Sundry Contributors
  * This source code is freely redistributable and may be used for
@@ -7,18 +16,10 @@
  * the consequences of using this software.
  */
 
-/*
- * Sound Tools statistics "effect" file.
- *
- * Build various statistics on file and print them.
- *
- * Output is unmodified from input.
- *
- */
-
 #include <math.h>
 #include <string.h>
 #include "st_i.h"
+#include "FFT.h"
 
 /* Private data for STAT effect */
 typedef struct statstuff {
@@ -34,9 +35,8 @@
         int     srms;
         int     fft;
         unsigned long   bin[4];
-        double  *re;
-        double  *im;
-        unsigned long   fft_bits;
+        float  *re_in;
+        float  *re_out;
         unsigned long   fft_size;
         unsigned long   fft_offset;
 } *stat_t;
@@ -57,9 +57,7 @@
         while (n>0)
         {
                 if (!(strcmp(argv[0], "-v")))
-                {
                         stat->volume = 1;
-                }
                 else if (!(strcmp(argv[0], "-s")))
                 {
                         double scale;
@@ -76,20 +74,15 @@
                         }
                         stat->scale = scale;
 
-                        /* Two option argument.  Account for this */
+                        /* Two argument option.  Account for this */
                         --n; ++argv;
                 }
                 else if (!(strcmp(argv[0], "-rms")))
-                {
                         stat->srms = 1;
-                }
                 else if (!(strcmp(argv[0], "-freq")))
-                {
                         stat->fft = 1;
-                }
-                else if (!(strcmp(argv[0], "-d"))) {
+                else if (!(strcmp(argv[0], "-d")))
                         stat->volume = 2;
-                }
                 else
                 {
                         st_fail("Summary effect: unknown option");
@@ -107,7 +100,6 @@
 {
         stat_t stat = (stat_t) effp->priv;
         int i;
-        unsigned long  bitmask;
 
         stat->min = stat->max = stat->mid = 0;
         stat->asum = 0;
@@ -123,30 +115,16 @@
                 stat->bin[i] = 0;
 
         stat->fft_size = 4096;
-        stat->re = 0;
-        stat->im = 0;
+        stat->re_in = stat->re_out = NULL;
 
         if (stat->fft)
         {
-            bitmask = 0x80000000L;
-            stat->fft_bits = 31;
             stat->fft_offset = 0;
-            while (bitmask && !(stat->fft_size & bitmask))
-            {
-                bitmask = bitmask >> 1;
-                stat->fft_bits--;
-            }
 
-            if (bitmask && (stat->fft_size & ~bitmask))
-            {
-                st_fail("FFT can only use sample buffers of 2^n. Buffer size used is %ld",stat->fft_size);
-                return(ST_EOF);
-            }
+            stat->re_in = (float *)malloc(sizeof(float) * stat->fft_size);
+            stat->re_out = (float *)malloc(sizeof(float) * (stat->fft_size / 2));
 
-            stat->re = (double *)malloc(sizeof(double) * stat->fft_size);
-            stat->im = (double *)malloc(sizeof(double) * stat->fft_size);
-
-            if (!stat->re || !stat->im)
+            if (!stat->re_in || !stat->re_out)
             {
                 st_fail("Unable to allocate memory for FFT buffers.");
                 return (ST_EOF);
@@ -157,25 +135,33 @@
 }
 
 /*
+ * Print power spectrum to given stream
+ */
+static void print_power_spectrum(unsigned samples, float rate, float *re_in, float *re_out)
+{
+  float ffa = rate / samples;
+  unsigned i;
+  
+  PowerSpectrum(samples, re_in, re_out);
+  for (i = 0; i < samples / 2; i++)
+    fprintf(stderr, "%f  %f\n", ffa * i, re_out[i]);
+}
+
+/*
  * Processed signed long samples from ibuf to obuf.
  * Return number of samples processed.
  */
 
-static int FFT(short dir,long m,double *x,double *y);
-
 int st_stat_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf,
                  st_size_t *isamp, st_size_t *osamp)
 {
         stat_t stat = (stat_t) effp->priv;
         int len, done, x;
-        unsigned int x1;
-        short count;
-        float magnitude;
-        float ffa;
+        short count = 0;
 
-        count = 0;
         len = ((*isamp > *osamp) ? *osamp : *isamp);
-        if (len==0) return (ST_SUCCESS);
+        if (len==0)
+          return (ST_SUCCESS);
 
         if (stat->read == 0)    /* 1st sample */
                 stat->min = stat->max = stat->mid = stat->last = (*ibuf)/stat->scale;
@@ -184,34 +170,17 @@
         {
             for (x = 0; x < len; x++)
             {
-                stat->re[stat->fft_offset] = ibuf[x];
-                stat->im[stat->fft_offset++] = 0;
+                stat->re_in[stat->fft_offset++] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[x]);
 
                 if (stat->fft_offset >= stat->fft_size)
                 {
                     stat->fft_offset = 0;
-                    FFT(1,stat->fft_bits,stat->re,stat->im);
-                    ffa = (float)effp->ininfo.rate/stat->fft_size;
-                    for (x1 = 0; x1 < stat->fft_size/2; x1++)
-                    {
-                        if (x1 == 0 || x1 == 1)
-                        {
-                            magnitude = 0.0; /* no DC */
-                        }
-                        else
-                        {
-                            magnitude = sqrt(stat->re[x1]*stat->re[x1] + stat->im[x1]*stat->im[x1]);
-                            if (x1 == (stat->fft_size/2) - 1)
-                                magnitude *= 2.0;
-                        }
-                        fprintf(stderr,"%f  %f\n",ffa*x1, magnitude);
-                    }
+                    print_power_spectrum(stat->fft_size, effp->ininfo.rate, stat->re_in, stat->re_out);
                 }
 
             }
         }
 
-
         for(done = 0; done < len; done++) {
                 long lsamp;
                 double samp, delta;
@@ -221,7 +190,6 @@
                 stat->bin[(lsamp>>30)+2]++;
                 *obuf++ = lsamp;
 
-
                 if (stat->volume == 2)
                 {
                     fprintf(stderr,"%08lx ",lsamp);
@@ -266,42 +234,18 @@
 int st_stat_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp)
 {
     stat_t stat = (stat_t) effp->priv;
-    unsigned int x;
-    float magnitude;
-    float ffa;
 
     /* When we run out of samples, then we need to pad buffer with
-     * zeros and then run FFT one last time.  Only perform this
-     * operation if there are at least 1 sample in the buffer.
+     * zeros and then run FFT one last time to process any unprocessed
+     * samples.
      */
+    if (stat->fft && stat->fft_offset) {
+      unsigned int x;
 
-    if (stat->fft && stat->fft_offset)
-    {
-        /* When we run out of samples, then we need to pad buffer with
-         * zeros and then run FFT one last time.  Only perform this
-         * operation if there are at least 1 sample in the buffer.
-         */
-        for (x = stat->fft_offset; x < stat->fft_size; x++)
-        {
-            stat->re[x] = 0;
-            stat->im[x] = 0;
-        }
-        FFT(1,stat->fft_bits,stat->re,stat->im);
-        ffa = (float)effp->ininfo.rate/stat->fft_size;
-        for (x=0; x < stat->fft_size/2; x++)
-        {
-            if (x == 0 || x == 1)
-            {
-                magnitude = 0.0; /* no DC */
-            }
-            else
-            {
-                magnitude = sqrt(stat->re[x]*stat->re[x] + stat->im[x]*stat->im[x]);
-                if (x != (stat->fft_size/2) - 1)
-                    magnitude *= 2.0;
-            }
-            fprintf(stderr, "%f  %f\n",ffa*x, magnitude);
-        }
+      for (x = stat->fft_offset; x < stat->fft_size; x++)
+        stat->re_in[x] = 0;
+      
+      print_power_spectrum(stat->fft_size, effp->ininfo.rate, stat->re_in, stat->re_out);
     }
 
     *osamp = 0;
@@ -348,9 +292,8 @@
                 fprintf(stderr, "%.3f\n", ST_SAMPLE_MAX/(amp*scale));
                 return (ST_SUCCESS);
         }
-        if (stat->volume == 2) {
+        if (stat->volume == 2)
                 fprintf(stderr, "\n\n");
-        }
         /* print out the info */
         fprintf(stderr, "Samples read:      %12u\n", stat->read);
         fprintf(stderr, "Length (seconds):  %12.6f\n", (double)stat->read/effp->ininfo.rate/effp->ininfo.channels);
@@ -372,7 +315,8 @@
         freq = sqrt(stat->dsum2/stat->sum2)*effp->ininfo.rate/(M_PI*2);
         fprintf(stderr, "Rough   frequency: %12d\n", (int)freq);
 
-        if (amp>0) fprintf(stderr, "Volume adjustment: %12.3f\n", ST_SAMPLE_MAX/(amp*scale));
+        if (amp>0)
+        	fprintf(stderr, "Volume adjustment: %12.3f\n", ST_SAMPLE_MAX/(amp*scale));
 
         if (stat->bin[2] == 0 && stat->bin[3] == 0)
                 fprintf(stderr, "\nProbably text, not sound\n");
@@ -383,128 +327,35 @@
                 if (x >= 3.0)                  /* use opposite encoding */
                 {
                         if (effp->ininfo.encoding == ST_ENCODING_UNSIGNED)
-                        {
                                 fprintf (stderr,"\nTry: -t raw -b -s \n");
-                        }
                         else
-                        {
                                 fprintf (stderr,"\nTry: -t raw -b -u \n");
-                        }
 
                 }
                 else if (x <= 1.0/3.0)
-                {
-                    ;;              /* correctly decoded */
-                }
+                  ;             /* correctly decoded */
                 else if (x >= 0.5 && x <= 2.0)       /* use ULAW */
                 {
                         if (effp->ininfo.encoding == ST_ENCODING_ULAW)
-                        {
                                 fprintf (stderr,"\nTry: -t raw -b -u \n");
-                        }
                         else
-                        {
                                 fprintf (stderr,"\nTry: -t raw -b -U \n");
-                        }
                 }
                 else
-                {
                         fprintf (stderr, "\nCan't guess the type\n");
-                }
         }
 
-        /* Release FFT memory if allocated */
-        if (stat->re)
-            free((void *)stat->re);
-        if (stat->im)
-            free((void *)stat->im);
+        /* Release FFT memory */
+        free(stat->re_in);
+        free(stat->re_out);
 
         return (ST_SUCCESS);
 
 }
 
-
-/*
-   This computes an in-place complex-to-complex FFT
-   x and y are the real and imaginary arrays of 2^(m-1) points.
-   dir =  1 gives forward transform
-   dir = -1 gives reverse transform
-*/
-static int FFT(short dir,long m,double *re,double *im)
-{
-   long n,i,i1,j,k,i2,l,l1,l2;
-   double c1,c2,tre,tim,t1,t2,u1,u2,z;
-
-   /* Calculate the number of points */
-   n = 1;
-   for (i=0;i<m;i++)
-      n *= 2;
-
-   /* Do the bit reversal */
-   i2 = n >> 1;
-
-   j = 0;
-
-   for (i=0;i<n-1;i++) {
-      if (i < j) {
-         tre = re[i];
-         tim = im[i];
-         re[i] = re[j];
-         im[i] = im[j];
-         re[j] = tre;
-         im[j] = tim;
-      }
-      k = i2;
-      while (k <= j) {
-         j -= k;
-         k >>= 1;
-      }
-      j += k;
-   }
-
-   /* Compute the FFT */
-   c1 = -1.0;
-   c2 = 0.0;
-   l2 = 1;
-   for (l=0;l<m;l++) {
-      l1 = l2;
-      l2 <<= 1;
-      u1 = 1.0;
-      u2 = 0.0;
-      for (j=0;j<l1;j++) {
-         for (i=j;i<n;i+=l2) {
-            i1 = i + l1;
-            t1 = u1 * re[i1] - u2 * im[i1];
-            t2 = u1 * im[i1] + u2 * re[i1];
-            re[i1] = re[i] - t1;
-            im[i1] = im[i] - t2;
-            re[i] += t1;
-            im[i] += t2;
-         }
-         z =  u1 * c1 - u2 * c2;
-         u2 = u1 * c2 + u2 * c1;
-         u1 = z;
-      }
-      c2 = sqrt((1.0 - c1) / 2.0);
-      if (dir == 1)
-         c2 = -c2;
-      c1 = sqrt((1.0 + c1) / 2.0);
-   }
-
-   /* Scaling for forward transform */
-   if (dir == 1) {
-      for (i=0;i<n;i++) {
-         re[i] /= n;
-         im[i] /= n;
-      }
-   }
-
-   return ST_SUCCESS;
-}
-
 static st_effect_t st_stat_effect = {
   "stat",
-  "Usage: [ -s n ] [ -rms ] [ -v ] [ -d ]",
+  "Usage: [ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]",
   ST_EFF_MCHAN | ST_EFF_REPORT,
   st_stat_getopts,
   st_stat_start,