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