add dithering to lp coeff quantization
authorJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 2 Feb 2007 06:14:41 +0000 (06:14 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 2 Feb 2007 06:14:41 +0000 (06:14 +0000)
src/libFLAC/lpc.c

index ffcc36d..c21b6dd 100644 (file)
@@ -152,10 +152,8 @@ void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_o
 int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
 {
        unsigned i;
-       FLAC__double d, cmax = -1e32;
+       FLAC__double cmax;
        FLAC__int32 qmax, qmin;
-       const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
-       const int min_shiftlimit = -max_shiftlimit - 1;
 
        FLAC__ASSERT(precision > 0);
        FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
@@ -166,19 +164,21 @@ int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order,
        qmin = -qmax;
        qmax--;
 
+       /* calc cmax = max( |lp_coeff[i]| ) */
+       cmax = 0.0;
        for(i = 0; i < order; i++) {
-               if(lp_coeff[i] == 0.0)
-                       continue;
-               d = fabs(lp_coeff[i]);
+               const FLAC__double d = fabs(lp_coeff[i]);
                if(d > cmax)
                        cmax = d;
        }
-redo_it:
+
        if(cmax <= 0.0) {
                /* => coefficients are all 0, which means our constant-detect didn't work */
                return 2;
        }
        else {
+               const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+               const int min_shiftlimit = -max_shiftlimit - 1;
                int log2cmax;
 
                (void)frexp(cmax, &log2cmax);
@@ -186,6 +186,9 @@ redo_it:
                *shift = (int)precision - log2cmax - 1;
 
                if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
+#ifdef FLAC__OVERFLOW_DETECT
+                       fprintf(stderr,"FLAC__lpc_quantize_coefficients: shift out of limit: shift=%d cmax=%f precision=%u\n",q,qmax,*shift,cmax,precision+1);
+#endif
 #if 0
                        /*@@@ this does not seem to help at all, but was not extensively tested either: */
                        if(*shift > max_shiftlimit)
@@ -197,36 +200,53 @@ redo_it:
        }
 
        if(*shift >= 0) {
+               FLAC__double error = 0.0;
+               FLAC__int32 q;
                for(i = 0; i < order; i++) {
-                       qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift));
-
-                       /* double-check the result */
-                       if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
+                       error += lp_coeff[i] * (1 << *shift);
+                       q = lround(error); /* round() is also suitable */
 #ifdef FLAC__OVERFLOW_DETECT
-                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift), floor((FLAC__double)lp_coeff[i] * (FLAC__double)(1 << *shift)));
+                       if(q > qmax)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+                       else if(q < qmin)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
 #endif
-                               cmax *= 2.0;
-                               goto redo_it;
-                       }
+                       if(q > qmax)
+                               q = qmax;
+                       else if(q < qmin)
+                               q = qmin;
+                       error -= q;
+                       qlp_coeff[i] = q;
                }
        }
-       else { /* (*shift < 0) */
+       /* negative shift is very rare but due to design flaw, negative shift is
+        * a NOP in the decoder, so it must be handled specially by scaling down
+        * coeffs
+        */
+       else {
                const int nshift = -(*shift);
+               FLAC__double error = 0.0;
+               FLAC__int32 q;
 #ifdef DEBUG
                fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
 #endif
                for(i = 0; i < order; i++) {
-                       qlp_coeff[i] = (FLAC__int32)floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift));
-
-                       /* double-check the result */
-                       if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
+                       error += lp_coeff[i] / (1 << nshift);
+                       q = lround(error); /* round() is also suitable */
 #ifdef FLAC__OVERFLOW_DETECT
-                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift), floor((FLAC__double)lp_coeff[i] / (FLAC__double)(1 << nshift)));
+                       if(q > qmax)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+                       else if(q < qmin)
+                               fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
 #endif
-                               cmax *= 2.0;
-                               goto redo_it;
-                       }
+                       if(q > qmax)
+                               q = qmax;
+                       else if(q < qmin)
+                               q = qmin;
+                       error -= q;
+                       qlp_coeff[i] = q;
                }
+               *shift = 0;
        }
 
        return 0;