SB-CELP decoder (continued)
[speexdsp.git] / libspeex / cb_search.c
index 85360ef..dcdf72a 100644 (file)
 
 \*-----------------------------------------------------------------------*/
 
-/* Modified by Jean-Marc Valin 2002 */
+/* Modified by Jean-Marc Valin 2002
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
 
 
 #include <stdlib.h>
 #include <cb_search.h>
 #include "filters.h"
+#include <math.h>
+#include <stdio.h>
+#include "stack_alloc.h"
+#include "vq.h"
+#include "matrix.h"
 
-#define min(a,b) ((a) < (b) ? (a) : (b))
+static float scal_gains4[16] = {
+   0.27713,
+   0.49282,
+   0.69570,
+   0.90786,
+   1.14235,
+   1.42798,
+   1.80756,
+   2.42801
+};
 
 /*---------------------------------------------------------------------------*\
                                                                              
@@ -30,7 +60,7 @@
                                                                              
 \*---------------------------------------------------------------------------*/
 
-void overlap_cb_search(
+float overlap_cb_search(
 float target[],                        /* target vector */
 float ak[],                    /* LPCs for this subframe */
 float awk1[],                  /* Weighted LPCs for this subframe */
@@ -64,7 +94,7 @@ int   nsf                       /* number of samples in subframe */
   bscore = 0.0;
   impulse[0] = 1.0;
 
-  /* Calculate impulse response of  A(z/g2) / ( A(z)*(z/g1) ) */
+  /* Calculate impulse response of  A(z/g1) / ( A(z)*(z/g2) ) */
   residue_zero(impulse, awk1, h, nsf, p);
   syn_filt_zero(h, ak, h, nsf, p);
   syn_filt_zero(h, awk2, h, nsf,p);
@@ -81,7 +111,7 @@ int   nsf                       /* number of samples in subframe */
     d = 0.0; e = 0.0;
     for(i=0; i<nsf; i++) {
       d += target[i]*resp[i];
-      e += resp[i]*resp[i]+1;
+      e += resp[i]*resp[i];
     }
     g = d/(e+.1);
     score = g*d;
@@ -104,6 +134,231 @@ int   nsf                       /* number of samples in subframe */
   free(resp);
   free(h);
   free(impulse);
+  return bscore;
+}
+
+
+
+void split_cb_search(
+float target[],                        /* target vector */
+float ak[],                    /* LPCs for this subframe */
+float awk1[],                  /* Weighted LPCs for this subframe */
+float awk2[],                  /* Weighted LPCs for this subframe */
+void *par,                      /* Codebook/search parameters*/
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+float *exc,
+FrameBits *bits,
+float *stack
+)
+{
+   int i,j;
+   float *resp, *E, *Ee;
+   float *t, *r, *e, *tresp;
+   float *gains;
+   int *ind;
+   float *shape_cb;
+   int shape_cb_size, subvect_size, nb_subvect;
+   float exc_energy=0;
+   split_cb_params *params;
+
+   params = (split_cb_params *) par;
+   subvect_size = params->subvect_size;
+   nb_subvect = params->nb_subvect;
+   shape_cb_size = 1<<params->shape_bits;
+   shape_cb = params->shape_cb;
+   resp = PUSH(stack, shape_cb_size*subvect_size);
+   tresp = PUSH(stack, shape_cb_size*nsf);
+   E = PUSH(stack, shape_cb_size);
+   Ee = PUSH(stack, shape_cb_size);
+   t = PUSH(stack, nsf);
+   r = PUSH(stack, nsf);
+   e = PUSH(stack, nsf);
+   gains = PUSH(stack, nb_subvect);
+   ind = (int*)PUSH(stack, nb_subvect);
+
+   syn_filt_zero(target, awk1, e, nsf, p);
+   residue_zero(e, ak, e, nsf, p);
+   residue_zero(e, awk2, e, nsf, p);
+   for (i=0;i<nsf;i++)
+      exc_energy += e[i]*e[i];
+   exc_energy=sqrt(.125*exc_energy);
+
+   /* Quantize global (average) gain */
+   {
+      float q;
+      int id;
+      q=log(exc_energy+.1);
+      q=floor(.5+2*(q-2));
+      if (q<0)
+         q=0;
+      if (q>15)
+         q=15;
+      id = (int)q;
+      frame_bits_pack(bits, id, 4);
+      exc_energy=exp(.5*q+2);
+   }
+
+   for (i=0;i<nsf;i++)
+      t[i]=target[i];
+   for (i=0;i<shape_cb_size;i++)
+   {
+      float *res = resp+i*subvect_size;
+      residue_zero(shape_cb+i*subvect_size, awk1, res, subvect_size, p);
+      syn_filt_zero(res, ak, res, subvect_size, p);
+      syn_filt_zero(res, awk2, res, subvect_size,p);
+      E[i]=0;
+      for(j=0;j<subvect_size;j++)
+         E[i]+=res[j]*res[j];
+      Ee[i]=0;
+      for(j=0;j<subvect_size;j++)
+         Ee[i]+=shape_cb[i*subvect_size+j]*shape_cb[i*subvect_size+j];
+      
+   }
 
+   for (i=0;i<nb_subvect;i++)
+   {
+      int best_index=0;
+      float g, corr, best_gain=0, score, best_score=-1;
+      for (j=0;j<shape_cb_size;j++)
+      {
+         corr=xcorr(resp+j*subvect_size,t+subvect_size*i,subvect_size);
+         score=corr*corr/(.001+E[j]);
+         g = corr/(.001+E[j]);
+         if (score>best_score)
+         {
+            best_index=j;
+            best_score=score;
+            best_gain=corr/(.001+E[j]);
+         }
+      }
+      frame_bits_pack(bits,best_index,params->shape_bits);
+      {
+         int s=0, best_id, j;
+         float best_dist;
+         best_gain /= .01+exc_energy;
+         if (best_gain<0)
+         {
+            best_gain=-best_gain;
+            s=1;
+         }
+         best_dist=(best_gain-scal_gains4[0])*(best_gain-scal_gains4[0]);
+         best_id=0;
+         for (j=1;j<8;j++)
+         {
+            float dist;
+            dist=(best_gain-scal_gains4[j])*(best_gain-scal_gains4[j]);
+            if (dist<best_dist)
+            {
+               best_id=j;
+               best_dist=dist;
+            }
+         }
+         best_gain=scal_gains4[best_id];
+         /*printf ("gain_quant: %f %d %f\n", best_gain, best_id, scal_gains4[best_id]);*/
+         if (s)
+            best_gain=-best_gain;
+         best_gain *= exc_energy;
+         frame_bits_pack(bits,s,1);
+         frame_bits_pack(bits,best_id,3);
+      }
+      ind[i]=best_index;
+      gains[i]=best_gain;
+
+      for (j=0;j<nsf;j++)
+         e[j]=0;
+      for (j=0;j<subvect_size;j++)
+         e[subvect_size*i+j]=best_gain*shape_cb[best_index*subvect_size+j];
+      residue_zero(e, awk1, r, nsf, p);
+      syn_filt_zero(r, ak, r, nsf, p);
+      syn_filt_zero(r, awk2, r, nsf,p);
+      for (j=0;j<nsf;j++)
+         tresp[i*nsf+j]=r[j];
+      for (j=0;j<nsf;j++)
+         t[j]-=r[j];
+   }
+   
+   for (i=0;i<nb_subvect;i++)
+      for (j=0;j<subvect_size;j++)
+         e[subvect_size*i+j]=gains[i]*shape_cb[ind[i]*subvect_size+j];
+
+   for (j=0;j<nsf;j++)
+      exc[j]+=e[j];
+   residue_zero(e, awk1, r, nsf, p);
+   syn_filt_zero(r, ak, r, nsf, p);
+   syn_filt_zero(r, awk2, r, nsf,p);
+   for (j=0;j<nsf;j++)
+      target[j]-=r[j];
+
+   
+
+
+   POP(stack);
+   POP(stack);
+   POP(stack);
+   POP(stack);
+   POP(stack);
+   POP(stack);
+   POP(stack);
+   POP(stack);
 }
 
+
+
+
+void split_cb_unquant(
+float *exc,
+void *par,                      /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+FrameBits *bits,
+float *stack
+)
+{
+   int i,j;
+   int *ind;
+   float *gains;
+   float *sign;
+   float *shape_cb, exc_energy;
+   int shape_cb_size, subvect_size, nb_subvect;
+   split_cb_params *params;
+
+   params = (split_cb_params *) par;
+   subvect_size = params->subvect_size;
+   nb_subvect = params->nb_subvect;
+   shape_cb_size = 1<<params->shape_bits;
+   shape_cb = params->shape_cb;
+   
+   ind = (int*)PUSH(stack, nb_subvect);
+   gains = PUSH(stack, nb_subvect);
+   sign = PUSH(stack, nb_subvect);
+
+   /* Decode global (average) gain */
+   {
+      int id;
+      id = frame_bits_unpack_unsigned(bits, 4);
+      exc_energy=exp(.5*id+2);
+   }
+
+   for (i=0;i<nb_subvect;i++)
+   {
+      int gain_id;
+      ind[i] = frame_bits_unpack_unsigned(bits, params->shape_bits);
+      if (frame_bits_unpack_unsigned(bits, 1))
+         sign[i]=-1;
+      else
+         sign[i]=1;
+      
+      gain_id = frame_bits_unpack_unsigned(bits, 3);
+      gains[i]=scal_gains4[gain_id];
+      gains[i] *= sign[i];
+      gains[i] *= exc_energy;
+   }
+
+   for (i=0;i<nb_subvect;i++)
+      for (j=0;j<subvect_size;j++)
+         exc[subvect_size*i+j]+=gains[i]*shape_cb[ind[i]*subvect_size+j];
+   
+   POP(stack);
+   POP(stack);
+   POP(stack);
+}