Renamed celt_word* to opus_val*
[opus.git] / libcelt / vq.c
index 442347f..58173d8 100644 (file)
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    
-   - Neither the name of the Xiph.org Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-   
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 #include "vq.h"
 #include "arch.h"
 #include "os_support.h"
+#include "bands.h"
 #include "rate.h"
 
 #ifndef M_PI
 #define M_PI 3.141592653
 #endif
 
-static void exp_rotation1(celt_norm *X, int len, int stride, celt_word16 c, celt_word16 s)
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
 {
    int i;
    celt_norm *Xptr;
@@ -71,9 +68,10 @@ static void exp_rotation1(celt_norm *X, int len, int stride, celt_word16 c, celt
 
 static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
 {
+   static const int SPREAD_FACTOR[3]={15,10,5};
    int i;
-   celt_word16 c, s;
-   celt_word16 gain, theta;
+   opus_val16 c, s;
+   opus_val16 gain, theta;
    int stride2=0;
    int factor;
    /*int i;
@@ -84,18 +82,12 @@ static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int
       X[14] = 1;
       K=5;
    }*/
-   if (2*K>=len || spread==0)
+   if (2*K>=len || spread==SPREAD_NONE)
       return;
-   if (spread==1)
-      factor=10;
-   else if (spread==2)
-      factor=5;
-   else
-      factor=15;
+   factor = SPREAD_FACTOR[spread-1];
 
-   gain = celt_div((celt_word32)MULT16_16(Q15_ONE,len),(celt_word32)(len+factor*K));
-   /* FIXME: Make that HALF16 instead of HALF32 */
-   theta = HALF32(MULT16_16_Q15(gain,gain));
+   gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
+   theta = HALF16(MULT16_16_Q15(gain,gain));
 
    c = celt_cos_norm(EXTEND32(theta));
    s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /*  sin(theta) */
@@ -109,6 +101,8 @@ static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int
       while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
          stride2++;
    }
+   /*TODO: We should be passing around log2(B), not B, for both this and for
+      extract_collapse_mask().*/
    len /= stride;
    for (i=0;i<stride;i++)
    {
@@ -135,14 +129,14 @@ static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int
 /** Takes the pitch vector and the decoded residual vector, computes the gain
     that will give ||p+g*y||=1 and mixes the residual with the pitch. */
 static void normalise_residual(int * restrict iy, celt_norm * restrict X,
-      int N, int K, celt_word32 Ryy, celt_word16 gain)
+      int N, opus_val32 Ryy, opus_val16 gain)
 {
    int i;
 #ifdef FIXED_POINT
    int k;
 #endif
-   celt_word32 t;
-   celt_word16 g;
+   opus_val32 t;
+   opus_val16 g;
 
 #ifdef FIXED_POINT
    k = celt_ilog2(Ryy)>>1;
@@ -156,25 +150,46 @@ static void normalise_residual(int * restrict iy, celt_norm * restrict X,
    while (++i < N);
 }
 
-void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband,
-      int resynth, ec_enc *enc, celt_int32 *seed, celt_word16 gain)
+static unsigned extract_collapse_mask(int *iy, int N, int B)
+{
+   unsigned collapse_mask;
+   int N0;
+   int i;
+   if (B<=1)
+      return 1;
+   /*TODO: We should be passing around log2(B), not B, for both this and for
+      exp_rotation().*/
+   N0 = N/B;
+   collapse_mask = 0;
+   i=0; do {
+      int j;
+      j=0; do {
+         collapse_mask |= (iy[i*N0+j]!=0)<<i;
+      } while (++j<N0);
+   } while (++i<B);
+   return collapse_mask;
+}
+
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
+      int resynth, ec_enc *enc, opus_val16 gain)
 {
    VARDECL(celt_norm, y);
    VARDECL(int, iy);
-   VARDECL(celt_word16, signx);
+   VARDECL(opus_val16, signx);
    int i, j;
-   celt_word16 s;
+   opus_val16 s;
    int pulsesLeft;
-   celt_word32 sum;
-   celt_word32 xy;
-   celt_word16 yy;
+   opus_val32 sum;
+   opus_val32 xy;
+   opus_val16 yy;
+   unsigned collapse_mask;
    SAVE_STACK;
 
    celt_assert2(K!=0, "alg_quant() needs at least one pulse");
 
    ALLOC(y, N, celt_norm);
    ALLOC(iy, N, int);
-   ALLOC(signx, N, celt_word16);
+   ALLOC(signx, N, opus_val16);
    
    exp_rotation(X, N, 1, B, K, spread);
 
@@ -198,7 +213,7 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
    /* Do a pre-search by projecting on the pyramid */
    if (K > (N>>1))
    {
-      celt_word16 rcp;
+      opus_val16 rcp;
       j=0; do {
          sum += X[j];
       }  while (++j<N);
@@ -207,7 +222,9 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
 #ifdef FIXED_POINT
       if (sum <= K)
 #else
-      if (sum <= EPSILON)
+      /* Prevents infinities and NaNs from causing too many pulses
+         to be allocated. 64 is an approximation of infinity here. */
+      if (!(sum > EPSILON && sum < 64))
 #endif
       {
          X[0] = QCONST16(1.f,14);
@@ -241,7 +258,7 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
 #endif
    if (pulsesLeft > N+3)
    {
-      celt_word16 tmp = pulsesLeft;
+      opus_val16 tmp = pulsesLeft;
       yy = MAC16_16(yy, tmp, tmp);
       yy = MAC16_16(yy, tmp, y[0]);
       iy[0] += pulsesLeft;
@@ -252,8 +269,8 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
    for (i=0;i<pulsesLeft;i++)
    {
       int best_id;
-      celt_word32 best_num = -VERY_LARGE16;
-      celt_word16 best_den = 0;
+      opus_val32 best_num = -VERY_LARGE16;
+      opus_val16 best_den = 0;
 #ifdef FIXED_POINT
       int rshift;
 #endif
@@ -266,7 +283,7 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
       yy = ADD32(yy, 1);
       j=0;
       do {
-         celt_word16 Rxy, Ryy;
+         opus_val16 Rxy, Ryy;
          /* Temporary sums of the new pulse(s) */
          Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
          /* We're multiplying y[j] by two so we don't have to do it here */
@@ -308,20 +325,23 @@ void alg_quant(celt_norm *X, int N, int K, int spread, int B, celt_norm *lowband
    
    if (resynth)
    {
-      normalise_residual(iy, X, N, K, yy, gain);
+      normalise_residual(iy, X, N, yy, gain);
       exp_rotation(X, N, -1, B, K, spread);
    }
+   collapse_mask = extract_collapse_mask(iy, N, B);
    RESTORE_STACK;
+   return collapse_mask;
 }
 
 
 /** Decode pulse vector and combine the result with the pitch vector to produce
     the final normalised signal in the current band. */
-void alg_unquant(celt_norm *X, int N, int K, int spread, int B,
-      celt_norm *lowband, ec_dec *dec, celt_int32 *seed, celt_word16 gain)
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+      ec_dec *dec, opus_val16 gain)
 {
    int i;
-   celt_word32 Ryy;
+   opus_val32 Ryy;
+   unsigned collapse_mask;
    VARDECL(int, iy);
    SAVE_STACK;
 
@@ -333,33 +353,22 @@ void alg_unquant(celt_norm *X, int N, int K, int spread, int B,
    do {
       Ryy = MAC16_16(Ryy, iy[i], iy[i]);
    } while (++i < N);
-   normalise_residual(iy, X, N, K, Ryy, gain);
+   normalise_residual(iy, X, N, Ryy, gain);
    exp_rotation(X, N, -1, B, K, spread);
+   collapse_mask = extract_collapse_mask(iy, N, B);
    RESTORE_STACK;
+   return collapse_mask;
 }
 
-celt_word16 vector_norm(const celt_norm *X, int N)
-{
-   int i;
-   celt_word32 E = EPSILON;
-   const celt_norm *xptr = X;
-   for (i=0;i<N;i++)
-   {
-      E = MAC16_16(E, *xptr, *xptr);
-      xptr++;
-   }
-   return celt_sqrt(E);
-}
-
-void renormalise_vector(celt_norm *X, int N, celt_word16 gain)
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain)
 {
    int i;
 #ifdef FIXED_POINT
    int k;
 #endif
-   celt_word32 E = EPSILON;
-   celt_word16 g;
-   celt_word32 t;
+   opus_val32 E = EPSILON;
+   opus_val16 g;
+   opus_val32 t;
    celt_norm *xptr = X;
    for (i=0;i<N;i++)
    {
@@ -381,3 +390,42 @@ void renormalise_vector(celt_norm *X, int N, celt_word16 gain)
    /*return celt_sqrt(E);*/
 }
 
+int stereo_itheta(celt_norm *X, celt_norm *Y, int stereo, int N)
+{
+   int i;
+   int itheta;
+   opus_val16 mid, side;
+   opus_val32 Emid, Eside;
+
+   Emid = Eside = EPSILON;
+   if (stereo)
+   {
+      for (i=0;i<N;i++)
+      {
+         celt_norm m, s;
+         m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
+         s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
+         Emid = MAC16_16(Emid, m, m);
+         Eside = MAC16_16(Eside, s, s);
+      }
+   } else {
+      for (i=0;i<N;i++)
+      {
+         celt_norm m, s;
+         m = X[i];
+         s = Y[i];
+         Emid = MAC16_16(Emid, m, m);
+         Eside = MAC16_16(Eside, s, s);
+      }
+   }
+   mid = celt_sqrt(Emid);
+   side = celt_sqrt(Eside);
+#ifdef FIXED_POINT
+   /* 0.63662 = 2/pi */
+   itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
+#else
+   itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
+#endif
+
+   return itheta;
+}