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;
}