Home | History | Annotate | Download | only in src
      1 /*
      2  ** Copyright 2003-2010, VisualOn, Inc.
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 /*******************************************************************************
     17 	File:		adj_thr.c
     18 
     19 	Content:	Threshold compensation functions
     20 
     21 *******************************************************************************/
     22 
     23 /* Include system headers before local headers - the local headers
     24  * redefine __inline, which can mess up definitions in libc headers if
     25  * they happen to use __inline. */
     26 #include <string.h>
     27 #include "basic_op.h"
     28 #include "oper_32b.h"
     29 #include "adj_thr_data.h"
     30 #include "adj_thr.h"
     31 #include "qc_data.h"
     32 #include "line_pe.h"
     33 
     34 
     35 #define  minSnrLimit    0x6666 /* 1 dB */
     36 #define  PEBITS_COEF	0x170a /* 0.18*(1 << 15)*/
     37 
     38 #define  HOLE_THR_LONG	0x2873	/* 0.316*(1 << 15) */
     39 #define  HOLE_THR_SHORT 0x4000  /* 0.5  *(1 << 15) */
     40 
     41 #define  MS_THRSPREAD_COEF 0x7333  /* 0.9 * (1 << 15) */
     42 
     43 #define	 MIN_SNR_COEF	   0x651f  /* 3.16* (1 << (15 - 2)) */
     44 
     45 /* values for avoid hole flag */
     46 enum _avoid_hole_state {
     47   NO_AH              =0,
     48   AH_INACTIVE        =1,
     49   AH_ACTIVE          =2
     50 };
     51 
     52 /********************************************************************************
     53 *
     54 * function name:bits2pe
     55 * description: convert from bits to pe
     56 *			   pe = 1.18*desiredBits
     57 *
     58 **********************************************************************************/
     59 Word16 bits2pe(const Word16 bits) {
     60   return (bits + ((PEBITS_COEF * bits) >> 15));
     61 }
     62 
     63 /********************************************************************************
     64 *
     65 * function name:calcThreshExp
     66 * description: loudness calculation (threshold to the power of redExp)
     67 *			   thr(n)^0.25
     68 *
     69 **********************************************************************************/
     70 static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
     71                           PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
     72                           const Word16 nChannels)
     73 {
     74   Word16 ch, sfb, sfbGrp;
     75   Word32 *pthrExp, *psfbThre;
     76   for (ch=0; ch<nChannels; ch++) {
     77     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
     78 	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
     79 	  pthrExp = &(thrExp[ch][sfbGrp]);
     80 	  psfbThre = psyOutChan->sfbThreshold + sfbGrp;
     81 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
     82 		*pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
     83 		pthrExp++; psfbThre++;
     84       }
     85   }
     86 }
     87 
     88 /********************************************************************************
     89 *
     90 * function name:adaptMinSnr
     91 * description: reduce minSnr requirements for bands with relative low energies
     92 *
     93 **********************************************************************************/
     94 static void adaptMinSnr(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
     95                         Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
     96                         MINSNR_ADAPT_PARAM *msaParam,
     97                         const Word16        nChannels)
     98 {
     99   Word16 ch, sfb, sfbOffs, shift;
    100   Word32 nSfb, avgEn;
    101   Word16 log_avgEn = 0;
    102   Word32 startRatio_x_avgEn = 0;
    103 
    104 
    105   for (ch=0; ch<nChannels; ch++) {
    106     PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
    107 
    108     /* calc average energy per scalefactor band */
    109     avgEn = 0;
    110     nSfb = 0;
    111     for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
    112       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    113         avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
    114         nSfb = nSfb + 1;
    115       }
    116     }
    117 
    118     if (nSfb > 0) {
    119 	  avgEn = avgEn / nSfb;
    120 
    121       log_avgEn = iLog4(avgEn);
    122       startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
    123     }
    124 
    125 
    126     /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
    127     for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
    128       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    129         if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
    130           Word16 dbRatio, minSnrRed;
    131           Word32 snrRed;
    132           Word16 newMinSnr;
    133 
    134           dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
    135           dbRatio = dbRatio + (dbRatio << 1);
    136 
    137           minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
    138           minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
    139                                                3: 0.00375(redRatioFac)*80
    140                                                20: 0.25(maxRed) * 80 */
    141 
    142           snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
    143           /*
    144              snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
    145           */
    146 
    147           newMinSnr = round16(pow2_xy(snrRed,80*4));
    148 
    149           psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
    150         }
    151       }
    152     }
    153   }
    154 
    155 }
    156 
    157 
    158 /********************************************************************************
    159 *
    160 * function name:initAvoidHoleFlag
    161 * description: determine bands where avoid hole is not necessary resp. possible
    162 *
    163 **********************************************************************************/
    164 static void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    165                               PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    166                               PSY_OUT_ELEMENT* psyOutElement,
    167                               const Word16 nChannels,
    168                               AH_PARAM *ahParam)
    169 {
    170   Word16 ch, sfb, sfbGrp, shift;
    171   Word32 threshold;
    172   Word32* psfbSpreadEn;
    173 
    174   for (ch=0; ch<nChannels; ch++) {
    175     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    176 
    177     if (psyOutChan->windowSequence != SHORT_WINDOW) {
    178       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    179          psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
    180 		 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    181 			*psfbSpreadEn = *psfbSpreadEn >> 1;  /* 0.5 */
    182 			++psfbSpreadEn;
    183         }
    184       }
    185     }
    186     else {
    187       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    188 		psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
    189         for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    190           *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3);  /* 0.63 */
    191 		  ++psfbSpreadEn;
    192         }
    193       }
    194     }
    195   }
    196 
    197   /* increase minSnr for local peaks, decrease it for valleys */
    198   if (ahParam->modifyMinSnr) {
    199     for(ch=0; ch<nChannels; ch++) {
    200       PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    201 
    202       if (psyOutChan->windowSequence != SHORT_WINDOW)
    203         threshold = HOLE_THR_LONG;
    204       else
    205         threshold = HOLE_THR_SHORT;
    206 
    207       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    208         Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
    209 		for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    210           Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
    211 
    212           if (sfb > 0)
    213             sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
    214           else
    215             sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
    216 
    217           if (sfb < (psyOutChan->maxSfbPerGroup-1))
    218             sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
    219           else
    220             sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
    221           avgEn = (sfbEnm1 + sfbEnp1) >> 1;
    222           sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
    223 
    224           if (sfbEn > avgEn && avgEn > 0) {
    225             Word32 tmpMinSnr;
    226             shift = norm_l(sfbEn);
    227 			tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
    228             tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
    229             tmpMinSnr = max(tmpMinSnr, threshold);
    230             *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
    231           }
    232           /* valley ? */
    233 
    234           if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
    235             Word32 tmpMinSnr;
    236             Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
    237 
    238             if(minSnrEn < sfbEn) {
    239 			  shift = norm_l(sfbEn);
    240               tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
    241             }
    242             else {
    243               tmpMinSnr = MAX_16;
    244             }
    245             tmpMinSnr = min(minSnrLimit, tmpMinSnr);
    246 
    247             *psfbMinSnr =
    248               (min((tmpMinSnr >>  2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
    249           }
    250 		  psfbMinSnr++;
    251         }
    252       }
    253     }
    254   }
    255 
    256   /* stereo: adapt the minimum requirements sfbMinSnr of mid and
    257      side channels */
    258 
    259   if (nChannels == 2) {
    260     PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
    261     PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
    262     for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
    263       if (psyOutElement->toolsInfo.msMask[sfb]) {
    264         Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
    265         Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
    266         Word32 maxSfbEn = max(sfbEnM, sfbEnS);
    267         Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
    268 
    269         if(maxThr >= sfbEnM) {
    270           psyOutChanM->sfbMinSnr[sfb] = MAX_16;
    271         }
    272         else {
    273           shift = norm_l(sfbEnM);
    274 		  psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
    275 			  round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
    276         }
    277 
    278         if(maxThr >= sfbEnS) {
    279           psyOutChanS->sfbMinSnr[sfb] = MAX_16;
    280         }
    281         else {
    282 		  shift = norm_l(sfbEnS);
    283           psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
    284 			  round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
    285         }
    286 
    287 
    288         if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
    289           psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
    290 
    291         if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
    292           psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
    293       }
    294     }
    295   }
    296 
    297 
    298   /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
    299   for(ch=0; ch<nChannels; ch++) {
    300     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    301     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    302       Word16 *pahFlag = ahFlag[ch] + sfbGrp;
    303 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    304 
    305         if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
    306             (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
    307             (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
    308           *pahFlag++ = NO_AH;
    309         }
    310         else {
    311           *pahFlag++ = AH_INACTIVE;
    312         }
    313       }
    314       for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
    315         *pahFlag++ = NO_AH;
    316       }
    317     }
    318   }
    319 }
    320 
    321 /********************************************************************************
    322 *
    323 * function name:calcPeNoAH
    324 * description: sum the pe data only for bands where avoid hole is inactive
    325 *
    326 **********************************************************************************/
    327 static void calcPeNoAH(Word16          *pe,
    328                        Word16          *constPart,
    329                        Word16          *nActiveLines,
    330                        PE_DATA         *peData,
    331                        Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    332                        PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    333                        const Word16     nChannels)
    334 {
    335   Word16 ch, sfb, sfbGrp;
    336   int ipe, iconstPart, inActiveLines;
    337 
    338   ipe = 0;
    339   iconstPart = 0;
    340   inActiveLines = 0;
    341   for(ch=0; ch<nChannels; ch++) {
    342     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    343     PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
    344     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    345       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    346 
    347         if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
    348           ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
    349           iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
    350           inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
    351         }
    352       }
    353     }
    354   }
    355 
    356   *pe = saturate(ipe);
    357   *constPart = saturate(iconstPart);
    358   *nActiveLines = saturate(inActiveLines);
    359 }
    360 
    361 /********************************************************************************
    362 *
    363 * function name:reduceThresholds
    364 * description: apply reduction formula
    365 *
    366 **********************************************************************************/
    367 static void reduceThresholds(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    368                              Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    369                              Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
    370                              const Word16     nChannels,
    371                              const Word32     redVal)
    372 {
    373   Word32 sfbThrReduced;
    374   Word32 *psfbEn, *psfbThr;
    375   Word16 ch, sfb, sfbGrp;
    376 
    377   for(ch=0; ch<nChannels; ch++) {
    378     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    379     for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
    380  	  psfbEn  = psyOutChan->sfbEnergy + sfbGrp;
    381       psfbThr = psyOutChan->sfbThreshold + sfbGrp;
    382 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    383 
    384         if (*psfbEn > *psfbThr) {
    385           /* threshold reduction formula */
    386           Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
    387           tmp = fixmul(tmp, tmp);
    388           sfbThrReduced = fixmul(tmp, tmp);
    389           /* avoid holes */
    390           tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
    391 
    392           if ((sfbThrReduced > tmp) &&
    393               (ahFlag[ch][sfbGrp+sfb] != NO_AH)){
    394             sfbThrReduced = max(tmp, *psfbThr);
    395             ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
    396           }
    397 		  *psfbThr = sfbThrReduced;
    398         }
    399 
    400 		psfbEn++;  psfbThr++;
    401       }
    402     }
    403   }
    404 }
    405 
    406 
    407 /********************************************************************************
    408 *
    409 * function name:correctThresh
    410 * description: if pe difference deltaPe between desired pe and real pe is small enough,
    411 *             the difference can be distributed among the scale factor bands.
    412 *
    413 **********************************************************************************/
    414 static void correctThresh(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    415                           Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    416                           PE_DATA          *peData,
    417                           Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
    418                           const Word32     redVal,
    419                           const Word16     nChannels,
    420                           const Word32     deltaPe)
    421 {
    422   Word16 ch, sfb, sfbGrp,shift;
    423   PSY_OUT_CHANNEL *psyOutChan;
    424   PE_CHANNEL_DATA *peChanData;
    425   Word32 deltaSfbPe;
    426   Word32 normFactor;
    427   Word32 *psfbPeFactors;
    428   Word16 *psfbNActiveLines, *pahFlag;
    429   Word32 sfbEn, sfbThr;
    430   Word32 sfbThrReduced;
    431 
    432   /* for each sfb calc relative factors for pe changes */
    433   normFactor = 1;
    434   for(ch=0; ch<nChannels; ch++) {
    435     psyOutChan = &psyOutChannel[ch];
    436     peChanData = &peData->peChannelData[ch];
    437     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    438       psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
    439 	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
    440 	  pahFlag = ahFlag[ch] + sfbGrp;
    441 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    442         Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
    443 
    444         if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) && (redThrExp >= *psfbNActiveLines)) {
    445 
    446           *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
    447           normFactor = L_add(normFactor, *psfbPeFactors);
    448         }
    449         else {
    450           *psfbPeFactors = 0;
    451         }
    452 		psfbPeFactors++;
    453 		pahFlag++; psfbNActiveLines++;
    454       }
    455     }
    456   }
    457 
    458 
    459   /* calculate new thresholds */
    460   for(ch=0; ch<nChannels; ch++) {
    461     psyOutChan = &psyOutChannel[ch];
    462     peChanData = &peData->peChannelData[ch];
    463     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
    464       psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
    465 	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
    466 	  pahFlag = ahFlag[ch] + sfbGrp;
    467 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
    468         /* pe difference for this sfb */
    469         deltaSfbPe = *psfbPeFactors * deltaPe;
    470 
    471 		/* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
    472         if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) {
    473           /* new threshold */
    474           Word32 thrFactor;
    475           sfbEn  = psyOutChan->sfbEnergy[sfbGrp+sfb];
    476           sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
    477 
    478            if(deltaSfbPe >= 0){
    479             /*
    480               reduce threshold
    481             */
    482             thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
    483 
    484             sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
    485           }
    486           else {
    487             /*
    488               increase threshold
    489             */
    490             thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
    491 
    492 
    493             if(thrFactor > sfbThr) {
    494               shift = norm_l(thrFactor);
    495 			  sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
    496             }
    497             else {
    498               sfbThrReduced = MAX_32;
    499             }
    500 
    501           }
    502 
    503           /* avoid hole */
    504           sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
    505 
    506           if ((sfbThrReduced > sfbEn) &&
    507               (*pahFlag == AH_INACTIVE)) {
    508             sfbThrReduced = max(sfbEn, sfbThr);
    509             *pahFlag = AH_ACTIVE;
    510           }
    511 
    512           psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
    513         }
    514 
    515 		pahFlag++; psfbNActiveLines++; psfbPeFactors++;
    516       }
    517     }
    518   }
    519 }
    520 
    521 
    522 /********************************************************************************
    523 *
    524 * function name:reduceMinSnr
    525 * description: if the desired pe can not be reached, reduce pe by reducing minSnr
    526 *
    527 **********************************************************************************/
    528 static void reduceMinSnr(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    529                          PE_DATA         *peData,
    530                          Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    531                          const Word16     nChannels,
    532                          const Word16     desiredPe)
    533 {
    534   Word16 ch, sfb, sfbSubWin;
    535   Word16 deltaPe;
    536 
    537   /* start at highest freq down to 0 */
    538   sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
    539   while (peData->pe > desiredPe && sfbSubWin > 0) {
    540 
    541     sfbSubWin = sfbSubWin - 1;
    542     /* loop over all subwindows */
    543     for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
    544         sfb+=psyOutChannel[0].sfbPerGroup) {
    545       /* loop over all channels */
    546 		PE_CHANNEL_DATA* peChan = peData->peChannelData;
    547 		PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
    548 		for (ch=0; ch<nChannels; ch++) {
    549         if (ahFlag[ch][sfb] != NO_AH &&
    550             psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
    551           psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
    552           psyOutCh->sfbThreshold[sfb] =
    553             L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
    554 
    555           /* calc new pe */
    556           deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
    557               peChan->sfbPe[sfb];
    558           peData->pe = peData->pe + deltaPe;
    559           peChan->pe = peChan->pe + deltaPe;
    560         }
    561 		peChan += 1; psyOutCh += 1;
    562       }
    563       /* stop if enough has been saved */
    564 
    565       if (peData->pe <= desiredPe)
    566         break;
    567     }
    568   }
    569 }
    570 
    571 /********************************************************************************
    572 *
    573 * function name:allowMoreHoles
    574 * description: if the desired pe can not be reached, some more scalefactor bands
    575 *              have to be quantized to zero
    576 *
    577 **********************************************************************************/
    578 static void allowMoreHoles(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
    579                            PSY_OUT_ELEMENT *psyOutElement,
    580                            PE_DATA         *peData,
    581                            Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
    582                            const AH_PARAM  *ahParam,
    583                            const Word16     nChannels,
    584                            const Word16     desiredPe)
    585 {
    586   Word16 ch, sfb;
    587   Word16 actPe, shift;
    588 
    589   actPe = peData->pe;
    590 
    591   /* for MS allow hole in the channel with less energy */
    592 
    593   if (nChannels==2 &&
    594       psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
    595     PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
    596     PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
    597     for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
    598       Word32 minEn;
    599 
    600       if (psyOutElement->toolsInfo.msMask[sfb]) {
    601         /* allow hole in side channel ? */
    602         minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
    603 
    604         if (ahFlag[1][sfb] != NO_AH &&
    605             minEn > psyOutChanR->sfbEnergy[sfb]) {
    606           ahFlag[1][sfb] = NO_AH;
    607           psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
    608           actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
    609         }
    610         /* allow hole in mid channel ? */
    611         else {
    612         minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
    613 
    614           if (ahFlag[0][sfb]!= NO_AH &&
    615               minEn > psyOutChanL->sfbEnergy[sfb]) {
    616             ahFlag[0][sfb] = NO_AH;
    617             psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
    618             actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
    619           }
    620         }
    621 
    622         if (actPe < desiredPe)
    623           break;
    624       }
    625     }
    626   }
    627 
    628   /* subsequently erase bands */
    629   if (actPe > desiredPe) {
    630     Word16 startSfb[2];
    631     Word32 avgEn, minEn;
    632     Word16 ahCnt;
    633     Word16 enIdx;
    634     Word16 enDiff;
    635     Word32 en[4];
    636     Word16 minSfb, maxSfb;
    637     Flag   done;
    638 
    639     /* do not go below startSfb */
    640     for (ch=0; ch<nChannels; ch++) {
    641 
    642       if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
    643         startSfb[ch] = ahParam->startSfbL;
    644       else
    645         startSfb[ch] = ahParam->startSfbS;
    646     }
    647 
    648     avgEn = 0;
    649     minEn = MAX_32;
    650     ahCnt = 0;
    651     for (ch=0; ch<nChannels; ch++) {
    652       PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    653       for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
    654 
    655         if ((ahFlag[ch][sfb] != NO_AH) &&
    656             (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
    657           minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
    658           avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
    659           ahCnt++;
    660         }
    661       }
    662     }
    663 
    664     if(ahCnt) {
    665       Word32 iahCnt;
    666       shift = norm_l(ahCnt);
    667 	  iahCnt = Div_32( 1 << shift, ahCnt << shift );
    668       avgEn = fixmul(avgEn, iahCnt);
    669     }
    670 
    671     enDiff = iLog4(avgEn) - iLog4(minEn);
    672     /* calc some energy borders between minEn and avgEn */
    673     for (enIdx=0; enIdx<4; enIdx++) {
    674       Word32 enFac;
    675       enFac = ((6-(enIdx << 1)) * enDiff);
    676       en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
    677     }
    678 
    679     /* start with lowest energy border at highest sfb */
    680     maxSfb = psyOutChannel[0].sfbCnt - 1;
    681     minSfb = startSfb[0];
    682 
    683     if (nChannels == 2) {
    684       maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
    685       minSfb = min(minSfb, startSfb[1]);
    686     }
    687 
    688     sfb = maxSfb;
    689     enIdx = 0;
    690     done = 0;
    691     while (!done) {
    692 
    693       for (ch=0; ch<nChannels; ch++) {
    694         PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
    695 
    696         if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
    697           /* sfb energy below border ? */
    698 
    699           if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
    700             /* allow hole */
    701             ahFlag[ch][sfb] = NO_AH;
    702             psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
    703             actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
    704           }
    705 
    706           if (actPe < desiredPe) {
    707             done = 1;
    708             break;
    709           }
    710         }
    711       }
    712       sfb = sfb - 1;
    713 
    714       if (sfb < minSfb) {
    715         /* restart with next energy border */
    716         sfb = maxSfb;
    717         enIdx = enIdx + 1;
    718 
    719         if (enIdx - 4 >= 0)
    720           done = 1;
    721       }
    722     }
    723   }
    724 }
    725 
    726 /********************************************************************************
    727 *
    728 * function name:adaptThresholdsToPe
    729 * description: two guesses for the reduction value and one final correction of the
    730 *              thresholds
    731 *
    732 **********************************************************************************/
    733 static void adaptThresholdsToPe(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
    734                                 PSY_OUT_ELEMENT    *psyOutElement,
    735                                 Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
    736                                 PE_DATA            *peData,
    737                                 const Word16        nChannels,
    738                                 const Word16        desiredPe,
    739                                 AH_PARAM           *ahParam,
    740                                 MINSNR_ADAPT_PARAM *msaParam)
    741 {
    742   Word16 noRedPe, redPe, redPeNoAH;
    743   Word16 constPart, constPartNoAH;
    744   Word16 nActiveLines, nActiveLinesNoAH;
    745   Word16 desiredPeNoAH;
    746   Word32 redVal, avgThrExp;
    747   Word32 iter;
    748 
    749   calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
    750 
    751   adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
    752 
    753   initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
    754 
    755   noRedPe = peData->pe;
    756   constPart = peData->constPart;
    757   nActiveLines = peData->nActiveLines;
    758 
    759   /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
    760   avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
    761 
    762   /* r1 = 2^((a-per)/4*b) - t^0.25 */
    763   redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
    764 
    765   /* reduce thresholds */
    766   reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
    767 
    768   /* pe after first guess */
    769   calcSfbPe(peData, psyOutChannel, nChannels);
    770   redPe = peData->pe;
    771 
    772   iter = 0;
    773   do {
    774     /* pe for bands where avoid hole is inactive */
    775     calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
    776                peData, peData->ahFlag, psyOutChannel, nChannels);
    777 
    778     desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
    779 
    780     if (desiredPeNoAH < 0) {
    781       desiredPeNoAH = 0;
    782     }
    783 
    784     /* second guess */
    785 
    786     if (nActiveLinesNoAH > 0) {
    787 
    788 		avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
    789 
    790 		redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
    791 
    792 		/* reduce thresholds */
    793 		reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
    794     }
    795 
    796     calcSfbPe(peData, psyOutChannel, nChannels);
    797     redPe = peData->pe;
    798 
    799     iter = iter+1;
    800 
    801   } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
    802 
    803 
    804   if ((100 * redPe < 115 * desiredPe)) {
    805     correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
    806                   nChannels, desiredPe - redPe);
    807   }
    808   else {
    809     Word16 desiredPe105 = (105 * desiredPe) / 100;
    810     reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
    811                  nChannels, desiredPe105);
    812     allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
    813                    ahParam, nChannels, desiredPe105);
    814   }
    815 }
    816 
    817 
    818 /*****************************************************************************
    819 *
    820 * function name: calcBitSave
    821 * description:  Calculates percentage of bit save, see figure below
    822 * returns:
    823 * input:        parameters and bitres-fullness
    824 * output:       percentage of bit save
    825 *
    826 *****************************************************************************/
    827 static Word16 calcBitSave(Word16 fillLevel,
    828                           const Word16 clipLow,
    829                           const Word16 clipHigh,
    830                           const Word16 minBitSave,
    831                           const Word16 maxBitSave)
    832 {
    833   Word16 bitsave = 0;
    834 
    835   fillLevel = max(fillLevel, clipLow);
    836   fillLevel = min(fillLevel, clipHigh);
    837 
    838   if(clipHigh-clipLow)
    839   bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
    840                               (clipHigh-clipLow)));
    841 
    842   return (bitsave);
    843 }
    844 
    845 
    846 
    847 /*****************************************************************************
    848 *
    849 * function name: calcBitSpend
    850 * description:  Calculates percentage of bit spend, see figure below
    851 * returns:
    852 * input:        parameters and bitres-fullness
    853 * output:       percentage of bit spend
    854 *
    855 *****************************************************************************/
    856 static Word16 calcBitSpend(Word16 fillLevel,
    857                            const Word16 clipLow,
    858                            const Word16 clipHigh,
    859                            const Word16 minBitSpend,
    860                            const Word16 maxBitSpend)
    861 {
    862   Word16 bitspend = 1;
    863 
    864   fillLevel = max(fillLevel, clipLow);
    865   fillLevel = min(fillLevel, clipHigh);
    866 
    867   if(clipHigh-clipLow)
    868   bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
    869                                 (clipHigh-clipLow)));
    870 
    871   return (bitspend);
    872 }
    873 
    874 
    875 /*****************************************************************************
    876 *
    877 * function name: adjustPeMinMax()
    878 * description:  adjusts peMin and peMax parameters over time
    879 * returns:
    880 * input:        current pe, peMin, peMax
    881 * output:       adjusted peMin/peMax
    882 *
    883 *****************************************************************************/
    884 static void adjustPeMinMax(const Word16 currPe,
    885                            Word16      *peMin,
    886                            Word16      *peMax)
    887 {
    888   Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
    889   Word16 diff;
    890   Word16 minDiff = extract_l(currPe / 6);
    891   minFacHi = 30;
    892   maxFacHi = 100;
    893   minFacLo = 14;
    894   maxFacLo = 7;
    895 
    896   diff = currPe - *peMax ;
    897 
    898   if (diff > 0) {
    899     *peMin = *peMin + ((diff * minFacHi) / 100);
    900     *peMax = *peMax + ((diff * maxFacHi) / 100);
    901   } else {
    902     diff = *peMin - currPe;
    903 
    904     if (diff > 0) {
    905       *peMin = *peMin - ((diff * minFacLo) / 100);
    906       *peMax = *peMax - ((diff * maxFacLo) / 100);
    907     } else {
    908       *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
    909       *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
    910     }
    911   }
    912 
    913 
    914   if ((*peMax - *peMin) < minDiff) {
    915     Word16 partLo, partHi;
    916 
    917     partLo = max(0, (currPe - *peMin));
    918     partHi = max(0, (*peMax - currPe));
    919 
    920     *peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
    921     *peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
    922     *peMin = max(0, *peMin);
    923   }
    924 }
    925 
    926 
    927 /*****************************************************************************
    928 *
    929 * function name: BitresCalcBitFac
    930 * description:  calculates factor of spending bits for one frame
    931 *                1.0 : take all frame dynpart bits
    932 *                >1.0 : take all frame dynpart bits + bitres
    933 *                <1.0 : put bits in bitreservoir
    934 *  returns:      BitFac*100
    935 *  input:        bitres-fullness, pe, blockType, parameter-settings
    936 *  output:
    937 *
    938 *****************************************************************************/
    939 static Word16 bitresCalcBitFac( const Word16   bitresBits,
    940                                 const Word16   maxBitresBits,
    941                                 const Word16   pe,
    942                                 const Word16   windowSequence,
    943                                 const Word16   avgBits,
    944                                 const Word16   maxBitFac,
    945                                 ADJ_THR_STATE *AdjThr,
    946                                 ATS_ELEMENT   *adjThrChan)
    947 {
    948   BRES_PARAM *bresParam;
    949   Word16 pex;
    950   Word16 fillLevel;
    951   Word16 bitSave, bitSpend, bitresFac;
    952 
    953   fillLevel = extract_l((100* bitresBits) / maxBitresBits);
    954 
    955   if (windowSequence != SHORT_WINDOW)
    956     bresParam = &(AdjThr->bresParamLong);
    957   else
    958     bresParam = &(AdjThr->bresParamShort);
    959 
    960   pex = max(pe, adjThrChan->peMin);
    961   pex = min(pex,adjThrChan->peMax);
    962 
    963   bitSave = calcBitSave(fillLevel,
    964                         bresParam->clipSaveLow, bresParam->clipSaveHigh,
    965                         bresParam->minBitSave, bresParam->maxBitSave);
    966 
    967   bitSpend = calcBitSpend(fillLevel,
    968                           bresParam->clipSpendLow, bresParam->clipSpendHigh,
    969                           bresParam->minBitSpend, bresParam->maxBitSpend);
    970 
    971   if(adjThrChan->peMax != adjThrChan->peMin)
    972 	bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
    973                     (adjThrChan->peMax - adjThrChan->peMin));
    974   else
    975 	bitresFac = 0x7fff;
    976 
    977   bitresFac = min(bitresFac,
    978                     (100-30 + extract_l((100 * bitresBits) / avgBits)));
    979 
    980   bitresFac = min(bitresFac, maxBitFac);
    981 
    982   adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
    983 
    984   return bitresFac;
    985 }
    986 
    987 /*****************************************************************************
    988 *
    989 * function name: AdjThrInit
    990 * description:  init thresholds parameter
    991 *
    992 *****************************************************************************/
    993 void AdjThrInit(ADJ_THR_STATE *hAdjThr,
    994                 const Word32   meanPe,
    995                 Word32         chBitrate)
    996 {
    997   ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
    998   MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
    999 
   1000   /* common for all elements: */
   1001   /* parameters for bitres control */
   1002   hAdjThr->bresParamLong.clipSaveLow   =  20;
   1003   hAdjThr->bresParamLong.clipSaveHigh  =  95;
   1004   hAdjThr->bresParamLong.minBitSave    =  -5;
   1005   hAdjThr->bresParamLong.maxBitSave    =  30;
   1006   hAdjThr->bresParamLong.clipSpendLow  =  20;
   1007   hAdjThr->bresParamLong.clipSpendHigh =  95;
   1008   hAdjThr->bresParamLong.minBitSpend   = -10;
   1009   hAdjThr->bresParamLong.maxBitSpend   =  40;
   1010 
   1011   hAdjThr->bresParamShort.clipSaveLow   =  20;
   1012   hAdjThr->bresParamShort.clipSaveHigh  =  75;
   1013   hAdjThr->bresParamShort.minBitSave    =   0;
   1014   hAdjThr->bresParamShort.maxBitSave    =  20;
   1015   hAdjThr->bresParamShort.clipSpendLow  =  20;
   1016   hAdjThr->bresParamShort.clipSpendHigh =  75;
   1017   hAdjThr->bresParamShort.minBitSpend   = -5;
   1018   hAdjThr->bresParamShort.maxBitSpend   =  50;
   1019 
   1020   /* specific for each element: */
   1021 
   1022   /* parameters for bitres control */
   1023   atsElem->peMin = extract_l(((80*meanPe) / 100));
   1024   atsElem->peMax = extract_l(((120*meanPe) / 100));
   1025 
   1026   /* additional pe offset to correct pe2bits for low bitrates */
   1027   atsElem->peOffset = 0;
   1028   if (chBitrate < 32000) {
   1029     atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
   1030   }
   1031 
   1032   /* avoid hole parameters */
   1033   if (chBitrate > 20000) {
   1034     atsElem->ahParam.modifyMinSnr = TRUE;
   1035     atsElem->ahParam.startSfbL = 15;
   1036     atsElem->ahParam.startSfbS = 3;
   1037   }
   1038   else {
   1039     atsElem->ahParam.modifyMinSnr = FALSE;
   1040     atsElem->ahParam.startSfbL = 0;
   1041     atsElem->ahParam.startSfbS = 0;
   1042   }
   1043 
   1044   /* minSnr adaptation */
   1045   /* maximum reduction of minSnr goes down to minSnr^maxRed */
   1046   msaParam->maxRed = 0x20000000;     /* *0.25f */
   1047   /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
   1048   msaParam->startRatio = 0x0ccccccd; /* 10 */
   1049   /* maximum minSnr reduction to minSnr^maxRed is reached for
   1050      avgEn/sfbEn >= maxRatio */
   1051   msaParam->maxRatio =  0x0020c49c; /* 1000 */
   1052   /* helper variables to interpolate minSnr reduction for
   1053      avgEn/sfbEn between startRatio and maxRatio */
   1054 
   1055   msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
   1056 
   1057   msaParam->redOffs = 0x30000000;  /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
   1058 
   1059 
   1060   /* pe correction */
   1061   atsElem->peLast = 0;
   1062   atsElem->dynBitsLast = 0;
   1063   atsElem->peCorrectionFactor = 100; /* 1.0 */
   1064 
   1065 }
   1066 
   1067 /*****************************************************************************
   1068 *
   1069 * function name: calcPeCorrection
   1070 * description:  calculates the desired perceptual entropy factor
   1071 *				It is between 0.85 and 1.15
   1072 *
   1073 *****************************************************************************/
   1074 static void calcPeCorrection(Word16 *correctionFac,
   1075                              const Word16 peAct,
   1076                              const Word16 peLast,
   1077                              const Word16 bitsLast)
   1078 {
   1079   Word32 peAct100 = 100 * peAct;
   1080   Word32 peLast100 = 100 * peLast;
   1081   Word16 peBitsLast = bits2pe(bitsLast);
   1082 
   1083   if ((bitsLast > 0) &&
   1084       (peAct100 < (150 * peLast)) &&  (peAct100 > (70 * peLast)) &&
   1085       ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
   1086     {
   1087       Word16 newFac = (100 * peLast) / peBitsLast;
   1088       /* dead zone */
   1089 
   1090       if (newFac < 100) {
   1091         newFac = min(((110 * newFac) / 100), 100);
   1092         newFac = max(newFac, 85);
   1093       }
   1094       else {
   1095         newFac = max(((90 * newFac) / 100), 100);
   1096         newFac = min(newFac, 115);
   1097       }
   1098 
   1099       if ((newFac > 100 && *correctionFac < 100) ||
   1100           (newFac < 100 && *correctionFac > 100)) {
   1101         *correctionFac = 100;
   1102       }
   1103       /* faster adaptation towards 1.0, slower in the other direction */
   1104 
   1105       if ((*correctionFac < 100 && newFac < *correctionFac) ||
   1106           (*correctionFac > 100 && newFac > *correctionFac))
   1107         *correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
   1108       else
   1109         *correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
   1110       *correctionFac = min(*correctionFac, 115);
   1111       *correctionFac = max(*correctionFac, 85);
   1112     }
   1113   else {
   1114     *correctionFac = 100;
   1115   }
   1116 }
   1117 
   1118 /********************************************************************************
   1119 *
   1120 * function name: AdjustThresholds
   1121 * description:  Adjust thresholds to the desired bitrate
   1122 *
   1123 **********************************************************************************/
   1124 void AdjustThresholds(ADJ_THR_STATE   *adjThrState,
   1125                       ATS_ELEMENT     *AdjThrStateElement,
   1126                       PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
   1127                       PSY_OUT_ELEMENT *psyOutElement,
   1128                       Word16          *chBitDistribution,
   1129                       Word16           logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
   1130                       Word16           sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
   1131                       QC_OUT_ELEMENT  *qcOE,
   1132 					  ELEMENT_BITS	  *elBits,
   1133 					  const Word16     nChannels,
   1134                       const Word16     maxBitFac)
   1135 {
   1136   PE_DATA peData;
   1137   Word16 noRedPe, grantedPe, grantedPeCorr;
   1138   Word16 curWindowSequence;
   1139   Word16 bitFactor;
   1140   Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
   1141   Word16 bitresBits = elBits->bitResLevel;
   1142   Word16 maxBitresBits = elBits->maxBits;
   1143   Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
   1144   Word16 ch;
   1145   memset(&peData, 0, sizeof(peData));
   1146 
   1147   prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
   1148 
   1149   /* pe without reduction */
   1150   calcSfbPe(&peData, psyOutChannel, nChannels);
   1151   noRedPe = peData.pe;
   1152 
   1153 
   1154   curWindowSequence = LONG_WINDOW;
   1155 
   1156   if (nChannels == 2) {
   1157 
   1158     if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
   1159         (psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
   1160       curWindowSequence = SHORT_WINDOW;
   1161     }
   1162   }
   1163   else {
   1164     curWindowSequence = psyOutChannel[0].windowSequence;
   1165   }
   1166 
   1167 
   1168   /* bit factor */
   1169   bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
   1170                                curWindowSequence, avgBits, maxBitFac,
   1171                                adjThrState,
   1172                                AdjThrStateElement);
   1173 
   1174   /* desired pe */
   1175   grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
   1176 
   1177   /* correction of pe value */
   1178   calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
   1179                    min(grantedPe, noRedPe),
   1180                    AdjThrStateElement->peLast,
   1181                    AdjThrStateElement->dynBitsLast);
   1182   grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
   1183 
   1184 
   1185   if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
   1186     /* calc threshold necessary for desired pe */
   1187     adaptThresholdsToPe(psyOutChannel,
   1188                         psyOutElement,
   1189                         logSfbEnergy,
   1190                         &peData,
   1191                         nChannels,
   1192                         grantedPeCorr,
   1193                         &AdjThrStateElement->ahParam,
   1194                         &AdjThrStateElement->minSnrAdaptParam);
   1195   }
   1196 
   1197   /* calculate relative distribution */
   1198   for (ch=0; ch<nChannels; ch++) {
   1199     Word16 peOffsDiff = peData.pe - peData.offset;
   1200     chBitDistribution[ch] = 200;
   1201 
   1202     if (peOffsDiff > 0) {
   1203       Word32 temp = 1000 - (nChannels * 200);
   1204       chBitDistribution[ch] = chBitDistribution[ch] +
   1205 		  (temp * peData.peChannelData[ch].pe) / peOffsDiff;
   1206     }
   1207   }
   1208 
   1209   /* store pe */
   1210   qcOE->pe = noRedPe;
   1211 
   1212   /* update last pe */
   1213   AdjThrStateElement->peLast = grantedPe;
   1214 }
   1215 
   1216 /********************************************************************************
   1217 *
   1218 * function name: AdjThrUpdate
   1219 * description:  save dynBitsUsed for correction of bits2pe relation
   1220 *
   1221 **********************************************************************************/
   1222 void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
   1223                   const Word16 dynBitsUsed)
   1224 {
   1225   AdjThrStateElement->dynBitsLast = dynBitsUsed;
   1226 }
   1227 
   1228 
   1229