斗龙战士2百诺被打屁股:MP3详解-程序中子函数代码详析(2)

来源:百度文库 编辑:中财网 时间:2024/05/04 08:52:44

3:函数read_decoder_table分析

int read_decoder_table(FILE *fi)

{

该函数的作用是将34个供解码的数值存入了变量ht[n].val中,以方便以后的解码调用

//HTN=34

        int n,i,nn,t;

    unsigned int v0,v1;

        char command[100],line[100];

        for (n=0;n

    要进行34次循环因为有34个子表

        /* .table number treelen xlen ylen linbits */

        do {

        fgets(line,99,fi);

从解码树表文件fi中读入98个字符然后在最后加“/0”组成字符窜存入树组line中,但是如果碰到回车则马上停止读入。

        } while ((line[0] == '#') || (line[0] < ' '));

因为文件huffdec.txt中一行就有一个回车,所以往往取不到98个字符,就碰到了回车。

文件huffdec.txt中开始的部分是一些无用的说明部分是用#作为开头的,上面的这个循环就是为了去除无效行,直到取出一行有效行后进行下面的操作:

        sscanf(line,"%s %s %u %u %u %u",command,ht[n].tablename,

           &ht[n].treelen, &ht[n].xlen, &ht[n].ylen, &ht[n].linbits);

从一个字符串中读进与指定格式相符的数据存入相应的变量,即取出子表头信息,子表头信息包含表名,解码树长,x长,y长,和linbits这些参量。在这里的含义就是将.table  0   0  0  0  0中的.table存入command,0存入ht[n].tablename,...

        if (strcmp(command,".end")==0)

判断两个字符串

        return n;

    如果command==.end说明已经循环完了34次,已经到了文件尾了,所以返回就可以了

        else if (strcmp(command,".table")!=0) {

        fprintf(stderr,"huffman table %u data corrupted\n",n);

        return -1;

    }

    如果command!=.end&&!=.table报错

        ht[n].linmax = (1<

   计算出linmax参量(什么用处?)

        do {

        fgets(line,99,fi);

        } while ((line[0] == '#') || (line[0] < ' '));

    取出子表中第2行有效行

        sscanf(line,"%s %u",command,&t);

    取出该有效行中的有效参数

        if (strcmp(command,".reference")==0) {

        ht[n].ref   = t;

        ht[n].val   = ht[t].val;

        ht[n].treelen  = ht[t].treelen;

        if ( (ht[n].xlen != ht[t].xlen) ||

           (ht[n].ylen != ht[t].ylen)  ) {

        fprintf(stderr,"wrong table %u reference\n",n);

        return (-3);

        };

      while ((line[0] == '#') || (line[0] < ' ') ) {

        fgets(line,99,fi);

        }

    }   

    文件中ht[n].ref的存在只是为了减小解码表的容量,但是增加了解码程序的代码长度

        else if (strcmp(command,".treedata")==0) {

        ht[n].ref  = -1;

        ht[n].val = (unsigned char (*)[2])

        calloc(2*(ht[n].treelen),sizeof(unsigned char));

        位变量val动态分配内存空间

         if ((ht[n].val == NULL) && ( ht[n].treelen != 0 )){

        fprintf(stderr, "heaperror at table %d\n",n);

        exit (-10);

         }

         for (i=0;i

        fscanf(fi,"%x %x",&v0, &v1);

        ht[n].val[i][0]=(unsigned char)v0;

        ht[n].val[i][1]=(unsigned char)v1;

        }

    将34个供解码的数值存入了变量ht[n].val中

        fgets(line,99,fi); /* read the rest of the line */

       }

        else {

        fprintf(stderr,"huffman decodertable error at table %d\n",n);

        }

        }

        return n;

}

4:函数huffman_decoder分析

int huffman_decoder(struct huffcodetab *h, int *x, int *y, int *v, int *w)

{

参数说明这个函数需要一个指向相应霍夫曼表的结构体指针,根据霍夫曼解码表来查表解码,解码出来的数据先存到x,y,v,w上,然后在函数外,将值存入变量is中。本身这里的程序语句不难理解,前提是对霍夫曼查表法解码由足够的了解。往下的部分就不再作程序本身的介绍。只简单的了解数据的流程就可以了,这里数据是从全局buf中一个比特一个比特的取出,根据霍夫曼解码方法,通过对比表格,得到相应的解码后的数据。前面已经介绍了,为了方便霍夫曼解码,数据分了3个大区,其中大值区还分为3个小区。不同区里的比特选用的解码表不一样,解码出来的数据个数也是不一样的。具体实现方法还没有彻底弄通呢。

  HUFFBITS level;

  在前面的文件里面已经定义了#define HUFFBITS unsigned long int

  还定义了HUFFBITS dmask = 1 << (sizeof(HUFFBITS)*8-1);

  int point = 0;

  int error = 1;

  level     = dmask;

  if (h->val == NULL) return 2;

  /* table 0 needs no bits */

  if ( h->treelen == 0)

  {  *x = *y = 0;

     return 0;

  }

  /* Lookup in Huffman table. */

  以下开始霍夫曼的查表法解码,即在解码表中查找对应的解码数据

  do {

    if (h->val[point][0]==0) {   /*end of tree*/

      *x = h->val[point][1] >> 4;

      *y = h->val[point][1] & 0xf;

在数据组织形式上val是一对出现的val[point][0]表示val中第[point]对中的第一个数据

如果第point对val中的第一个数据是0的话,那么x,y根据上式确定

      error = 0;

      break;

    }

    if (hget1bit()) {

      while (h->val[point][1] >= MXOFF) point += h->val[point][1];

      point += h->val[point][1];

    }

    else {

        while (h->val[point][0] >= MXOFF) point += h->val[point][0];

      point += h->val[point][0];

    }

    level >>= 1;

  } while (level  || (point < ht->treelen) );

 

  /* Check for error. */

 

  if (error) { /* set x and y to a medium value as a simple concealment */

    printf("Illegal Huffman code in data.\n");

    *x = (h->xlen-1 << 1);

    *y = (h->ylen-1 << 1);

  }

 

  /* Process sign encodings for quadruples tables. */

 

  if (h->tablename[0] == '3'

      && (h->tablename[1] == '2' || h->tablename[1] == '3')) {

     *v = (*y>>3) & 1;

     *w = (*y>>2) & 1;

     *x = (*y>>1) & 1;

     *y = *y & 1;

 

     /* v, w, x and y are reversed in the bitstream.

        switch them around to make test bistream work. */

    

/*   {int i=*v; *v=*y; *y=i; i=*w; *w=*x; *x=i;}  MI */

 

     if (*v)

        if (hget1bit() == 1) *v = -*v;

     if (*w)

        if (hget1bit() == 1) *w = -*w;

     if (*x)

        if (hget1bit() == 1) *x = -*x;

     if (*y)

        if (hget1bit() == 1) *y = -*y;

     }

    

  /* Process sign and escape encodings for dual tables. */

 

  else {

 

      /* x and y are reversed in the test bitstream.

         Reverse x and y here to make test bitstream work. */

     

/*    removed 11/11/92 -ag 

        {int i=*x; *x=*y; *y=i;}

*/     

     if (h->linbits)

       if ((h->xlen-1) == *x)

         *x += hgetbits(h->linbits);

     if (*x)

        if (hget1bit() == 1) *x = -*x;

     if (h->linbits)     

       if ((h->ylen-1) == *y)

         *y += hgetbits(h->linbits);

     if (*y)

        if (hget1bit() == 1) *y = -*y;

     }

     

  return error; 

}

反量化函数分析

 

void III_dequantize_sample(long int is[SBLIMIT][SSLIMIT], double xr[SBLIMIT][SSLIMIT], III_scalefac_t *scalefac, struct gr_info_s *gr_info, int ch, frame_params *fr_ps)

{

    参数说明:is是该函数的解码对象,解码后存入xr,需要比例因子结构体,边信息结构体,以及帧信息

    int ss,sb,cb=0,sfreq=fr_ps->header->sampling_frequency;

    int stereo = fr_ps->stereo;

    int next_cb_boundary, cb_begin, cb_width, sign;

 

    /* choose correct scalefactor band per block type, initalize boundary */

反量化也是以颗粒为单位进行的,霍夫曼解码后的数据还是以颗粒为组织形式

    if (gr_info->window_switching_flag && (gr_info->block_type == 2) )

        if (gr_info->mixed_block_flag)

            如果该颗粒是短块并且是混合型的短块则next_cb_boundary有下面的公式确定

            next_cb_boundary=sfBandIndex[sfreq].l[1];  /* LONG blocks: 0,1,3 */

        else {

            如果是非混合型的短块那么需要的一些解码系数确定如下:

            next_cb_boundary=sfBandIndex[sfreq].s[1]*3; /* pure SHORT block */

            cb_width = sfBandIndex[sfreq].s[1];

            cb_begin = 0;

        }

    else

        如果是长块,那么系数确定如下

        next_cb_boundary=sfBandIndex[sfreq].l[1];  /* LONG blocks: 0,1,3 */

系数确定后则可以进行解码操作:反量化操作就是一个公式计算过程:

    以下便是对SBLIMIT*SSLIMIT即32*18=576个数据的依次反量化计算;

    遵循的公式是xr[sb][ss] = pow( 2.0 , (0.25 * (gr_info->global_gain - 210.0)));

    /* apply formula per block type */

    for (sb=0 ; sb < SBLIMIT ; sb++) {

        for (ss=0 ; ss < SSLIMIT ; ss++) {

            if ( (sb*18)+ss == next_cb_boundary)

                当要解码的数据位置正好落在边界的时候要作适当的调整

                ???这个所谓的边界是什么的边界???

            { /* Adjust critical band boundary */

                if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {

                    if (gr_info->mixed_block_flag) {

                       

                        if (((sb*18)+ss) == sfBandIndex[sfreq].l[8])  {

                            如果这个颗粒是混合型的短块并且数据的位置还与sfBandIndex[sfreq].l[8])相同

                            那么要对next_cb_boundary等系数重新调整

                            next_cb_boundary=sfBandIndex[sfreq].s[4]*3;

                            cb = 3;

                            cb_width = sfBandIndex[sfreq].s[cb+1] -

                                        sfBandIndex[sfreq].s[cb];

                            cb_begin = sfBandIndex[sfreq].s[cb]*3;

                        }

                        else if (((sb*18)+ss) < sfBandIndex[sfreq].l[8])

                            如果这个颗粒是混合型的短块并且数据的位置还小于sfBandIndex[sfreq].l[8])

                            那么要对next_cb_boundary等系数重新另一种调整如下

                            next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];

                        else {

                            如果这个颗粒是混合型的短块并且数据的位置还大于sfBandIndex[sfreq].l[8])

                            那么要对next_cb_boundary等系数重新第三种调整如下

                            next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1]*3;

                            cb_width = sfBandIndex[sfreq].s[cb+1] -

                                        sfBandIndex[sfreq].s[cb];

                            cb_begin = sfBandIndex[sfreq].s[cb]*3;

                        }

                    }

                    else {

                        如果是非混合型的短块,进行这样的调整:

                        next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1]*3;

                        cb_width = sfBandIndex[sfreq].s[cb+1] -

                                    sfBandIndex[sfreq].s[cb];

                        cb_begin = sfBandIndex[sfreq].s[cb]*3;

                    }

                }

                else /* long blocks */

                    长块的话进行如下的调整:

                    ??调整的意义是什么???

                   next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];

            }

 

            /* Compute overall (global) scaling. */

            xr[sb][ss] = pow( 2.0 , (0.25 * (gr_info->global_gain - 210.0)));

 

            /* Do long/short dependent scaling operations. */

 

            if (gr_info->window_switching_flag && (

                ((gr_info->block_type == 2) && (gr_info->mixed_block_flag == 0)) ||

                ((gr_info->block_type == 2) && gr_info->mixed_block_flag && (sb >= 2)) )) {

                如果是一个非混合型的短块,或者是混合型的短块且(sb >= 2)

                xr[sb][ss] *= pow(2.0, 0.25 * -8.0 *

                        gr_info->subblock_gain[(((sb*18)+ss) - cb_begin)/cb_width]);

                xr[sb][ss] *= pow(2.0, 0.25 * -2.0 * (1.0+gr_info->scalefac_scale)

                        * (*scalefac)[ch].s[(((sb*18)+ss) - cb_begin)/cb_width][cb]);

            }

            else {   /* LONG block types 0,1,3 & 1st 2 subbands of switched blocks */

                xr[sb][ss] *= pow(2.0, -0.5 * (1.0+gr_info->scalefac_scale)

                                * ((*scalefac)[ch].l[cb]

                                + gr_info->preflag * pretab[cb]));

            }

 

            /* Scale quantized value. */

 

            sign = (is[sb][ss]<0) ? 1 : 0;

            xr[sb][ss] *= pow( (double) abs(is[sb][ss]), ((double)4.0/3.0) );

            if (sign) xr[sb][ss] = -xr[sb][ss];

        }

    }

}

立体声处理函数分析

void III_stereo(double xr[2][SBLIMIT][SSLIMIT], double lr[2][SBLIMIT][SSLIMIT], III_scalefac_t *scalefac, struct gr_info_s *gr_info, frame_params *fr_ps)

{  参数说明:操作对象是反量化后的存在xr的数据,结果存放在lr,需要比例因子结构体,颗粒信息结构体,帧结构体

  

   int sfreq = fr_ps->header->sampling_frequency;

   int stereo = fr_ps->stereo;

   int ms_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&

                   (fr_ps->header->mode_ext & 0x2);

   int i_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&

                  (fr_ps->header->mode_ext & 0x1);

   int sfb;

   int i,j,sb,ss,ch,is_pos[576];

   double is_ratio[576];

 

   /* intialization */

   立体声处理前的初始化工作:让is_pos[i]=0111B

   Joint Stereo 是一种立体声编码技巧,主要分为 Intensity Stereo(IS)

   和 Mid/Side (M/S) stereo 两种。 IS 的是在比较低流量时使用,利用

   了人耳对于低频讯号指向性分辨能力的不足,将音讯资料中的低频分解出

   来合成单声道资料,剩余的高频资料则合成另一个单声道资料,并另外纪录

   高频资料的位置资讯,来重建立体声的效果。例如钢琴独奏的录音就可以利用

   这种方法在有限的资料流量中减少音场资讯却大幅增加音色资讯。

   Mid/Side (M/S) stereo 在左右声道资料相似度大时常被用到,纪录方式是

   将左右声道音讯合并 (L+R) 得到新的一轨,再将左右声道音讯相减 (L-R) 得到

   另外一轨,然后再将这两轨资料用上面提到听觉心理学模型与滤波器处理。

   Mid/Side (M/S) stereo 与 IS 一样的是利用部分相位 (phase) 资讯的损失

   来换得较高的音色纪录资讯。一般的 MP3 是 Mid/Side stereo 和 Intensity Stereo 交替使用的

      is_pos[i] = 7;

 

   if ((stereo == 2) && i_stereo )

   这里主要要操作的是改变is_pos[i]如果is_pos[i]始终是初始化时的值7,那么立体声处理的时候

   将没有办法进行模式i_stereo的解码。因为i_stereo的解码要将音讯资料中的低频分解出

   来合成单声道资料,剩余的高频资料则合成另一个单声道资料,所以得弄清什么时候数据是

   低频的,什么时候是高频的以下的代码完成的就是这一识别工作is_ratio[i]从而产生需要的系数

   {  if (gr_info->window_switching_flag && (gr_info->block_type == 2))

      {  if( gr_info->mixed_block_flag )

        如果该帧是立体声的,并且是属于i_stereo模式的立体声并且该颗粒是混合型的短块

        那么参数max_sfb先得到确定为0

         {  int max_sfb = 0;

                       

            for ( j=0; j<3; j++ )

            {  int sfbcnt;

               sfbcnt = 2;

               sfbcnt的作用是什么?

               for( sfb=12; sfb >=3; sfb-- )

               {下面的操作进行30次 

               int lines;

               可能表征频带宽度

                  lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];

                  注意:这样一减最小的结果也是4

                  i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;

                  这样计算i最小的结果也是3

                  while ( lines > 0 )

                 

                  {  if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )

                    如果反量化的结果不是0,是0的话就不用进行立体声处理了

                    选择参数sfb=-10,lines=-10

                     {  sfbcnt = sfb;

                        sfb = -10;

                        lines = -10;

                     }

                     lines--;

                     i--;

                  }

               }

               sfb = sfbcnt + 1;

 

               if ( sfb > max_sfb )

                  max_sfb = sfb;

 

               while( sfb<12 )

               {  sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];

                  i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;

                  for ( ; sb > 0; sb--)

                  {  is_pos[i] = (*scalefac)[1].s[j][sfb];

                     if ( is_pos[i] != 7 )

                        is_ratio[i] = tan( is_pos[i] * (PI / 12));

                     i++;

                  }

                  sfb++;

               }

               sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];

               sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;

               sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];

               i = 3*sfBandIndex[sfreq].s[11] + j * sb;

               for ( ; sb > 0; sb-- )

               {  is_pos[i] = is_pos[sfb];

                  is_ratio[i] = is_ratio[sfb];

                  i++;

               }

             }

             if ( max_sfb <= 3 )

             {  i = 2;

                ss = 17;

                sb = -1;

                while ( i >= 0 )

                {  if ( xr[1][i][ss] != 0.0 )

                   {  sb = i*18+ss;

                      i = -1;

                   } else

                   {  ss--;

                      if ( ss < 0 )

                      {  i--;

                         ss = 17;

                      }

                   }

                }

                i = 0;

                while ( sfBandIndex[sfreq].l[i] <= sb )

                   i++;

                sfb = i;

                i = sfBandIndex[sfreq].l[i];

                for ( ; sfb<8; sfb++ )

                {  sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb];

                   for ( ; sb > 0; sb--)

                   {  is_pos[i] = (*scalefac)[1].l[sfb];

                      if ( is_pos[i] != 7 )

                         is_ratio[i] = tan( is_pos[i] * (PI / 12));

                      i++;

                   }

                }

            }

         } else

        如果该帧是立体声的,并且是属于i_stereo模式的立体声并且该颗粒是非混合型的短块  

         {  for ( j=0; j<3; j++ )

            {  int sfbcnt;

               sfbcnt = -1;

               for( sfb=12; sfb >=0; sfb-- )

               {  int lines;

                  lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];

                  i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;

                  while ( lines > 0 )

                  {  if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )

                     {  sfbcnt = sfb;

                        sfb = -10;

                        lines = -10;

                     }

                     lines--;

                     i--;

                  }

               }

               sfb = sfbcnt + 1;

               while( sfb<12 )

               {  sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];

                  i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;

                  for ( ; sb > 0; sb--)

                  {  is_pos[i] = (*scalefac)[1].s[j][sfb];

                     if ( is_pos[i] != 7 )

                        is_ratio[i] = tan( is_pos[i] * (PI / 12));

                     i++;

                  }

                  sfb++;

               }

 

               sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];

               sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;

               sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];

               i = 3*sfBandIndex[sfreq].s[11] + j * sb;

               for ( ; sb > 0; sb-- )

               {  is_pos[i] = is_pos[sfb];

                  is_ratio[i] = is_ratio[sfb];

                  i++;

               }

            }

         }

      } else

      {  i = 31;

         ss = 17;

         sb = 0;

         while ( i >= 0 )

         {  if ( xr[1][i][ss] != 0.0 )

            {  sb = i*18+ss;

               i = -1;

            } else

            {  ss--;

               if ( ss < 0 )

               {  i--;

                  ss = 17;

               }

            }

         }

         i = 0;

         while ( sfBandIndex[sfreq].l[i] <= sb )

            i++;

         sfb = i;

         i = sfBandIndex[sfreq].l[i];

         for ( ; sfb<21; sfb++ )

         {  sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb];

            for ( ; sb > 0; sb--)

            {  is_pos[i] = (*scalefac)[1].l[sfb];

               if ( is_pos[i] != 7 )

                  is_ratio[i] = tan( is_pos[i] * (PI / 12));

               i++;

            }

         }

         sfb = sfBandIndex[sfreq].l[20];

         for ( sb = 576 - sfBandIndex[sfreq].l[21]; sb > 0; sb-- )

         {  is_pos[i] = is_pos[sfb];

            is_ratio[i] = is_ratio[sfb];

            i++;

         }

      }

   }

 

   for(ch=0;ch<2;ch++)

      for(sb=0;sb

         for(ss=0;ss

            lr[ch][sb][ss] = 0;

 

   if (stereo==2)

      for(sb=0;sb

         for(ss=0;ss

            i = (sb*18)+ss;

            if ( is_pos[i] == 7 ) {

               if ( ms_stereo ) {

                  lr[0][sb][ss] = (xr[0][sb][ss]+xr[1][sb][ss])/1.41421356;

                  lr[1][sb][ss] = (xr[0][sb][ss]-xr[1][sb][ss])/1.41421356;

               }

               else {

                  lr[0][sb][ss] = xr[0][sb][ss];

                  lr[1][sb][ss] = xr[1][sb][ss];

               }

            }

            else if (i_stereo ) {

               lr[0][sb][ss] = xr[0][sb][ss] * (is_ratio[i]/(1+is_ratio[i]));

               lr[1][sb][ss] = xr[0][sb][ss] * (1/(1+is_ratio[i]));

            }

            else {

               printf("Error in streo processing\n");

            }

         }

   else  /* mono , bypass xr[0][][] to lr[0][][]*/

      for(sb=0;sb

         for(ss=0;ss

            lr[0][sb][ss] = xr[0][sb][ss];

 

}

数据重排列函数分析

void III_reorder(double xr[SBLIMIT][SSLIMIT], double ro[SBLIMIT][SSLIMIT], struct gr_info_s *gr_info, frame_params *fr_ps)

{   排列前的数据位置xr,排列后要存放的位置ro,需要颗粒结构体,和帧结构体

   int sfreq=fr_ps->header->sampling_frequency;

   int sfb, sfb_start, sfb_lines;

   int sb, ss, window, freq, src_line, des_line;

 

   for(sb=0;sb

      for(ss=0;ss

         ro[sb][ss] = 0;

 

   if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {

      if (gr_info->mixed_block_flag) {

         /* NO REORDER FOR LOW 2 SUBBANDS */

         for (sb=0 ; sb < 2 ; sb++)

            for (ss=0 ; ss < SSLIMIT ; ss++) {

               ro[sb][ss] = xr[sb][ss];

            }

            在最下面的两个子带中数据的排列不需要变化

            其它的子带要根据协议内容来变化

         /* REORDERING FOR REST SWITCHED SHORT */

         for(sfb=3,sfb_start=sfBandIndex[sfreq].s[3],

            sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start;

            sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],

            (sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))

               for(window=0; window<3; window++)

                  for(freq=0;freq

                     src_line = sfb_start*3 + window*sfb_lines + freq;

                     des_line = (sfb_start*3) + window + (freq*3);

                     ro[des_line/SSLIMIT][des_line%SSLIMIT] =

                                    xr[src_line/SSLIMIT][src_line%SSLIMIT];

               }

      }

      else {  /* pure short */

         for(sfb=0,sfb_start=0,sfb_lines=sfBandIndex[sfreq].s[1];

            sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],

            (sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))

               for(window=0; window<3; window++)

                  for(freq=0;freq

                     src_line = sfb_start*3 + window*sfb_lines + freq;

                     des_line = (sfb_start*3) + window + (freq*3);

                     ro[des_line/SSLIMIT][des_line%SSLIMIT] =

                                    xr[src_line/SSLIMIT][src_line%SSLIMIT];

               }

      }

   }

   else {   /*long blocks */

      for (sb=0 ; sb < SBLIMIT ; sb++)

         for (ss=0 ; ss < SSLIMIT ; ss++)

            ro[sb][ss] = xr[sb][ss];

   }}