adj_thr.c revision 132e42c04a58e623efa6cd6ca43641cd80db0f05
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 */
43enum _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**********************************************************************************/
56Word16 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**********************************************************************************/
67static 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**********************************************************************************/
91static 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**********************************************************************************/
161static 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**********************************************************************************/
324static 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**********************************************************************************/
364static 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**********************************************************************************/
411static 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) ) {
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) {
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**********************************************************************************/
525static 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**********************************************************************************/
575static 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**********************************************************************************/
730static 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*****************************************************************************/
824static 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*****************************************************************************/
853static 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*****************************************************************************/
881static 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*****************************************************************************/
936static 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*****************************************************************************/
990void 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*****************************************************************************/
1071static 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**********************************************************************************/
1121void 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**********************************************************************************/
1219void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1220                  const Word16 dynBitsUsed)
1221{
1222  AdjThrStateElement->dynBitsLast = dynBitsUsed;
1223}
1224
1225
1226