Fixes fixed-point overflow on really low energy
authorJean-Marc Valin <jean-marc.valin@octasic.com>
Thu, 27 Jan 2011 15:46:01 +0000 (10:46 -0500)
committerJean-Marc Valin <jean-marc.valin@octasic.com>
Thu, 27 Jan 2011 15:46:01 +0000 (10:46 -0500)
Makes celt_exp2() use Q10 input to avoid problems on very low energy.
Also makes the pitch downsampling more conservative on gain to avoid
problems later.

libcelt/bands.c
libcelt/mathops.h
libcelt/pitch.c
libcelt/quant_bands.c

index 1e3fc28..84ced2b 100644 (file)
@@ -231,7 +231,7 @@ void anti_collapse(const CELTMode *m, celt_norm *_X, unsigned char *collapse_mas
       depth = (1+pulses[i])/(m->eBands[i+1]-m->eBands[i]<<LM);
 
 #ifdef FIXED_POINT
-      thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,SHR32(celt_exp2(-SHL16(depth, 11-BITRES)),1) ));
+      thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1) ));
       {
          celt_word32 t;
          t = N0<<LM;
@@ -254,7 +254,7 @@ void anti_collapse(const CELTMode *m, celt_norm *_X, unsigned char *collapse_mas
 
 #ifdef FIXED_POINT
          if (Ediff < 16384)
-            r = 2*MIN16(16383,SHR32(celt_exp2(-SHL16(Ediff, 11-DB_SHIFT)),1));
+            r = 2*MIN16(16383,SHR32(celt_exp2(-Ediff),1));
          else
             r = 0;
          if (LM==3)
index 160c220..92adbe1 100644 (file)
@@ -175,17 +175,17 @@ static inline celt_word16 celt_log2(celt_word32 x)
 #define D1 22804
 #define D2 14819
 #define D3 10204
-/** Base-2 exponential approximation (2^x). (Q11 input, Q16 output) */
+/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */
 static inline celt_word32 celt_exp2(celt_word16 x)
 {
    int integer;
    celt_word16 frac;
-   integer = SHR16(x,11);
+   integer = SHR16(x,10);
    if (integer>14)
       return 0x7f000000;
    else if (integer < -15)
       return 0;
-   frac = SHL16(x-SHL16(integer,11),3);
+   frac = SHL16(x-SHL16(integer,10),4);
    frac = ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac))))));
    return VSHR32(EXTEND32(frac), -integer-2);
 }
index e02de3d..4c49597 100644 (file)
@@ -107,13 +107,13 @@ void pitch_downsample(celt_sig * restrict x[], celt_word16 * restrict x_lp,
    celt_word16 lpc[4], mem[4]={0,0,0,0};
    const int C = CHANNELS(_C);
    for (i=1;i<len>>1;i++)
-      x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT+2);
-   x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), SIG_SHIFT+2);
+      x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT+3);
+   x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), SIG_SHIFT+3);
    if (C==2)
    {
       for (i=1;i<len>>1;i++)
-         x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT+2);
-      x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT+2);
+         x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT+3);
+      x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT+3);
    }
 
    _celt_autocorr(x_lp, ac, NULL, 0,
index 4d14f46..867b3c7 100644 (file)
@@ -186,7 +186,7 @@ static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
       do {
          int bits_left;
          int qi, qi0;
-         celt_word16 q;
+         celt_word32 q;
          celt_word16 x;
          celt_word32 f, tmp;
          celt_word16 oldE;
@@ -246,15 +246,14 @@ static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
             qi = -1;
          error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT);
          badness += abs(qi0-qi);
-         q = SHL16(qi,DB_SHIFT);
+         q = SHL32(EXTEND32(qi),DB_SHIFT);
          
-         tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(EXTEND32(q),7);
+         tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7);
 #ifdef FIXED_POINT
          tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
 #endif
          oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
-         prev[c] = prev[c] + SHL32(EXTEND32(q),7) - PSHR32(MULT16_16(beta,q),8);
-
+         prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
       } while (++c < C);
    }
    return badness;
@@ -451,7 +450,7 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_word16 *o
       c=0;
       do {
          int qi;
-         celt_word16 q;
+         celt_word32 q;
          celt_word32 tmp;
          tell = ec_dec_tell(dec, 0);
          if(budget-tell>=15)
@@ -472,15 +471,15 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_word16 *o
          }
          else
             qi = -1;
-         q = SHL16(qi,DB_SHIFT);
+         q = SHL32(EXTEND32(qi),DB_SHIFT);
 
          oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
-         tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(EXTEND32(q),7);
+         tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7);
 #ifdef FIXED_POINT
          tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
 #endif
          oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
-         prev[c] = prev[c] + SHL32(EXTEND32(q),7) - PSHR32(MULT16_16(beta,q),8);
+         prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
       } while (++c < C);
    }
 }
@@ -549,9 +548,9 @@ void log2Amp(const CELTMode *m, int start, int end,
          eBands[i+c*m->nbEBands] = 0;
       for (;i<end;i++)
       {
-         celt_word16 lg = oldEBands[i+c*m->nbEBands]
-                        + SHL16((celt_word16)eMeans[i],6);
-         eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(SHL16(lg,11-DB_SHIFT)),4);
+         celt_word16 lg = ADD16(oldEBands[i+c*m->nbEBands],
+                         SHL16((celt_word16)eMeans[i],6));
+         eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4);
       }
       for (;i<m->nbEBands;i++)
          eBands[i+c*m->nbEBands] = 0;