removed unused variable
[speexdsp.git] / libspeex / cb_search.c
index 7b7e9e9..d171e54 100644 (file)
@@ -1,3 +1,4 @@
+/* Original copyright */
 /*-----------------------------------------------------------------------*\
 
     FILE........: GAINSHAPE.C
@@ -10,6 +11,7 @@
 
 \*-----------------------------------------------------------------------*/
 
+
 /* Modified by Jean-Marc Valin 2002
 
    This library is free software; you can redistribute it and/or
 #include "vq.h"
 #include "matrix.h"
 
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+
 static float scal_gains4[16] = {
    0.27713,
    0.49282,
@@ -49,6 +55,7 @@ static float scal_gains4[16] = {
    2.42801
 };
 
+
 /*---------------------------------------------------------------------------*\
                                                                              
  void overlap_cb_search()                                                            
@@ -70,7 +77,8 @@ int   entries,                        /* number of overlapping entries to search */
 float *gain,                   /* gain of optimum entry */
 int   *index,                  /* index of optimum entry */
 int   p,                        /* number of LPC coeffs */
-int   nsf                       /* number of samples in subframe */
+int   nsf,                      /* number of samples in subframe */
+float *stack
 )
 {
   float *resp;                 /* zero state response to current entry */
@@ -82,9 +90,13 @@ int   nsf                       /* number of samples in subframe */
 
   /* Initialise */
   
-  resp = (float*)malloc(sizeof(float)*nsf);
+  /*resp = (float*)malloc(sizeof(float)*nsf);
   h = (float*)malloc(sizeof(float)*nsf);
   impulse = (float*)malloc(sizeof(float)*nsf);
+  */
+  resp=PUSH(stack, nsf);
+  h=PUSH(stack, nsf);
+  impulse=PUSH(stack, nsf);
 
   for(i=0; i<nsf; i++)
     impulse[i] = 0.0;
@@ -113,7 +125,7 @@ int   nsf                       /* number of samples in subframe */
       d += target[i]*resp[i];
       e += resp[i]*resp[i];
     }
-    g = d/(e+.1);
+    g = d/(e+.0001);
     score = g*d;
     /*printf ("score: %f %f %f %f\n", target[0],d,e,score);*/
     if (score >= bscore) {
@@ -131,9 +143,12 @@ int   nsf                       /* number of samples in subframe */
     }
   }
 
-  free(resp);
+  /*free(resp);
   free(h);
-  free(impulse);
+  free(impulse);*/
+  POP(stack);
+  POP(stack);
+  POP(stack);
   return bscore;
 }
 
@@ -152,9 +167,9 @@ FrameBits *bits,
 float *stack
 )
 {
-   int i,j;
-   float *resp, *E, *Ee;
-   float *t, *r, *e, *tresp;
+   int i,j, id;
+   float *resp, *E, q;
+   float *t, *r, *e;
    float *gains;
    int *ind;
    float *shape_cb;
@@ -168,139 +183,511 @@ float *stack
    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);
 
+   /* Compute energy of the "real excitation" */
    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);
+   exc_energy=sqrt(exc_energy/nb_subvect);
+
+   /* Quantize global ("average") gain */
+   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);
 
-   /* Quantize global (average) gain */
-   {
-      float q;
-      q=log(exc_energy+.1);
-      q=floor(.5+2*(q-2));
-      if (q<0)
-         q=0;
-      if (q>15)
-         q=15;
-      exc_energy=exp(.5*q+2);
-   }
 
    for (i=0;i<nsf;i++)
       t[i]=target[i];
+
+   e[0]=1;
+   for (i=1;i<nsf;i++)
+      e[i]=0;
+   residue_zero(e, awk1, r, nsf, p);
+   syn_filt_zero(r, ak, r, nsf, p);
+   syn_filt_zero(r, awk2, r, nsf,p);
+   
+   /* Pre-compute codewords response and energy */
    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);
+
+      /* Compute codeword response */
+      int k;
+      for(j=0;j<subvect_size;j++)
+         res[j]=0;
+      for(j=0;j<subvect_size;j++)
+      {
+         for (k=j;k<subvect_size;k++)
+            res[k]+=shape_cb[i*subvect_size+j]*r[k-j];
+      }
+      /* Compute energy of codeword response */
       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];
-      
+      E[i]=1/(.001+E[i]);
    }
 
    for (i=0;i<nb_subvect;i++)
    {
-      int best_index=0;
+      int best_index=0, k, m;
       float g, corr, best_gain=0, score, best_score=-1;
+      /* Find best codeword for current sub-vector */
       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]);
+         score=corr*corr*E[j];
+         g = corr*E[j];
          if (score>best_score)
          {
             best_index=j;
             best_score=score;
-            best_gain=corr/(.001+E[j]);
+            best_gain=g;
          }
       }
+      frame_bits_pack(bits,best_index,params->shape_bits);
+      
+      /* Quantize gain */
       {
-         int s=0, best_id, j;
-         float best_dist;
+         int s=0, best_id;
          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;
-            }
-         }
+
+         /* Find gain index (it's a scalar but we use the VQ code anyway)*/
+         best_id = vq_index(&best_gain, scal_gains4, 1, 8);
+
          best_gain=scal_gains4[best_id];
-         printf ("gain_quant: %f %d %f\n", best_gain, best_id, 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);
       }
-      frame_bits_pack(bits,best_index,params->shape_bits);
-      if (best_gain>0)
-         frame_bits_pack(bits,0,1);
-      else
-          frame_bits_pack(bits,1,1);        
       ind[i]=best_index;
       gains[i]=best_gain;
-
-      for (j=0;j<nsf;j++)
-         e[j]=0;
+      /* Update target for next subvector */
       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 (j=0;j<nsf;j++)
-        exc[j]+=e[j];*/
+      {
+         g=best_gain*shape_cb[best_index*subvect_size+j];
+         for (k=subvect_size*i+j,m=0;k<nsf;k++,m++)
+            t[k] -= g*r[m];
+      }
    }
+   
+   /* Put everything back together */
+   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];
+
+   /* Update excitation */
+   for (j=0;j<nsf;j++)
+      exc[j]+=e[j];
+   
+   /* Update target */
+   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);
+}
+
+void split_cb_search_nogain(
+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;
+   float *t, *r, *e;
+   int *ind;
+   float *shape_cb;
+   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;
+   resp = PUSH(stack, shape_cb_size*subvect_size);
+   t = PUSH(stack, nsf);
+   r = PUSH(stack, nsf);
+   e = PUSH(stack, nsf);
+   ind = (int*)PUSH(stack, nb_subvect);
+
+   for (i=0;i<nsf;i++)
+      t[i]=target[i];
+
+   e[0]=1;
+   for (i=1;i<nsf;i++)
+      e[i]=0;
+   residue_zero(e, awk1, r, nsf, p);
+   syn_filt_zero(r, ak, r, nsf, p);
+   syn_filt_zero(r, awk2, r, nsf,p);
+   
+   /* Pre-compute codewords response and energy */
+   for (i=0;i<shape_cb_size;i++)
+   {
+      float *res = resp+i*subvect_size;
+
+      /* Compute codeword response */
+      int k;
+      for(j=0;j<subvect_size;j++)
+         res[j]=0;
+      for(j=0;j<subvect_size;j++)
+      {
+         for (k=j;k<subvect_size;k++)
+            res[k]+=shape_cb[i*subvect_size+j]*r[k-j];
+      }
+   }
+
+   for (i=0;i<nb_subvect;i++)
    {
-         printf ("exc_gains");
-         for (i=0;i<nb_subvect;i++)
-            printf (" %f", gains[i]/(.01f+exc_energy));
-         printf ("\n");
-      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];
+      int best_index=0, k, m;
+      float g, dist, best_dist=-1;
+      float *a, *b;
+      /* Find best codeword for current sub-vector */
+      for (j=0;j<shape_cb_size;j++)
+      {
+         dist=0;
+         a=resp+j*subvect_size;
+         b=t+subvect_size*i;
+         for (k=0;k<subvect_size;k++)
+            dist += (a[k]-b[k])*(a[k]-b[k]);
+         if (dist<best_dist || j==0)
+         {
+            best_dist=dist;
+            best_index=j;
+         }
+      }
+      /*printf ("best index: %d/%d\n", best_index, shape_cb_size);*/
+      frame_bits_pack(bits,best_index,params->shape_bits);
 
+      ind[i]=best_index;
+      /* Update target for next subvector */
+      for (j=0;j<subvect_size;j++)
+      {
+         g=shape_cb[best_index*subvect_size+j];
+         for (k=subvect_size*i+j,m=0;k<nsf;k++,m++)
+            t[k] -= g*r[m];
+      }
    }
+   
+   /* Put everything back together */
+   for (i=0;i<nb_subvect;i++)
+      for (j=0;j<subvect_size;j++)
+         e[subvect_size*i+j]=shape_cb[ind[i]*subvect_size+j];
 
+   /* Update excitation */
+   for (j=0;j<nsf;j++)
+      exc[j]+=e[j];
+   
+   /* Update target */
+   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);
+}
+
+
+
+
+void split_cb_search2(
+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, id;
+   float *resp, *E, q;
+   float *t, *r, *e;
+   float *gains;
+   int *ind, *gain_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);
+   E = 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);
+   gain_ind = (int*)PUSH(stack, nb_subvect);
+
+   /* Compute energy of the "real excitation" */
+   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(exc_energy/nb_subvect);
+
+   /* Quantize global ("average") gain */
+   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];
+
+   e[0]=1;
+   for (i=1;i<nsf;i++)
+      e[i]=0;
+   residue_zero(e, awk1, r, nsf, p);
+   syn_filt_zero(r, ak, r, nsf, p);
+   syn_filt_zero(r, awk2, r, nsf,p);
+   
+   /* Pre-compute codewords response and energy */
+   for (i=0;i<shape_cb_size;i++)
+   {
+      float *res = resp+i*subvect_size;
+
+      /* Compute codeword response */
+      int k;
+      for(j=0;j<subvect_size;j++)
+         res[j]=0;
+      for(j=0;j<subvect_size;j++)
+      {
+         for (k=j;k<subvect_size;k++)
+            res[k]+=shape_cb[i*subvect_size+j]*r[k-j];
+      }
+      /* Compute energy of codeword response */
+      E[i]=0;
+      for(j=0;j<subvect_size;j++)
+         E[i]+=res[j]*res[j];
+      E[i]=1/(.001+E[i]);
+   }
+
+   for (i=0;i<nb_subvect;i++)
+   {
+      int best_index[2]={0,0}, k, m, best_gain_ind[2]={0,0};
+      float g, corr, best_gain[2]={0,0}, score, best_score[2]={-1,-1};
+      /* Find best codeword for current sub-vector */
+      for (j=0;j<shape_cb_size;j++)
+      {
+         corr=xcorr(resp+j*subvect_size,t+subvect_size*i,subvect_size);
+         score=corr*corr*E[j];
+         g = corr*E[j];
+         if (score>best_score[0])
+         {
+            best_index[1]=best_index[0];
+            best_score[1]=best_score[0];
+            best_gain[1]=best_gain[0];
+
+            best_index[0]=j;
+            best_score[0]=score;
+            best_gain[0]=g;
+         } else if (score>best_score[1]) {
+            best_index[1]=j;
+            best_score[1]=score;
+            best_gain[1]=g;            
+         }
+      }
+      
+      /* Quantize gain */
+      for (k=0;k<2;k++) {
+         int s=0, best_id;
+         best_gain[k] /= .01+exc_energy;
+         if (best_gain[k]<0)
+         {
+            best_gain[k]=-best_gain[k];
+            s=1;
+         }
+
+         /* Find gain index (it's a scalar but we use the VQ code anyway)*/
+         best_id = vq_index(&best_gain[k], scal_gains4, 1, 8);
+
+         best_gain_ind[k]=best_id;
+         best_gain[k]=scal_gains4[best_id];
+         /*printf ("gain_quant: %f %d %f\n", best_gain, best_id, scal_gains4[best_id]);*/
+         if (s)
+            best_gain[k]=-best_gain[k];
+         best_gain[k] *= exc_energy;
+      }
+
+
+
+      if (i<nb_subvect-1) {
+         int best_index2=0;
+         float best_score2=-1, best_gain2=0;
+         int nbest;
+         float err[2]={0,0};
+         float *tt=PUSH(stack,nsf);
+         for (nbest=0;nbest<2;nbest++)
+         {
+            for (j=0;j<nsf;j++)
+               tt[j]=t[j];
+            for (j=0;j<subvect_size;j++)
+            {
+               g=best_gain[nbest]*shape_cb[best_index[nbest]*subvect_size+j];
+               for (k=subvect_size*i+j,m=0;k<nsf;k++,m++)
+                  tt[k] -= g*r[m];
+            }
+            
+
+            for (j=0;j<shape_cb_size;j++)
+            {
+               corr=xcorr(resp+j*subvect_size,tt+subvect_size*(i+1),subvect_size);
+               score=corr*corr*E[j];
+               g = corr*E[j];
+               if (score>best_score2)
+               {
+                  best_index2=j;
+                  best_score2=score;
+                  best_gain2=g;
+               }
+            }
+
+            {
+               int s=0, best_id;
+               best_gain2 /= .01+exc_energy;
+               if (best_gain2<0)
+               {
+                  best_gain2=-best_gain2;
+                  s=1;
+               }
+               best_id = vq_index(&best_gain2, scal_gains4, 1, 8);
+               best_gain2=scal_gains4[best_id];
+               if (s)
+                  best_gain2=-best_gain2;
+               best_gain2 *= exc_energy;
+            }
+
+            for (j=0;j<subvect_size;j++)
+            {
+               g=best_gain2*shape_cb[best_index2*subvect_size+j];
+               for (k=subvect_size*(i+1)+j,m=0;k<nsf;k++,m++)
+                  tt[k] -= g*r[m];
+            }
+            for (j=subvect_size*i;j<subvect_size*(i+2);j++)
+               err[nbest]-=tt[j]*tt[j];
+            
+            best_score[nbest]=err[nbest];
+         }
+
+         if (best_score[1]>best_score[0])
+         {
+            best_index[0]=best_index[1];
+            best_score[0]=best_score[1];
+            best_gain[0]=best_gain[1];
+            best_gain_ind[0]=best_gain_ind[1];
+         }
+         POP(stack);
+      }
+
+
+      
+
+      ind[i]=best_index[0];
+      gain_ind[i]=best_gain_ind[0];
+      gains[i]=best_gain[0];
+      /* Update target for next subvector */
+      for (j=0;j<subvect_size;j++)
+      {
+         g=best_gain[0]*shape_cb[best_index[0]*subvect_size+j];
+         for (k=subvect_size*i+j,m=0;k<nsf;k++,m++)
+            t[k] -= g*r[m];
+      }
+   }
+   for (i=0;i<nb_subvect;i++)
+   {
+      frame_bits_pack(bits, ind[i], params->shape_bits);
+      if (gains[i]<0)
+         frame_bits_pack(bits, 1, 1);
+      else
+         frame_bits_pack(bits, 0, 1);
+      frame_bits_pack(bits, gain_ind[i], 3);
+      printf ("encode split: %d %d %f\n", i, ind[i], gains[i]);
+
+   }
+   /* Put everything back together */
+   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];
+
+   /* Update excitation */
+   for (j=0;j<nsf;j++)
+      exc[j]+=e[j];
+   
+   /* Update target */
+   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);
@@ -323,7 +710,7 @@ float *stack
    int *ind;
    float *gains;
    float *sign;
-   float *shape_cb;
+   float *shape_cb, exc_energy;
    int shape_cb_size, subvect_size, nb_subvect;
    split_cb_params *params;
 
@@ -337,24 +724,74 @@ float *stack
    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);
+   }
+
+   /* Decode codewords and gains */
    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;
 
-   /*FIXME: Gain quantization changed, need to re-write that part */
-   for (i=0;i<nb_subvect;i++)
-      gains[i]=0;
+      printf ("decode split: %d %d %f\n", i, ind[i], gains[i]);
+   }
 
+   /* Compute decoded excitation */
    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);
+}
+
+
+
+void split_cb_nogain_unquant(
+float *exc,
+void *par,                      /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+float gain,
+FrameBits *bits,
+float *stack
+)
+{
+   int i,j;
+   int *ind;
+   float *shape_cb;
+   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);
+
+   /* Decode codewords and gains */
+   for (i=0;i<nb_subvect;i++)
+      ind[i] = frame_bits_unpack_unsigned(bits, params->shape_bits);
+
+   /* Compute decoded excitation */
+   for (i=0;i<nb_subvect;i++)
+      for (j=0;j<subvect_size;j++)
+         exc[subvect_size*i+j]+=gain*shape_cb[ind[i]*subvect_size+j];
+
    POP(stack);
 }