Exemple #1
0
void azfilter(
              Word16 a[],    /* (i) Q12 : prediction coefficients          */
              Word16 m,      /* (i)     : LPC order                        */
              Word16 x[],    /* (i) Q0  : input signal samples, incl. past */
              Word16 y[],    /* (o) Q0  : filtered output signal           */
              Word16 lg      /* (i)     : size of filtering                */
              )
{
   Word16 i, n;
   Word32 a0;
   Word16 *fp1;

   /* loop through every element of the current vector */
   for (n = 0; n < lg; n++) {
      
      /* perform multiply-adds along the delay line of filter */
      fp1 = x + n;
      a0 = L_mult0(a[0], *fp1--); // Q12
      for (i = 1; i <= m; i++)
         a0 = L_mac0(a0, a[i], *fp1--); // Q12
      
      /* get the output with rounding */
      y[n] = intround(L_shl(a0, 4)); // Q0
   }

   return;
}
Exemple #2
0
/**
 * \brief  31x16 Bit multiply (x*y)
 *
 * \param[i] xh  high part, bit [30..15]
 * \param[i] xl  low part, 15 LSBits
 * \param[i] y
 *
 * \return x*y
 */
Word32 L_multi31x16_X2(Word16 xh, Word16 xl, Word16 y)
{
    Word32 z;

    z = L_shl(L_mult0(xh,y),15);
    z = L_mac0(z,xl,y);

    return z;
}
Exemple #3
0
/****************************************************************************************
 Function:    categorize

 Syntax:      void categorize(Word16 number_of_available_bits,   
                              Word16 number_of_regions,
                              Word16 num_categorization_control_possibilities,
                              Word16 rms_index,                  
                              Word16 power_categories,           
                              Word16 category_balances)          

                  inputs:   number_of_regions
                            num_categorization_control_possibilities
                            number_of_available_bits
                            rms_index[MAX_NUMBER_OF_REGIONS]                              
                  
                  outputs:  power_categories[MAX_NUMBER_OF_REGIONS]                       
                            category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1]

 Description: Computes a series of categorizations 

 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.14      |     0.14
          -------|--------------|----------------  
            MAX  |    0.15      |     0.15
          -------|--------------|---------------- 
   			
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.42      |     0.45       |     0.48   
          -------|--------------|----------------|----------------
            MAX  |    0.47      |     0.52       |     0.52   
          -------|--------------|----------------|----------------

****************************************************************************************/
void categorize(Word16 number_of_available_bits,
		        Word16 number_of_regions,
		        Word16 num_categorization_control_possibilities,
		        Word16 *rms_index,
		        Word16 *power_categories,
		        Word16 *category_balances)
{
    
    Word16 offset;
    Word16 temp;
    Word16 frame_size;

    /* At higher bit rates, there is an increase for most categories in average bit
       consumption per region. We compensate for this by pretending we have fewer
       available bits. */
    test();
    if (number_of_regions == NUMBER_OF_REGIONS)
    {
        frame_size = DCT_LENGTH;
    }
    else
    {
        frame_size = MAX_DCT_LENGTH;
    }

    temp = sub(number_of_available_bits,frame_size);
    
    test();
    if (temp > 0)
    {
        number_of_available_bits = sub(number_of_available_bits,frame_size);
        number_of_available_bits = extract_l(L_mult0(number_of_available_bits,5));
        number_of_available_bits = shr(number_of_available_bits,3);
        number_of_available_bits = add(number_of_available_bits,frame_size);
    }

    /* calculate the offset using the original category assignments */
    offset = calc_offset(rms_index,number_of_regions,number_of_available_bits);



    /* compute the power categories based on the uniform offset */
    compute_raw_pow_categories(power_categories,rms_index,number_of_regions,offset);
    
    
    /* adjust the category assignments */
    /* compute the new power categories and category balances */
    comp_powercat_and_catbalance(power_categories,category_balances,rms_index,number_of_available_bits,number_of_regions,num_categorization_control_possibilities,offset);

}
Exemple #4
0
/***************************************************************************
 Function:    adjust_abs_region_power_index

 Syntax:      adjust_abs_region_power_index(Word16 *absolute_region_power_index,
                                            Word16 *mlt_coefs,
                                            Word16 number_of_regions)

              inputs:   *mlt_coefs
                        *absolute_region_power_index
                        number_of_regions
            
              outputs:  *absolute_region_power_index
 
 Description: Adjusts the absolute power index
 
 
 WMOPS:     7kHz |    24kbit    |      32kbit
          -------|--------------|----------------
            AVG  |    0.03      |      0.03
          -------|--------------|----------------  
            MAX  |    0.12      |      0.12
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.03      |     0.03       |     0.03
          -------|--------------|----------------|----------------
            MAX  |    0.14      |     0.14       |     0.14
          -------|--------------|----------------|----------------

***************************************************************************/
void adjust_abs_region_power_index(Word16 *absolute_region_power_index,Word16 *mlt_coefs,Word16 number_of_regions)
{
    Word16 n,i;
    Word16 region;
    Word16 *raw_mlt_ptr;
    
    Word32 acca;
    Word16 temp;

    for (region=0; region<number_of_regions; region++)
    {
        n = sub(absolute_region_power_index[region],39);
        n = shr_nocheck(n,1);
        
        test();
        if (n > 0)
        {
            temp = extract_l(L_mult0(region,REGION_SIZE));

            raw_mlt_ptr = &mlt_coefs[temp];

            for (i=0; i<REGION_SIZE; i++)
            {
                acca = L_shl_nocheck(*raw_mlt_ptr,16);
                acca = L_add(acca,32768L);
                acca = L_shr_nocheck(acca,n);
                acca = L_shr_nocheck(acca,16);
                *raw_mlt_ptr++ = extract_l(acca);
            }

            temp = shl_nocheck(n,1);
            temp = sub(absolute_region_power_index[region],temp);
            absolute_region_power_index[region] = temp;
            move16();
        }
    }
}
Exemple #5
0
/* Standard Long-Term Postfilter */
void postfilter(
                Word16 *s,   /* input : quantized speech signal         */
                Word16 pp,   /* input : pitch period                    */
                Word16 *ma_a,
                Word16 *b_prv,
                Word16 *pp_prv,
                Word16 *e)   /* output: enhanced speech signal          */
{
   int n;
   Word16 len, t0, t1, t2, t3, shift, aa, R0norm, R0_exp;
   Word32 a0, a1, R0, R1, R01, R01max, Rx;
   Word16 *fp1;
   Word16 ppt, pptmin, pptmax, ppnew;
   Word16 bb[2];
   Word16 R1max_exp, R1max, R01Sqmax_exp, R01Sqmax, R01Sq_exp, R01Sq, R1_exp, R1n;
   Word16 gainn, Rx_exp;
   Word16 buf[MAXPP+FRSZ];
   Word16 *ps, ww1, ww2;
   Word32 step, delta;
   Word16 bi0, bi1c, bi1p;
   
   ps = s+XQOFF;
   
   /********************************************************************/
   /*                 pitch search around decoded pitch                */
   /********************************************************************/
   pptmin = sub(pp, DPPQNS);
   pptmax = add(pp, DPPQNS);
   if (pptmin<MINPP)
   {
      pptmin = MINPP;
      pptmax = add(pptmin, 2*DPPQNS);
   }
   else if (pptmax>MAXPP)
   {
      pptmax = MAXPP;
      pptmin = sub(pptmax, 2*DPPQNS);
   }
   
   fp1 = &s[XQOFF-pptmax];
   len = add(FRSZ, pptmax);
   a0 = 0;
   for (n=0;n<len;n++) 
   {
      t1 = shr(*fp1++, 3);
      a0 = L_mac0(a0,t1,t1);
   }
   shift = norm_l(a0);
   if (a0==0) shift=31;
   shift = sub(6, shift);
   if (shift > 0)
   {
      ps = buf+pptmax;
      fp1 = &s[XQOFF-pptmax];
      shift = shr(add(shift, 1), 1);
      for (n=0;n<len;n++)
      {
         buf[n] = shr(fp1[n], shift);
      }
   }
   else shift=0;
   
   R0  = 0;
   R1  = 0;
   R01 = 0;
   for(n=0; n<FRSZ; n++)
   {
      R0  = L_mac0(R0, ps[n], ps[n]);
      R1  = L_mac0(R1, ps[n-pptmin], ps[n-pptmin]);
      R01 = L_mac0(R01,ps[n], ps[n-pptmin]);
   }
   R0_exp = norm_l(R0);
   R0norm = extract_h(L_shl(R0, R0_exp));
   R0_exp = R0_exp-16;
   
   ppnew        = pptmin;
   R1max_exp    = norm_l(R1);
   R1max        = extract_h(L_shl(R1, R1max_exp));
   R01Sqmax_exp = norm_l(R01);
   t1           = extract_h(L_shl(R01, R01Sqmax_exp));
   R01Sqmax_exp = shl(R01Sqmax_exp, 1);
   R01Sqmax     = extract_h(L_mult(t1, t1));
   R01max       = R01;
   for(ppt=pptmin+1; ppt<=pptmax; ppt++)
   {
      R1 = L_msu0(R1,ps[FRSZ-ppt], ps[FRSZ-ppt]);
      R1 = L_mac0(R1,ps[-ppt], ps[-ppt]);      
      R01= 0;
      for(n=0; n<FRSZ; n++)
      {
         R01 = L_mac0(R01, ps[n], ps[n-ppt]);
      }
      R01Sq_exp = norm_l(R01);
      t1 = extract_h(L_shl(R01, R01Sq_exp));
      R01Sq_exp = shl(R01Sq_exp, 1);
      R01Sq = extract_h(L_mult(t1, t1));
      R1_exp = norm_l(R1);
      R1n = extract_h(L_shl(R1, R1_exp));
      
      a0 = L_mult(R01Sq, R1max);
      a1 = L_mult(R01Sqmax, R1n);
      t1 = add(R01Sq_exp, R1max_exp);
      t2 = add(R01Sqmax_exp, R1_exp);
      
      t2 = sub(t1, t2);
      if (t2>=0) a0 = L_shr(a0, t2);
      if (t2<0)  a1 = L_shl(a1, t2); 
      
      if (L_sub(a0, a1)>0) 
      {
         R01Sqmax = R01Sq; 
         R01Sqmax_exp = R01Sq_exp;
         R1max = R1n; R1max_exp = R1_exp;
         ppnew = ppt;
         R01max = R01;
      }
   }
   
   /******************************************************************/
   /*               calculate all-zero pitch postfilter              */
   /******************************************************************/
   if (R1max==0 || R0==0 || R01max <= 0)
   {
      aa = 0;
   }
   else
   {
      a0 = R1max_exp-16;
      t1 = mult(R1max, R0norm);
      a0 = a0+R0_exp-15;
      sqrt_i(t1, (Word16)a0, &t1, &t2);
      t0 = norm_l(R01max);
      t3 = extract_h(L_shl(R01max, t0));
      t0 = t0-16;
      aa = mult(t3, t1);
      t0 = t0+t2-15;
      t0 = t0-15;
      if (t0<0) aa = shl(aa, sub(0,t0));
      else aa = shr(aa, t0);
   }
   a0 = L_mult(8192, aa);
   a0 = L_mac(a0, 24576, *ma_a);
   *ma_a = intround(a0);
   if((*ma_a < ATHLD1) && (aa < (ATHLD2)))
      aa = 0;
   bb[1] = mult(ScLTPF, aa);
   
   /******************************************************************/
   /*             calculate normalization energies                   */
   /******************************************************************/
   Rx = 0;
   R0 = 0;
   for(n=0; n<FRSZ; n++)
   {
      a0   = L_shl(s[XQOFF+n], 15);
      a0   = L_add(a0, L_mult0(bb[1], s[XQOFF+n-ppnew]));
      e[n] = intround(a0);
      t1   = shr(e[n], shift);
      t2   = shr(s[XQOFF+n], shift);
      Rx   = L_mac0(Rx, t1, t1);
      R0   = L_mac0(R0, t2, t2);
   }
   R0 = L_shr(R0, 2);
   if(R0 == 0 || Rx == 0)
      gainn = 32767;
   else
   {
      Rx_exp = norm_l(Rx);
      t1 = extract_h(L_shl(Rx, Rx_exp));
      t2 = extract_h(L_shl(R0, Rx_exp));
      if (t2>= t1)
         gainn = 32767;
      else
      {
         t1 = div_s(t2, t1);
         gainn = sqrts(t1);
      }
   }
   
   /******************************************************************/
   /*    interpolate from the previous postfilter to the current     */
   /******************************************************************/
   bb[0] = gainn;
   bb[1] = mult(gainn, bb[1]);
   step  = (Word32)((1.0/(NINT+1))*(2147483648.0));
   delta = 0;
   for(n=0; n<NINT; n++)
   {
      delta = L_add(delta, step);
      ww1   = intround(delta);
      ww2   = add(sub(32767, ww1), 1);
      /* interpolate between two filters */
      bi0 = intround(L_mac(L_mult(ww1, bb[0]), ww2, b_prv[0]));
      bi1c= mult(ww1, bb[1]);
      bi1p= mult(ww2, b_prv[1]);
      e[n] = intround(L_mac(L_mac(L_mult(bi1c, s[XQOFF+n-ppnew]), bi1p, s[XQOFF+n-(*pp_prv)]), bi0, s[XQOFF+n]));
   }
   for(n=NINT; n<FRSZ; n++)
   {
      e[n] = intround(L_shl(L_mult(gainn, e[n]),1));
   }
   
   /******************************************************************/
   /*                       save state memory                        */
   /******************************************************************/
   *pp_prv = ppnew;
   b_prv[0] = bb[0];
   b_prv[1] = bb[1];
   
   return;
}
Exemple #6
0
void vector_quantize_mlts(Word16 number_of_available_bits,
                          Word16 number_of_regions,
                          Word16 num_categorization_control_possibilities,
                          Word16 *mlt_coefs,
                          Word16 *absolute_region_power_index,
                          Word16 *power_categories,
                          Word16 *category_balances,
                          Word16 *p_categorization_control,
                          Word16 *region_mlt_bit_counts,
                          UWord32 *region_mlt_bits)
{

    Word16 *raw_mlt_ptr;
    Word16 region;
    Word16 category;
    Word16 total_mlt_bits = 0;

    Word16 temp;
    Word16 temp1;
    Word16 temp2;

    /* Start in the middle of the categorization control range. */
    temp = shr_nocheck(num_categorization_control_possibilities,1);
    temp = sub(temp,1);
    for (*p_categorization_control = 0; *p_categorization_control < temp; (*p_categorization_control)++)
    {
        region = category_balances[*p_categorization_control];
        move16();
        power_categories[region] = add(power_categories[region],1);
        move16();
    }

    for (region=0; region<number_of_regions; region++)
    {
        category = power_categories[region];
        move16();
        temp = extract_l(L_mult0(region,REGION_SIZE));
        raw_mlt_ptr = &mlt_coefs[temp];
        move16();
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
            vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl_nocheck(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
    }


    /* If too few bits... */
    temp = sub(total_mlt_bits,number_of_available_bits);
    test();
    test();
    logic16();
    while ((temp < 0) && (*p_categorization_control > 0))
    {
        test();
        test();
        logic16();
        (*p_categorization_control)--;
        region = category_balances[*p_categorization_control];
        move16();
        
        power_categories[region] = sub(power_categories[region],1);
        move16();

        total_mlt_bits = sub(total_mlt_bits,region_mlt_bit_counts[region]);
        category = power_categories[region];
        move16();
        
        raw_mlt_ptr = &mlt_coefs[region*REGION_SIZE];
        move16();
        
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
                vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl_nocheck(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
        temp = sub(total_mlt_bits,number_of_available_bits);
    }

    /* If too many bits... */
    /* Set up for while loop test */
    temp1 = sub(total_mlt_bits,number_of_available_bits);
    temp2 = sub(*p_categorization_control,sub(num_categorization_control_possibilities,1));
    test();
    test();
    logic16();
    
    while ((temp1 > 0) && (temp2 < 0))
    {
        /* operations for while contitions */
        test();
        test();
        logic16();
        
        region = category_balances[*p_categorization_control];
        move16();
        
        power_categories[region] = add(power_categories[region],1);
        move16();

        total_mlt_bits = sub(total_mlt_bits,region_mlt_bit_counts[region]);
        category = power_categories[region];
        move16();
        
        temp = extract_l(L_mult0(region,REGION_SIZE));
        raw_mlt_ptr = &mlt_coefs[temp];
        move16();
        
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
                vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl_nocheck(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
        (*p_categorization_control)++;
        
        temp1 = sub(total_mlt_bits,number_of_available_bits);
        temp2 = sub(*p_categorization_control,sub(num_categorization_control_possibilities,1));
    }
}
Exemple #7
0
void a2lsp(
           Word16 pc[],       /* (i) Q12: predictor coefficients */
           Word16 lsp[],      /* (o) Q15: line spectral pairs    */
           Word16 old_lsp[])  /* (i) Q15: old lsp                */
{
   Word16 i, j, exp;
   Word16 fa_man[NAB], fa_exp[NAB], fb_man[NAB], fb_exp[NAB];
   Word16 ta_man[NAB], ta_exp[NAB], tb_man[NAB], tb_exp[NAB];
   Word16 *t_man, *t_exp;
   Word32 a0;
   Word16 nd2, nf, ngrd;
   Word16 xroot, xlow, ylow, ind, xhigh, yhigh, xmid, ymid, dx, dy, dxdy, x, sign;


   /* Find normalization for fa and fb */
   /*   fb[0] = fa[0] = 1.0;                             */
   /*   for (i = 1, j = LPCO; i <= (LPCO/2); i++, j--) { */
   /*      fa[i] = pc[i] + pc[j] - fa[i-1];              */
   /*      fb[i] = pc[i] - pc[j] + fb[i-1];              */
   /*   }                                                */
   fa_man[0] = 16384; 
   fa_exp[0] = 6;       // fa_man[0] in high 16-bits >> fa_exp[0] = 1.0 in Q24 
   fb_man[0] = 16384;
   fb_exp[0] = 6;       // fb_man[0] in high 16-bits >> fb_exp[0] = 1.0 in Q24
   for (i = 1, j = LPCO; i <= (LPCO/2); i++, j--) {
      a0 = L_mult0(pc[i], 4096);     // Q24
      a0 = L_mac0(a0, pc[j], 4096);  // Q24
      a0 = L_sub(a0, L_shr(L_deposit_h(fa_man[i-1]),fa_exp[i-1]));  // Q24
      fa_exp[i] = norm_l(a0);
      fa_man[i] = intround(L_shl(a0, fa_exp[i]));  // Q(8+fb_exp[i])

      a0 = L_mult0(pc[i], 4096);     // Q24
      a0 = L_msu0(a0, pc[j], 4096);  // Q24
      a0 = L_add(a0, L_shr(L_deposit_h(fb_man[i-1]),fb_exp[i-1]));  // Q24
      fb_exp[i] = norm_l(a0);
      fb_man[i] = intround(L_shl(a0, fb_exp[i]));  // Q(8+fb_exp[i])
   }

   nd2 = (LPCO)/2;

   /* ta[] and tb[] in Q(7+exp)               */
   /* ta[0] = fa[nab-1]; ta[i] = 2.0 * fa[j]; */
   /* tb[0] = fb[nab-1]; tb[i] = 2.0 * fb[j]; */
   ta_man[0] = fa_man[NAB-1];
   ta_exp[0] = add(fa_exp[NAB-1], 1);
   tb_man[0] = fb_man[NAB-1];
   tb_exp[0] = add(fb_exp[NAB-1], 1);
   for (i = 1, j = NAB - 2; i < NAB; ++i, --j) {
      ta_man[i] = fa_man[j];
      ta_exp[i] = fa_exp[j];
      tb_man[i] = fb_man[j];
      tb_exp[i] = fb_exp[j];
   }

   nf = 0;
   t_man = ta_man;
   t_exp = ta_exp;
   xroot = 0x7fff;
   ngrd  = 0;
   xlow  = grid[0];  // Q15
   ylow = FNevChebP(xlow, t_man, t_exp, nd2);
   ind = 0;

   /* Root search loop */
   while (ngrd<(Ngrd-1) && nf < LPCO) {
      
      ngrd++;
      xhigh = xlow;
      yhigh = ylow;
      xlow  = grid[ngrd];
      ylow = FNevChebP(xlow, t_man, t_exp, nd2);
      
      if ( L_mult(ylow ,yhigh) <= 0) {
         
         /* Bisections of the interval containing a sign change */
         
         dx = xhigh - xlow;
         for (i = 1; i <= NBIS; ++i) {
            dx = shr(dx, 1);
            xmid = add(xlow, dx);
            ymid = FNevChebP(xmid, t_man, t_exp, nd2);
            if (L_mult(ylow,ymid) <= 0) {
               yhigh = ymid;
               xhigh = xmid;
            } else {
               ylow = ymid;
               xlow = xmid;
            }
         }
         
         /*
         * Linear interpolation in the subinterval with a sign change
         * (take care if yhigh=ylow=0)
         */
         
         dx = sub(xhigh, xlow);
         dy  = sub(ylow, yhigh);
         if (dy != 0) {
            sign = dy;
            dy = abs_s(dy);
            exp = norm_s(dy);
            dy = shl(dy, exp);
            /* The maximum grid distance is 1629 =>                                  */
            /* Maximum dx=1629/2^4=101.8125, i.e. 16384/101.8125=160.92~128 (7 bits) */
            /* However, due to the starting point for the search of a new root,      */
            /* xlow = xroot, 1 more bit of headroom for the division is required.    */
            dxdy = div_s(shl(dx,6), dy); 
            a0 = L_mult(dxdy, ylow);
            a0 = L_shr(a0, sub(6, exp));
            x  = intround(a0);
            if(sign < 0) x = negate(x);
            xmid = add(xlow, x);
         } 
         else {
            xmid = add(xlow, shr(dx,1));
         }
         
         /* acos mapping for New lsp component */
         while (( costable[ind] >= xmid ) && (ind < 63)) ind++;
         ind--;
         a0 = L_mult( sub(xmid, costable[ind]) , acosslope[ind] );
         x  = intround(L_shl(a0, 4));
         lsp[nf] = add(x, shl(ind, 9));
         ++nf;
         
         /* Start the search for the roots of next polynomial at the estimated
         * location of the root just found.  We have to catch the case that the
         * two polynomials have roots at the same place to avoid getting stuck at
         * that root.
         */
         
         if (xmid >= xroot) xmid = xlow - dx;
         xroot = xmid;
         if (t_man == ta_man){
            t_man = tb_man;
            t_exp = tb_exp;
         }
         else{
            t_man = ta_man;
            t_exp = ta_exp;
         }
         xlow = xmid;
         ylow = FNevChebP(xlow, t_man, t_exp, nd2);
         
      }
   }
   
   /* Check if all LSPs are found */
   if( sub(nf, LPCO) < 0)
   {
      W16copy(lsp, old_lsp, LPCO);
   }

   return;
}
Exemple #8
0
Word16  refinepitch(
                    Word16 *x,      /* (i) Q1 */
                    Word16    cpp,
                    Word16 *ppt) /* (o) Q9 */
{
   Word32   a0, a1;
   Word32   cor, energy, cormax, enermax32;        /* Q3 */
   Word16   energymax, energymax_exp, ener, ener_exp;
   Word16   cor2, cor2_exp, cor2max, cor2max_exp;
   Word16   *sp0, *sp1, *sp2, *sp3;
   Word16   *xt;
   Word16   s, t;
   Word16   lb, ub;
   int      pp, i, j;
   
   if (cpp >= MAXPP) cpp = MAXPP-1;
   if (cpp < MINPP)  cpp = MINPP;
   lb = sub((Word16)cpp,DEV); 
   if (lb < MINPP) lb = MINPP; /* lower bound of pitch period search range */
   ub = add((Word16)cpp,DEV);
   /* to avoid selecting HMAXPP as the refined pitch period */
   if (ub >= MAXPP) ub = MAXPP-1;/* lower bound of pitch period search range */
   
   i   = lb;            /* start the search from lower bound       */
   xt  = x+XOFF;   
   sp0 = xt;
   sp1 = xt-i;
   cor = energy = 0;
   for (j=0;j<FRSZ; j++) 
   {
      s = *sp1++;
      t = *sp0++;
      energy = L_mac0(energy, s, s);
      cor    = L_mac0(cor, s, t);
   }
   
   pp             = i;
   cormax         = cor;
   enermax32      = energy;
   energymax_exp  = norm_l(enermax32);
   energymax      = extract_h(L_shl(enermax32, energymax_exp));
   a0             = cor;
   cor2max_exp    = norm_l(a0);
   s              = extract_h(L_shl(a0, cor2max_exp));
   cor2max_exp    = shl(cor2max_exp, 1);
   cor2max        = extract_h(L_mult0(s, s));
   sp0            = xt+FRSZ-lb-1;
   sp1            = xt-lb-1;
   for (i=lb+1;i<=ub;i++) 
   {
      sp2 = xt;
      sp3 = xt-i;
      cor = 0;
      for (j=0;j<FRSZ;j++) 
         cor = L_mac0(cor, *sp2++, *sp3++);
      
      a0       = cor;
      cor2_exp = norm_l(a0);
      s        = extract_h(L_shl(a0, cor2_exp));
      cor2_exp = shl(cor2_exp, 1);
      cor2     = extract_h(L_mult0(s, s));
      
      s        = *sp0--;
      t        = *sp1--;
      energy   = L_msu0(energy, s, s);
      energy   = L_mac0(energy, t, t);
      a0       = energy;
      ener_exp = norm_l(a0);
      ener     = extract_h(L_shl(a0, ener_exp));
      
      if (ener>0) 
      {   
         a0 = L_mult0(cor2, energymax);
         a1 = L_mult0(cor2max, ener);
         s  = add(cor2_exp, energymax_exp);
         t  = add(cor2max_exp, ener_exp);
         if (s>=t) a0 = L_shr(a0, sub(s,t));
         else      a1 = L_shr(a1, sub(t,s));
         if (a0 > a1) 
         {
            pp             = i;
            cormax         = cor;
            enermax32      = energy;   
            cor2max        = cor2; 
            cor2max_exp    = cor2_exp;
            energymax      = ener; 
            energymax_exp  = ener_exp;
         }
      }
   }
   
   if ((enermax32 == 0) || (cormax<=0)) 
      *ppt = 0;
   else 
   {
      ub    = sub(norm_l(cormax),1);
      lb    = norm_l(enermax32);
      s     = extract_h(L_shl(cormax,ub));
      t     = extract_h(L_shl(enermax32,lb));
      s     = div_s(s, t);
      lb    = sub(sub(lb,ub),6);
      *ppt  = shl(s, lb);
   }
   return pp;
}