On Fri, Jan 08, 2016 at 03:31:18PM +0100, Markus Glugla wrote:
> Hi,

Hi Markus
 
> I read the spectrogram threads and affiliate a request. I'm using
> sometimes sox spectrogram to get an spectral overview of various
> measurement datas. But i want to plot the spectrogram with other tools
> e.g. gnuplot.
> 
> I would be very grateful if it were possible to output the spectrogram
> data as plotable values in a file or stream. Does anybody have the
> same intention and more experience than me to produce a patch?

I have been planning to implement an amplitude and water-fall output,
that can be sent to Gnuplot. I will need these in the coming months, so
perhaps it will get done.

A crude way of getting the raw numbers could be to use the color values
from the generated png file, e.g. with Imagemagick:

    sox -n -n synth 1 synth 1k:5k spectrogram -r -o - |
    convert png:- txt:-                 |
    
    # translate into Gnuplot compatible input
    awk -v FS='[,:() ]+' 'NR > 2               { print $1, $2, ($3+$4+$5)/3 }'  
|
    awk                  'NR > 2 && $2 != prev { printf "\n" } { prev = $2 } 1' 
\
    > spectrogram.dat

Note the use of the `-r` option to sox, which omits all decorations. See
`sox --help-effect spectrogram` for more.

Now plot the data file with Gnuplot:

    echo 'splot "spectrogram.dat" with pm3d' | gnuplot --persist

If you want to get at the raw spectrogram, you need to patch
spectrogram.c. The attached patch works best with single channel files.
Use the new `-O filename` switch to save the binary data.

The default output is a sequence of floats which are 4 bytes long. This
is also Gnuplots default for binary input. This means you can plot the
output like this:

    echo 'plot "<sox -n -n synth 1 sine 1k:5k spectrogram -O -" \
            binary array=(513,800) flipy rotation=90d with image' |
    gnuplot --persist

Note that if your output from sox is short, the spectrogram dimensions
will be different from 800x513 and Gnuplot will barf.

-- 
best regards
Thor Andreassen
diff --git a/src/spectrogram.c b/src/spectrogram.c
index afb0b0e..0fdbd4a 100644
--- a/src/spectrogram.c
+++ b/src/spectrogram.c
@@ -58,9 +58,10 @@ typedef struct {
   sox_bool   monochrome, light_background, high_colour, slack_overlap, no_axes;
   sox_bool   raw, alt_palette, truncate;
   win_type_t win_type;
-  char const * out_name, * title, * comment;
+  char const * out_name, * title, * comment, * out_name_raw;
   char const *duration_str, *start_time_str;
   sox_bool   using_stdout; /* output image to stdout */
+  sox_bool   using_stdout_raw; /* output raw spectrogram to stdout */
 
   /* Shared work area */
   double     * shared, * * shared_ptr;
@@ -107,10 +108,11 @@ static int getopts(sox_effect_t * effp, int argc, char 
**argv)
   char const * next;
   int c;
   lsx_getopt_t optstate;
-  lsx_getopt_init(argc, argv, "+S:d:x:X:y:Y:z:Z:q:p:W:w:st:c:AarmlhTo:", NULL, 
lsx_getopt_flag_none, 1, &optstate);
+  lsx_getopt_init(argc, argv, "+S:d:x:X:y:Y:z:Z:q:p:W:w:st:c:AarmlhTo:O:", 
NULL, lsx_getopt_flag_none, 1, &optstate);
 
   p->dB_range = 120, p->spectrum_points = 249, p->perm = 1; /* Non-0 defaults 
*/
   p->out_name = "spectrogram.png", p->comment = "Created by SoX";
+  p->out_name_raw = NULL;
 
   while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
     GETOPT_NUMERIC(optstate, 'x', x_size0       , 100, MAX_X_SIZE)
@@ -134,6 +136,7 @@ static int getopts(sox_effect_t * effp, int argc, char 
**argv)
     case 't': p->title            = optstate.arg; break;
     case 'c': p->comment          = optstate.arg; break;
     case 'o': p->out_name         = optstate.arg; break;
+    case 'O': p->out_name_raw     = optstate.arg; break;
     case 'S': next = lsx_parseposition(0., optstate.arg, NULL, (uint64_t)0, 
(uint64_t)0, '=');
       if (next && !*next) {p->start_time_str = lsx_strdup(optstate.arg); 
break;}
       return lsx_usage(effp);
@@ -164,6 +167,14 @@ static int getopts(sox_effect_t * effp, int argc, char 
**argv)
     effp->global_info->global_info->stdout_in_use_by = effp->handler.name;
     p->using_stdout = sox_true;
   }
+  if (p->out_name_raw != NULL && !strcmp(p->out_name_raw, "-")) {
+    if (effp->global_info->global_info->stdout_in_use_by) {
+      lsx_fail("stdout already in use by `%s'", 
effp->global_info->global_info->stdout_in_use_by);
+      return SOX_EOF;
+    }
+    effp->global_info->global_info->stdout_in_use_by = effp->handler.name;
+    p->using_stdout_raw = sox_true;
+  }
   return optstate.ind !=argc || p->win_type == INT_MAX? lsx_usage(effp) : 
SOX_SUCCESS;
 }
 
@@ -530,7 +541,7 @@ static int axis(double to, int max_steps, double * limit, 
char * * prefix)
 static int stop(sox_effect_t * effp) /* only called, by end(), on flow 0 */
 {
   priv_t *    p        = (priv_t *) effp->priv;
-  FILE *      file;
+  FILE *      file, * file_raw;
   uLong       font_len = 96 * font_y;
   int         chans    = effp->in_signal.channels;
   int         c_rows   = p->rows * chans + chans - 1;
@@ -556,6 +567,18 @@ static int stop(sox_effect_t * effp) /* only called, by 
end(), on flow 0 */
       goto error;
     }
   }
+  if(p->out_name_raw != NULL) {
+    if (p->using_stdout_raw) {
+      SET_BINARY_MODE(stdout);
+      file_raw = stdout;
+    } else {
+      file_raw = fopen(p->out_name_raw, "wb");
+      if (!file_raw) {
+        lsx_fail("failed to create `%s': %s", p->out_name_raw, 
strerror(errno));
+        goto error;
+      }
+    }
+  }
   lsx_debug("signal-max=%g", p->max);
   font = lsx_malloc(font_len);
   assert(uncompress(font, &font_len, fixed, sizeof(fixed)-1) == Z_OK);
@@ -642,6 +665,11 @@ static int stop(sox_effect_t * effp) /* only called, by 
end(), on flow 0 */
       print_at(cols - right + 1, base + y + 5, Labels, text);
     }
   }
+
+  /* Write raw spectrogram data */
+  if(p->out_name_raw != NULL)
+    fwrite(p->dBfs, (size_t) p->cols * p->rows, sizeof(*p->dBfs), file_raw);
+
   free(font);
   png_set_rows(png, png_info, png_rows);
   png_write_png(png, png_info, PNG_TRANSFORM_IDENTITY, NULL);
@@ -689,6 +717,7 @@ sox_effect_handler_t const * lsx_spectrogram_effect_fn(void)
     "\t-t text\tTitle text",
     "\t-c text\tComment text",
     "\t-o text\tOutput file name; default `spectrogram.png'",
+    "\t-O text\tOutput file name with raw spectrogram data",
     "\t-d time\tAudio duration to fit to X-axis; e.g. 1:00, 48",
     "\t-S position\tStart the spectrogram at the given input position",
   };
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140
_______________________________________________
SoX-devel mailing list
SoX-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sox-devel

Reply via email to