shithub: sox

Download patch

ref: 77360f7193a2ba2e8473bf83609d9462e8cdb617
parent: 0e6972cf5804d39f2db6389fb33c217361c93c54
author: Mans Rullgard <mans@mansr.com>
date: Mon Dec 16 12:20:40 EST 2019

mp3: fix duration calculation

Avoid rounding errors as much as possible.  It is still possible for
the CBR extrapolation to be slightly off.

--- a/src/mp3-util.h
+++ b/src/mp3-util.h
@@ -249,22 +249,16 @@
   return 0;
 }
 
-static void mad_timer_mult(mad_timer_t * t, double d)
+static size_t mp3_duration(sox_format_t * ft)
 {
-  t->seconds = (signed long)(d *= (t->seconds + t->fraction * (1. / MAD_TIMER_RESOLUTION)));
-  t->fraction = (unsigned long)((d - t->seconds) * MAD_TIMER_RESOLUTION + .5);
-}
-
-static size_t mp3_duration_ms(sox_format_t * ft)
-{
   priv_t              * p = (priv_t *) ft->priv;
   struct mad_stream   mad_stream;
   struct mad_header   mad_header;
   struct mad_frame    mad_frame;
-  mad_timer_t         time = mad_timer_zero;
   size_t              initial_bitrate = 0; /* Initialised to prevent warning */
   size_t              tagsize = 0, consumed = 0, frames = 0;
   sox_bool            vbr = sox_false, depadded = sox_false;
+  size_t              num_samples = 0;
 
   p->mad_stream_init(&mad_stream);
   p->mad_header_init(&mad_header);
@@ -309,7 +303,7 @@
         continue; /* Not an audio frame */
       }
 
-      p->mad_timer_add(&time, mad_header.duration);
+      num_samples += MAD_NSBSAMPLES(&mad_header) * 32;
       consumed += mad_stream.next_frame - mad_stream.this_frame;
 
       lsx_debug_more("bitrate=%lu", mad_header.bitrate);
@@ -324,7 +318,7 @@
             break;
           }
         if ((frames = xing_frames(p, mad_stream.anc_ptr, mad_stream.anc_bitlen))) {
-          p->mad_timer_multiply(&time, (signed long)frames);
+          num_samples *= frames;
           lsx_debug("got exact duration from XING frame count (%" PRIuPTR ")", frames);
           break;
         }
@@ -333,7 +327,9 @@
 
       /* If not VBR, we can time just a few frames then extrapolate */
       if (++frames == 25 && !vbr) {
-        mad_timer_mult(&time, (double)(lsx_filelength(ft) - tagsize) / consumed);
+        double frame_size = (double) consumed / frames;
+        size_t num_frames = (lsx_filelength(ft) - tagsize) / frame_size;
+        num_samples = num_samples / frames * num_frames;
         lsx_debug("got approx. duration by CBR extrapolation");
         break;
       }
@@ -344,7 +340,8 @@
   mad_header_finish(&mad_header);
   p->mad_stream_finish(&mad_stream);
   lsx_rewind(ft);
-  return p->mad_timer_count(time, MAD_UNITS_MILLISECONDS);
+
+  return num_samples;
 }
 
 #endif /* HAVE_MAD_H */
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -391,7 +391,7 @@
     if (!ft->signal.length)
 #endif
       if (!ignore_length)
-        ft->signal.length = mp3_duration_ms(ft);
+        ft->signal.length = mp3_duration(ft);
   }
 
   p->mad_stream_init(&p->Stream);
@@ -466,7 +466,6 @@
   if (ignore_length)
     ft->signal.length = SOX_UNSPEC;
   else {
-    ft->signal.length = (uint64_t)(ft->signal.length * .001 * ft->signal.rate + .5);
     ft->signal.length *= ft->signal.channels;  /* Keep separate from line above! */
   }