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