shithub: sox

Download patch

ref: 7765a3215eadbb56ca67429b93538dfc559cbd12
parent: 38f21528d72f4fc3f5408fcd5104190d1d4e588c
author: robs <robs>
date: Wed Feb 20 03:12:52 EST 2008

VU meter improvements:
  o delineated meter limits
  o now only one red level: >= -1dB FSD
  o add 3-second peak hold display (dB headroom)

--- a/src/sox.c
+++ b/src/sox.c
@@ -422,7 +422,7 @@
 {
   size_t len;
 
-  for (len = 0; len < *isamp; len += effp->ininfo.channels) {
+  if (show_progress) for (len = 0; len < *isamp; len += effp->ininfo.channels) {
     omax[0] = max(omax[0], ibuf[len]);
     omin[0] = min(omin[0], ibuf[len]);
     if (effp->ininfo.channels > 1) {
@@ -557,35 +557,58 @@
   return string[n];
 }
 
+static sox_bool since(struct timeval * then, double secs, sox_bool always_reset)
+{
+  sox_bool ret;
+  struct timeval now;
+  time_t d;
+  gettimeofday(&now, NULL);
+  d = now.tv_sec - then->tv_sec;
+  ret = d > ceil(secs) || now.tv_usec - then->tv_usec + d * TIME_FRAC >= secs * TIME_FRAC;
+  if (ret || always_reset)
+    *then = now;
+  return ret;
+}
+
+#define MIN_HEADROOM 6.
+static double min_headroom = MIN_HEADROOM;
+
 static char const * vu(unsigned channel)
 {
+  static struct timeval then;
   static char const * const text[][2] = {
+    /* White: 2dB steps */
     {"", ""}, {"-", "-"}, {"=", "="}, {"-=", "=-"},
     {"==", "=="}, {"-==", "==-"}, {"===", "==="}, {"-===", "===-"},
     {"====", "===="}, {"-====", "====-"}, {"=====", "====="},
     {"-=====", "=====-"}, {"======", "======"},
-    {"!=====", "=====!"}, {"!!====", "====!!"}, /* 2 `red' levels */
+    /* Red: 1dB steps */
+    {"!=====", "=====!"},
   };
-  int const red = 2, white = array_length(text) - red;
+  int const red = 1, white = array_length(text) - red;
   double const MAX = SOX_SAMPLE_MAX, MIN = SOX_SAMPLE_MIN;
   double linear = max(omax[channel] / MAX, omin[channel] / MIN);
-  int vu_dB = linear? floor(2 * white + red - .5 + linear_to_dB(linear)) : 0;
-  int index = vu_dB < 2 * white? max(vu_dB / 2, 0) : vu_dB - white;
+  double dB = linear_to_dB(linear);
+  int vu_dB = linear? floor(2 * white + red + dB) : 0;
+  int index = vu_dB < 2 * white? max(vu_dB / 2, 0) : min(vu_dB - white, red + white - 1);
   omax[channel] = omin[channel] = 0;
+  if (-dB < min_headroom) {
+    gettimeofday(&then, NULL);
+    min_headroom = -dB;
+  }
+  else if (since(&then, 3., sox_false))
+    min_headroom = -dB;
+
   return text[index][channel];
 }
 
-static sox_bool since(struct timeval * then, double secs, sox_bool always_reset)
+static char * headroom(void)
 {
-  sox_bool ret;
-  struct timeval now;
-  time_t d;
-  gettimeofday(&now, NULL);
-  d = now.tv_sec - then->tv_sec;
-  ret = d > ceil(secs) || now.tv_usec - then->tv_usec + d * TIME_FRAC >= secs * TIME_FRAC;
-  if (ret || always_reset)
-    *then = now;
-  return ret;
+  static char buff[10];
+  unsigned h = (unsigned)(min_headroom * 10);
+  if (min_headroom >= MIN_HEADROOM) return "      ";
+  sprintf(buff, "Hd:%u.%u", h /10, h % 10);
+  return buff;
 }
 
 static void display_status(sox_bool all_done)
@@ -593,7 +616,7 @@
   static struct timeval then;
   if (!show_progress)
     return;
-  if (all_done || since(&then, .15, sox_false)) {
+  if (all_done || since(&then, .1, sox_false)) {
     double read_time = (double)read_wide_samples / combiner.rate;
     double left_time = 0, in_time = 0, percentage = 0;
 
@@ -602,10 +625,10 @@
       left_time = max(in_time - read_time, 0);
       percentage = max(100. * read_wide_samples / input_wide_samples, 0);
     }
-    fprintf(stderr, "\r%s [%s] of %s (%-5s) Samps out:%-5s%6s|%-6sClips:%-5s",
-      str_time(read_time), str_time(left_time), str_time(in_time),
-      sigfigs3p(percentage), sigfigs3(output_samples),
-      vu(0), vu(1), sigfigs3(total_clips()));
+    fprintf(stderr, "\r%-5s %s [%s] of %s Out:%-5s [%6s|%-6s]%s Clip:%-5s",
+      sigfigs3p(percentage), str_time(read_time), str_time(left_time),
+      str_time(in_time), sigfigs3(output_samples),
+      vu(0), vu(1), headroom(), sigfigs3(total_clips()));
   }
   if (all_done)
     fputc('\n', stderr);