shithub: opus

Download patch

ref: f8eb420a09a1c57430505f52f282c7ed5b225db3
parent: ba8e2f7b2932cd68a6ff3f19c695a0771a0ec7b9
author: Jean-Marc Valin <[email protected]>
date: Fri Mar 7 09:44:56 EST 2008

Changed the pulse spreading rotations so that the number of iterations is
variable instead of the angle. Should now be both less CPU-intensive and
makes fixed-point code simpler.

--- a/libcelt/bands.c
+++ b/libcelt/bands.c
@@ -41,13 +41,13 @@
 #include "os_support.h"
 #include "mathops.h"
 
-void exp_rotation(celt_norm_t *X, int len, celt_word16_t theta, int dir, int stride, int iter)
+void exp_rotation(celt_norm_t *X, int len, int dir, int stride, int iter)
 {
    int i, k;
    celt_word16_t c, s;
-   /* c = cos(theta); s = dir*sin(theta); but we're approximating here for small theta */
-   c = Q15ONE-MULT16_16_Q15(QCONST16(.5f,15),MULT16_16_Q15(theta,theta));
-   s = dir*theta;
+   /* Equivalent to cos(.3) and sin(.3) */
+   c = QCONST16(0.95534,15);
+   s = dir*QCONST16(0.29552,15);
    for (k=0;k<iter;k++)
    {
       /* We could use MULT16_16_P15 instead of MULT16_16_Q15 for more accuracy, 
@@ -255,11 +255,11 @@
       
       if (q > 0)
       {
-         celt_word16_t theta = DIV32_16(MULT16_16_16(QCONST16(.007f,15),B*(eBands[i+1]-eBands[i])),q);
-         exp_rotation(P+B*eBands[i], B*(eBands[i+1]-eBands[i]), theta, -1, B, 8);
-         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), theta, -1, B, 8);
+         int nb_rotations = (B*(eBands[i+1]-eBands[i])+4*q)/(8*q);
+         exp_rotation(P+B*eBands[i], B*(eBands[i+1]-eBands[i]), -1, B, nb_rotations);
+         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), -1, B, nb_rotations);
          alg_quant(X+B*eBands[i], W+B*eBands[i], B*(eBands[i+1]-eBands[i]), q, P+B*eBands[i], alpha, enc);
-         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), theta, 1, B, 8);
+         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), 1, B, nb_rotations);
       }
       for (j=B*eBands[i];j<B*eBands[i+1];j++)
          norm[j] = MULT16_16_Q15(n,X[j]);
@@ -316,10 +316,10 @@
       
       if (q > 0)
       {
-         celt_word16_t theta = DIV32_16(MULT16_16_16(QCONST16(.007f,15),B*(eBands[i+1]-eBands[i])),q);
-         exp_rotation(P+B*eBands[i], B*(eBands[i+1]-eBands[i]), theta, -1, B, 8);
+         int nb_rotations = (B*(eBands[i+1]-eBands[i])+4*q)/(8*q);
+         exp_rotation(P+B*eBands[i], B*(eBands[i+1]-eBands[i]), -1, B, nb_rotations);
          alg_unquant(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), q, P+B*eBands[i], alpha, dec);
-         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), theta, 1, B, 8);
+         exp_rotation(X+B*eBands[i], B*(eBands[i+1]-eBands[i]), 1, B, nb_rotations);
       }
       for (j=B*eBands[i];j<B*eBands[i+1];j++)
          norm[j] = MULT16_16_Q15(n,X[j]);
--- a/libcelt/bands.h
+++ b/libcelt/bands.h
@@ -41,7 +41,7 @@
 /** Applies a series of rotations so that pulses are spread like a two-sided
 exponential. The effect of this is to reduce the tonal noise created by the
 sparse spectrum resulting from the pulse codebook */
-void exp_rotation(celt_norm_t *X, int len, celt_word16_t theta, int dir, int stride, int iter);
+void exp_rotation(celt_norm_t *X, int len, int dir, int stride, int iter);
 
 /** Normalise each band of X such that the energy in each band is 
     equal to 1
--- a/tests/rotation-test.c
+++ b/tests/rotation-test.c
@@ -13,31 +13,37 @@
 void test_rotation(int N, int K)
 {
    int i;
-   double err = 0, ener = 0, snr;
-   celt_word16_t theta = Q15_ONE*.007*N/K;
+   double err = 0, ener = 0, snr, snr0;
    celt_word16_t x0[MAX_SIZE];
    celt_word16_t x1[MAX_SIZE];
+   int nb_rotations = (N+4*K)/(8*K);
    for (i=0;i<N;i++)
       x1[i] = x0[i] = rand()%32767-16384;
-   exp_rotation(x1, N, theta, 1, 1, 8);
-   exp_rotation(x1, N, theta, -1, 1, 8);
+   exp_rotation(x1, N, 1, 1, nb_rotations);
    for (i=0;i<N;i++)
    {
       err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
       ener += x0[i]*(double)x0[i];
    }
+   snr0 = 20*log10(ener/err);
+   err = ener = 0;
+   exp_rotation(x1, N, -1, 1, nb_rotations);
+   for (i=0;i<N;i++)
+   {
+      err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
+      ener += x0[i]*(double)x0[i];
+   }
    snr = 20*log10(ener/err);
-   printf ("SNR for size %d (%d pulses) is %f\n", N, K, snr);
-   if (snr < 60)
+   printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0);
+   if (snr < 60 || snr0 > 20)
       ret = 1;
 }
 
 int main()
 {
-   test_rotation(4, 40);
-   test_rotation(7, 20);
-   test_rotation(10, 10);
+   test_rotation(15, 3);
    test_rotation(23, 5);
    test_rotation(50, 3);
+   test_rotation(80, 1);
    return ret;
 }