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", };