History

more colour control

robs committed 18 years ago

Commit 784ea2a1 parent d2b295b2 files · +155 −101Browse files

Showing the changes to src/spectrogram.c (1 of 2 files). Show all

Unified · Split

src/spectrogram.c+99−71
@@ -89,18 +89,16 @@ static enum_item const window_options[] = { · 88 unmodified lines
8989
9090 typedef struct {
9191 int y_size, dft_size, rows, cols, step_size, block_steps, block_num;
92− double buf[MAX_DFT_SIZE];
93− double dft_buf[MAX_DFT_SIZE];
94− double window[MAX_DFT_SIZE];
95− int bit_rev_table[100]; /* For Ooura fft */
96− double sin_cos_table[dft_sc_len(MAX_DFT_SIZE)]; /* ditto */
97− double magnitudes[(MAX_DFT_SIZE >> 1) + 1];
98− float * dBfs;
99− double pixels_per_sec, block_norm, max;
10092 int dB_range, gain, style, read, end, end_min, last_end;
93+ int spectrum_points, perm;
10194 char const * out_name, * title, * comment;
102− sox_bool slack_overlap, no_axes;
95+ sox_bool high_colour, slack_overlap, no_axes, truncated;
10396 win_type_t win_type;
97+ double buf[MAX_DFT_SIZE], dft_buf[MAX_DFT_SIZE], window[MAX_DFT_SIZE];
98+ double pixels_per_sec, block_norm, max, magnitudes[(MAX_DFT_SIZE>>1) + 1];
99+ int bit_rev_table[100]; /* For Ooura fft */
100+ double sin_cos_table[dft_sc_len(MAX_DFT_SIZE)]; /* ditto */
101+ float * dBfs;
104102 } priv_t;
105103
106104 #define GETOPT_NUMERIC(ch, name, min, max) case ch:{ \
@@ -142,13 +140,16 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 35 unmodified lines
142140
143141 --argv, ++argc, optind = 1, opterr = 0; /* re-jig for getopt */
144142 p->pixels_per_sec = 100, p->y_size = 2, p->dB_range = 120;/* non-0 defaults */
143+ p->spectrum_points = 249, p->perm = 1;
145144 p->style = 1, p->out_name = "spectrogram.png", p->comment = "Created by SoX";
146145
147− while ((c = getopt(argc, argv, "+x:y:z:g:w:st:c:amlo:")) != -1) switch (c) {
146+ while ((c = getopt(argc, argv, "+x:y:z:Z:q:p:w:st:c:amlho:")) != -1) switch (c) {
148147 GETOPT_NUMERIC('x', pixels_per_sec, 1 , 5000)
149148 GETOPT_NUMERIC('y', y_size , 1 , 1 + MAX_DFT_SIZE_SHIFT)
150− GETOPT_NUMERIC('z', dB_range , 40 , 180)
151− GETOPT_NUMERIC('g', gain ,-100, 100)
149+ GETOPT_NUMERIC('z', dB_range , 20 , 180)
150+ GETOPT_NUMERIC('Z', gain ,-100, 100)
151+ GETOPT_NUMERIC('q', spectrum_points, 0 , p->spectrum_points)
152+ GETOPT_NUMERIC('p', perm , 1 , 6)
152153 case 'w': p->win_type = enum_option(c, window_options); break;
153154 case 's': p->slack_overlap = sox_true; break;
154155 case 't': p->title = optarg; break;
@@ -156,11 +157,14 @@ static int getopts(sox_effect_t * effp, int argc, char **argv) · 1 unmodified line
156157 case 'a': p->no_axes = sox_true; break;
157158 case 'm': monochrome = sox_true; break;
158159 case 'l': light_background = sox_true; break;
160+ case 'h': p->high_colour = sox_true; break;
159161 case 'o': p->out_name = optarg; break;
160162 default: sox_fail("unknown option `-%c'", optopt); return lsx_usage(effp);
161163 }
162− p->y_size -= 1;
164+ p->gain = - p->gain;
165+ --p->y_size, --p->perm;
163166 p->style = 2 * monochrome + light_background;
167+ p->spectrum_points += 2;
164168 argc -= optind, optind = callers_optind, opterr = callers_opterr;
165169 return argc || p->win_type == INT_MAX? lsx_usage(effp) : SOX_SUCCESS;
166170 }
@@ -219,6 +223,7 @@ static int do_column(sox_effect_t * effp) · 52 unmodified lines
219223
220224 if (p->cols == MAX_COLS) {
221225 sox_warn("PNG truncated at %g seconds", (double)MAX_COLS * p->step_size * p->block_steps / effp->in_signal.rate);
226+ p->truncated = sox_true;
222227 return SOX_EOF;
223228 }
224229 ++p->cols;
@@ -275,7 +280,7 @@ static int drain(sox_effect_t * effp, sox_sample_t * obuf_, sox_size_t * osamp) · 50 unmodified lines
275280 {
276281 priv_t * p = (priv_t *)effp->priv;
277282
278− if (p->cols != MAX_COLS) {
283+ if (!p->truncated) {
279284 sox_sample_t * ibuf = calloc(p->dft_size, sizeof(*ibuf));
280285 sox_sample_t * obuf = calloc(p->dft_size, sizeof(*obuf));
281286 sox_size_t isamp = (p->dft_size - p->step_size) / 2;
@@ -298,52 +303,72 @@ static int drain(sox_effect_t * effp, sox_sample_t * obuf_, sox_size_t * osamp) · 16 unmodified lines
298303 return SOX_SUCCESS;
299304 }
300305
301−#define spectrum_points (1 + 250)
302−enum {Background = spectrum_points, Text, Labels, Grid, palette_size};
306+enum {Background, Text, Labels, Grid, fixed_palette};
303307
304−static unsigned colour(double x, int range)
308+static unsigned colour(priv_t const * p, double x)
305309 {
306− x = range_limit(x, -range, 0);
307− return (1 + x / range) * (spectrum_points - 1) + .5;
310+ unsigned c = x < -p->dB_range? 0 : x >= 0? p->spectrum_points - 1 :
311+ 1 + (1 + x / p->dB_range) * (p->spectrum_points - 2);
312+ return fixed_palette + c;
308313 }
309314
310−static void make_palette(png_byte * palette, int style)
315+static void make_palette(priv_t const * p, png_color * palette)
311316 {
312− int i, j, at;
313− for (i = j = 0; j < spectrum_points; i += 3, ++j) {
314− double r, g, b, x = (double)j / (spectrum_points - 1);
315− if (style > 1)
316− palette[i+2] = palette[i+1] = palette[i+0] = style == 2? j : 255 - j;
317− else {
318− at = style? (spectrum_points - 1) * 3 - i : i;
319− if (x < .16) r = 0;
320− else if (x < .72) r = .99 * sin((x - .16) / .56 * M_PI / 2);
321− else r = .01 * (x - .72) / .28 + .99;
322− if (x < .52) g = 0;
323− else if (x < .86) g = .99 * .5 * (1 - cos((x - .52) / .34 * M_PI));
324− else g = .01 * (x - .86) / .14 + .99;
325− if (x < .34) b = .5 * sin((x - .00) / .34 * M_PI / 2);
326− else if (x < .63) b = .5 * .5 * (1 + cos((x - .34) / .29 * M_PI));
327− else b = (1 - cos((x - .63) / .37 * M_PI / 2));
328− palette[at + 0] = r * 255 + .5;
329− palette[at + 1] = g * 255 + .5;
330− palette[at + 2] = b * 255 + .5;
331− }
317+ int i;
318+
319+ if (p->style & 1) {
320+ memcpy(palette++, (p->style & 2)? "\337\337\337":"\335\330\320", 3);
321+ memcpy(palette++, "\0\0\0" , 3);
322+ memcpy(palette++, "\077\077\077", 3);
323+ memcpy(palette++, "\077\077\077", 3);
324+ } else {
325+ memcpy(palette++, "\0\0\0" , 3);
326+ memcpy(palette++, "\377\377\377", 3);
327+ memcpy(palette++, "\277\277\277", 3);
328+ memcpy(palette++, "\177\177\177", 3);
332329 }
333− i = spectrum_points * 3;
334− switch (style) {
335− case 0: case 2:
336− memcpy(palette + i, "\0\0\0" , 3), i+= 3;
337− memcpy(palette + i, "\377\377\377", 3), i+= 3;
338− memcpy(palette + i, "\277\277\277", 3), i+= 3;
339− memcpy(palette + i, "\177\177\177", 3), i+= 3;
340− return;
341− case 1: memcpy(palette + i, "\335\330\320", 3), i+= 3; break;
342− default: memcpy(palette + i, "\337\337\337", 3), i+= 3;
330+ for (i = 0; i < p->spectrum_points; ++i) {
331+ double c[3] , x = (double)i / (p->spectrum_points - 1);
332+ int at = (p->style & 1)? p->spectrum_points - 1 - i : i;
333+ if (p->style > 1) {
334+ c[2] = c[1] = c[0] = x;
335+ if (p->high_colour) {
336+ c[(1 + p->perm) % 3] = x < .4? 0 : 5 / 3. * (x - .4);
337+ if (p->perm < 3)
338+ c[(2 + p->perm) % 3] = x < .4? 0 : 5 / 3. * (x - .4);
339+ }
340+ palette[at].red = .5 + 255 * c[0];
341+ palette[at].green= .5 + 255 * c[1];
342+ palette[at].blue = .5 + 255 * c[2];
343+ continue;
344+ }
345+ if (p->high_colour) {
346+ static const int states[3][7] = {
347+ {4,5,0,0,2,1,1}, {0,0,2,1,1,3,2}, {4,1,1,3,0,0,2}};
348+ int j, phase_num = min(6, x * 7);
349+ for (j = 0; j < 3; ++j) switch (states[j][phase_num]) {
350+ case 0: c[j] = 0; break;
351+ case 1: c[j] = 1; break;
352+ case 2: c[j] = sin((7 * x - phase_num) * M_PI / 2); break;
353+ case 3: c[j] = cos((7 * x - phase_num) * M_PI / 2); break;
354+ case 4: c[j] = 7 * x - phase_num; break;
355+ case 5: c[j] = 1 - (7 * x - phase_num); break;
356+ }
357+ } else {
358+ if (x < .16) c[0] = 0;
359+ else if (x < .72) c[0] = .99 * sin((x - .16) / .56 * M_PI / 2);
360+ else c[0] = .01 * (x - .72) / .28 + .99;
361+ if (x < .52) c[1] = 0;
362+ else if (x < .86) c[1] = .99 * .5 * (1 - cos((x - .52) / .34 * M_PI));
363+ else c[1] = .01 * (x - .86) / .14 + .99;
364+ if (x < .34) c[2] = .5 * sin((x - .00) / .34 * M_PI / 2);
365+ else if (x < .63) c[2] = .5 * .5 * (1 + cos((x - .34) / .29 * M_PI));
366+ else c[2] = (1 - cos((x - .63) / .37 * M_PI / 2));
367+ }
368+ palette[at].red = .5 + 255 * c[p->perm % 3];
369+ palette[at].green= .5 + 255 * c[(1 + p->perm + (p->perm % 2)) % 3];
370+ palette[at].blue = .5 + 255 * c[(2 + p->perm - (p->perm % 2)) % 3];
343371 }
344− memcpy(palette + i, "\0\0\0" , 3), i+= 3;
345− memcpy(palette + i, "\077\077\077", 3), i+= 3;
346− memcpy(palette + i, "\077\077\077", 3), i+= 3;
347372 }
348373
349374 static const Bytef fixed[] =
@@ -405,7 +430,7 @@ static int axis(double to, int max_steps, double * limit, char * * prefix) · 55 unmodified lines
405430 scale = pow(10., -3. * prefix_num);
406431 }
407432 *prefix = "pnum-kMGTPE" + prefix_num + (prefix_num? 4 : 11);
408− *limit = to * scale + .5;
433+ *limit = to * scale;
409434 return step * scale + .5;
410435 }
411436
@@ -427,7 +452,7 @@ static int stop(sox_effect_t * effp) · 15 unmodified lines
427452 png_bytepp png_rows = malloc(rows * sizeof(*png_rows));
428453 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0,0);
429454 png_infop png_info = png_create_info_struct(png);
430− png_byte palette[palette_size * 3];
455+ png_color palette[256];
431456 int i, j, step, tick_len = 2 + do_frame;
432457 char text[200], * prefix;
433458 double limit;
@@ -443,10 +468,10 @@ static int stop(sox_effect_t * effp) · 9 unmodified lines
443468 sox_debug("signal-max=%g", p->max);
444469 font = malloc(font_len);
445470 assert(uncompress(font, &font_len, fixed, sizeof(fixed)-1) == Z_OK);
446− make_palette(palette, p->style);
471+ make_palette(p, palette);
447472 memset(pixels, Background, cols * rows * sizeof(*pixels));
448473 png_init_io(png, file);
449− png_set_PLTE(png, png_info, (png_colorp)palette, palette_size);
474+ png_set_PLTE(png, png_info, palette, fixed_palette + p->spectrum_points);
450475 png_set_IHDR(png, png_info, (size_t)cols, (size_t)rows, 8,
451476 PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
452477 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
@@ -461,7 +486,7 @@ static int stop(sox_effect_t * effp) · 8 unmodified lines
461486 /* Spectrogram */
462487 for (j = 0; j < p->rows; ++j) {
463488 for (i = 0; i < p->cols; ++i)
464− pixel(left + i, below + j) = colour(p->dBfs[i*p->rows + j], p->dB_range);
489+ pixel(left + i, below + j) = colour(p, p->dBfs[i*p->rows + j]);
465490 if (do_frame) /* Frame verticals */
466491 pixel(left - 1, below + j) = pixel(left + p->cols,below + j) = Grid;
467492 }
@@ -503,7 +528,7 @@ static int stop(sox_effect_t * effp) · 35 unmodified lines
503528 /* Z-axis */
504529 print_at(cols - right - 2 - font_X, below - 13, Text, "dBFS");/* Axis label */
505530 for (j = 0; j < p->rows; ++j) { /* Spectrum */
506− png_byte b = colour(p->dB_range * (j / (p->rows - 1.) - 1), p->dB_range);
531+ png_byte b = colour(p, p->dB_range * (j / (p->rows - 1.) - 1));
507532 for (i = 0; i < spectrum_width; ++i)
508533 pixel(cols - right - 1 - i, below + j) = b;
509534 }
@@ -528,18 +553,21 @@ sox_effect_handler_t const * sox_spectrogram_effect_fn(void) · 18 unmodified lines
528553 {
529554 static sox_effect_handler_t handler = {
530555 "spectrogram", "[options]\n"
531− " -x num X-axis pixels/second, default 100\n"
532− " -y num Y-axis resolution (1 - 4), default 2\n"
533− " -z num Z-axis (colour) range in dB, default 120\n"
534− " -g num Apply num dB gain; to shift Z-axis\n"
535− " -w name Window: Hann (default), Hamming, Bartlett, Rectangular, Kaiser\n"
536− " -s Slack overlap\n"
537− " -a Suppress axes' lines\n"
538− " -t text Title text\n"
539− " -c text Comment text\n"
540− " -l Light background\n"
541− " -m Monochrome display\n"
542− " -o text output file name, default `spectrogram.png'\n",
556+ "\t-x num\tX-axis pixels/second, default 100\n"
557+ "\t-y num\tY-axis resolution (1 - 4), default 2\n"
558+ "\t-z num\tZ-axis range in dB, default 120\n"
559+ "\t-Z num\tZ-axis maximum in dBFS, default 0\n"
560+ "\t-q num\tZ-axis quantisation, default 249\n"
561+ "\t-w name\tWindow: Hann (default), Hamming, Bartlett, Rectangular, Kaiser\n"
562+ "\t-s\tSlack overlap\n"
563+ "\t-a\tSuppress axis lines\n"
564+ "\t-l\tLight background\n"
565+ "\t-m\tMonochrome\n"
566+ "\t-h\tHigh colour\n"
567+ "\t-p num\tPermute colours\n"
568+ "\t-t text\tTitle text\n"
569+ "\t-c text\tComment text\n"
570+ "\t-o text\toutput file name, default `spectrogram.png'\n",
543571 0, getopts, start, flow, drain, stop, NULL, sizeof(priv_t)};
544572 return &handler;
545573 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t